Skip to content

Commit 9583652

Browse files
JPeer264claude
andauthored
test(e2e): Use an external host address for the Lambda DSN on loopback hostnames
The AWS serverless E2E apps point the Lambda's DSN at the host IP that the runner's hostname resolves to. On Namespace runners the hostname resolves to 127.0.0.1, which inside the Lambda container is the container itself, so no event reached the event proxy and every test timed out. When the hostname resolves to a loopback address, use the first external IPv4 address that is not a Docker bridge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent aa368ec commit 9583652

2 files changed

Lines changed: 40 additions & 6 deletions

File tree

  • dev-packages/e2e-tests/test-applications

‎dev-packages/e2e-tests/test-applications/aws-serverless-layer/src/stack.ts‎

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,14 +118,31 @@ export class LocalLambdaStack extends Stack {
118118

119119
export async function getHostIp() {
120120
if (process.env.GITHUB_ACTIONS) {
121-
const host = await dns.lookup(os.hostname());
122-
return host.address;
121+
return getExternalHostIp();
123122
}
124123

125124
if (platform === 'darwin' || platform === 'win32') {
126125
return 'host.docker.internal';
127126
}
128127

128+
return getExternalHostIp();
129+
}
130+
131+
/**
132+
* The Lambda container reaches the event proxy on the host through an address of the host's network interface.
133+
* Some runners (e.g. Namespace) map the hostname to a loopback address, which inside the container is the container
134+
* itself, so fall back to the first external IPv4 address that is not a Docker bridge.
135+
*/
136+
async function getExternalHostIp(): Promise<string> {
129137
const host = await dns.lookup(os.hostname());
130-
return host.address;
138+
if (!host.address.startsWith('127.') && host.address !== '::1') {
139+
return host.address;
140+
}
141+
142+
const external = Object.entries(os.networkInterfaces())
143+
.filter(([name]) => !name.startsWith('docker') && !name.startsWith('br-') && !name.startsWith('veth'))
144+
.flatMap(([, addresses]) => addresses ?? [])
145+
.find(address => address.family === 'IPv4' && !address.internal);
146+
147+
return external?.address ?? host.address;
131148
}

‎dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts‎

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,14 +159,31 @@ export class LocalLambdaStack extends Stack {
159159

160160
export async function getHostIp() {
161161
if (process.env.GITHUB_ACTIONS) {
162-
const host = await dns.lookup(os.hostname());
163-
return host.address;
162+
return getExternalHostIp();
164163
}
165164

166165
if (platform === 'darwin' || platform === 'win32') {
167166
return 'host.docker.internal';
168167
}
169168

169+
return getExternalHostIp();
170+
}
171+
172+
/**
173+
* The Lambda container reaches the event proxy on the host through an address of the host's network interface.
174+
* Some runners (e.g. Namespace) map the hostname to a loopback address, which inside the container is the container
175+
* itself, so fall back to the first external IPv4 address that is not a Docker bridge.
176+
*/
177+
async function getExternalHostIp(): Promise<string> {
170178
const host = await dns.lookup(os.hostname());
171-
return host.address;
179+
if (!host.address.startsWith('127.') && host.address !== '::1') {
180+
return host.address;
181+
}
182+
183+
const external = Object.entries(os.networkInterfaces())
184+
.filter(([name]) => !name.startsWith('docker') && !name.startsWith('br-') && !name.startsWith('veth'))
185+
.flatMap(([, addresses]) => addresses ?? [])
186+
.find(address => address.family === 'IPv4' && !address.internal);
187+
188+
return external?.address ?? host.address;
172189
}

0 commit comments

Comments
 (0)