From 1d8c6bd74b99c57cf0d159ccd5290a8df8faba75 Mon Sep 17 00:00:00 2001 From: JPeer264 Date: Sat, 10 Oct 2026 09:31:21 +0200 Subject: [PATCH] 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 --- .../aws-serverless-layer/src/stack.ts | 23 ++++++++++++++++--- .../aws-serverless/src/stack.ts | 23 ++++++++++++++++--- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless-layer/src/stack.ts b/dev-packages/e2e-tests/test-applications/aws-serverless-layer/src/stack.ts index df5a076ef56d..6ed4cd16440f 100644 --- a/dev-packages/e2e-tests/test-applications/aws-serverless-layer/src/stack.ts +++ b/dev-packages/e2e-tests/test-applications/aws-serverless-layer/src/stack.ts @@ -118,14 +118,31 @@ export class LocalLambdaStack extends Stack { export async function getHostIp() { if (process.env.GITHUB_ACTIONS) { - const host = await dns.lookup(os.hostname()); - return host.address; + return getExternalHostIp(); } if (platform === 'darwin' || platform === 'win32') { return 'host.docker.internal'; } + return getExternalHostIp(); +} + +/** + * The Lambda container reaches the event proxy on the host through an address of the host's network interface. + * Some runners (e.g. Namespace) map the hostname to a loopback address, which inside the container is the container + * itself, so fall back to the first external IPv4 address that is not a Docker bridge. + */ +async function getExternalHostIp(): Promise { const host = await dns.lookup(os.hostname()); - return host.address; + if (!host.address.startsWith('127.') && host.address !== '::1') { + return host.address; + } + + const external = Object.entries(os.networkInterfaces()) + .filter(([name]) => !name.startsWith('docker') && !name.startsWith('br-') && !name.startsWith('veth')) + .flatMap(([, addresses]) => addresses ?? []) + .find(address => address.family === 'IPv4' && !address.internal); + + return external?.address ?? host.address; } diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts b/dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts index f314643572c2..c4eb3658afd0 100644 --- a/dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts +++ b/dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts @@ -159,14 +159,31 @@ export class LocalLambdaStack extends Stack { export async function getHostIp() { if (process.env.GITHUB_ACTIONS) { - const host = await dns.lookup(os.hostname()); - return host.address; + return getExternalHostIp(); } if (platform === 'darwin' || platform === 'win32') { return 'host.docker.internal'; } + return getExternalHostIp(); +} + +/** + * The Lambda container reaches the event proxy on the host through an address of the host's network interface. + * Some runners (e.g. Namespace) map the hostname to a loopback address, which inside the container is the container + * itself, so fall back to the first external IPv4 address that is not a Docker bridge. + */ +async function getExternalHostIp(): Promise { const host = await dns.lookup(os.hostname()); - return host.address; + if (!host.address.startsWith('127.') && host.address !== '::1') { + return host.address; + } + + const external = Object.entries(os.networkInterfaces()) + .filter(([name]) => !name.startsWith('docker') && !name.startsWith('br-') && !name.startsWith('veth')) + .flatMap(([, addresses]) => addresses ?? []) + .find(address => address.family === 'IPv4' && !address.internal); + + return external?.address ?? host.address; }