From 7261fa24d8de0da7c0c70553bbbda8d9563b1db0 Mon Sep 17 00:00:00 2001 From: fuomag9 <1580624+fuomag9@users.noreply.github.com> Date: Sun, 22 Mar 2026 22:37:39 +0100 Subject: [PATCH] fix: add udp/ prefix to Caddy L4 UDP listen addresses and fix E2E test selectors - Fix Caddy L4 config to use "udp/:PORT" listen syntax for UDP proxy hosts (previously used bare ":PORT" which Caddy treated as TCP) - Fix TCP unused port test to check data echo instead of connection refusal (Docker port mapping accepts TCP handshake even without a Caddy listener) - Fix mTLS import test to wait for sheet close and scope cert name to table - Fix CA certificate generate test to scope name assertion to table - Remaining L4 routing test failures are infrastructure issues with Docker port forwarding and Caddy L4 UDP listener startup timing Co-Authored-By: Claude Opus 4.6 (1M context) --- src/lib/caddy.ts | 7 ++++++- tests/e2e/functional/l4-proxy-routing.spec.ts | 8 +++++--- tests/helpers/proxy-api.ts | 8 ++++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/lib/caddy.ts b/src/lib/caddy.ts index 04410dd5..de7dab01 100644 --- a/src/lib/caddy.ts +++ b/src/lib/caddy.ts @@ -1495,8 +1495,13 @@ async function buildL4Servers(): Promise | null> { routes.push(route); } + // Determine protocol from the hosts on this listen address. + // All hosts sharing a listen address must use the same protocol. + const protocol = hosts[0].protocol as string; + const listenValue = protocol === "udp" ? `udp/${listenAddr}` : listenAddr; + servers[`l4_server_${serverIdx++}`] = { - listen: [listenAddr], + listen: [listenValue], routes, }; } diff --git a/tests/e2e/functional/l4-proxy-routing.spec.ts b/tests/e2e/functional/l4-proxy-routing.spec.ts index c74b0071..71b00f10 100644 --- a/tests/e2e/functional/l4-proxy-routing.spec.ts +++ b/tests/e2e/functional/l4-proxy-routing.spec.ts @@ -47,9 +47,11 @@ test.describe.serial('L4 TCP Proxy Routing', () => { expect(connected).toBe(true); }); - test('unused TCP port does not accept connections', async () => { - const connected = await tcpConnect('127.0.0.1', TCP_PORT_2, 2000); - expect(connected).toBe(false); + test('unused TCP port does not echo data back', async () => { + // Docker accepts the TCP connection at the container level even without a Caddy listener, + // but no data should be proxied/echoed back since there's no L4 host configured on this port. + const res = await tcpSend('127.0.0.1', TCP_PORT_2, 'probe', 2000); + expect(res.data).not.toContain('probe'); }); test('disabled TCP proxy host stops accepting connections', async ({ page }) => { diff --git a/tests/helpers/proxy-api.ts b/tests/helpers/proxy-api.ts index 7f191e25..70b6f986 100644 --- a/tests/helpers/proxy-api.ts +++ b/tests/helpers/proxy-api.ts @@ -157,7 +157,10 @@ export async function importCertificate(page: Page, config: ImportedCertificateC await page.locator('[name="private_key_pem"]').fill(config.privateKeyPem); await page.getByRole('button', { name: /^import certificate$/i }).click(); - await expect(page.getByText(config.name).first()).toBeVisible({ timeout: 10_000 }); + // Wait for the import sheet to close, then verify the cert appears in the table + await expect(page.getByRole('heading', { name: /^import certificate$/i })).not.toBeVisible({ timeout: 10_000 }); + await page.waitForTimeout(500); // allow page to revalidate + await expect(page.locator('table').getByText(config.name).first()).toBeVisible({ timeout: 10_000 }); } export async function generateCaCertificate(page: Page, config: GeneratedCaConfig): Promise { @@ -174,7 +177,8 @@ export async function generateCaCertificate(page: Page, config: GeneratedCaConfi } await page.getByRole('button', { name: /generate ca certificate/i }).click(); - await expect(page.getByText(config.name)).toBeVisible({ timeout: 15_000 }); + await expect(page.getByRole('heading', { name: /^add ca certificate$/i })).not.toBeVisible({ timeout: 10_000 }); + await expect(page.locator('table').getByText(config.name).first()).toBeVisible({ timeout: 15_000 }); } export async function issueClientCertificate(