diff --git a/web/lib/agent/expected-state.ts b/web/lib/agent/expected-state.ts index c4838999..72f1501b 100644 --- a/web/lib/agent/expected-state.ts +++ b/web/lib/agent/expected-state.ts @@ -594,15 +594,16 @@ async function buildTraefikConfig(server: Server, allServices: Service[]) { ), ); + const routePorts = buildRuntimeRoutePorts(allServices, ports); const routes = buildTraefikRoutes({ serverId: server.id, - ports: buildRuntimeRoutePorts(allServices, ports), + ports: routePorts, routableDeployments, serverlessServiceIds, serverlessRouteSuppressedServiceIds, }); - const routedDomains = routes.httpRoutes.map((r) => r.domain); - const certificates = await getAllCertificatesForDomains(routedDomains); + const certificateDomains = buildTraefikCertificateDomains(routePorts); + const certificates = await getAllCertificatesForDomains(certificateDomains); const controlPlaneUrl = process.env.APP_URL; if (!controlPlaneUrl) { @@ -722,6 +723,17 @@ export function buildTraefikRoutes({ return { httpRoutes, tcpRoutes, udpRoutes }; } +export function buildTraefikCertificateDomains(ports: RouteServicePort[]) { + return Array.from( + new Set( + ports + .filter((port) => port.isPublic && port.protocol === "http") + .map((port) => port.domain?.trim()) + .filter((domain): domain is string => Boolean(domain)), + ), + ).sort(); +} + function buildHealthCheck(service: Service): ExpectedContainer["healthCheck"] { if (!service.healthCheckCmd) return null; diff --git a/web/tests/expected-state.test.ts b/web/tests/expected-state.test.ts index 52d93b25..9685bf23 100644 --- a/web/tests/expected-state.test.ts +++ b/web/tests/expected-state.test.ts @@ -10,6 +10,7 @@ import { buildExpectedContainersFromRows, buildRuntimeRoutePorts, buildServerlessRoutesFromRows, + buildTraefikCertificateDomains, buildTraefikRoutes, } from "@/lib/agent/expected-state"; @@ -358,6 +359,33 @@ describe("expected-state pure builders", () => { expect(routes.httpRoutes).toEqual([]); }); + it("keeps suppressed serverless HTTP domains in certificate selection", () => { + const ports: Parameters[0] = [ + { + id: "port_1", + serviceId: "svc_serverless", + port: 3000, + isPublic: true, + protocol: "http", + domain: "sleepy.example.com", + externalPort: null, + tlsPassthrough: false, + }, + ]; + + const routes = buildTraefikRoutes({ + serverId: "proxy_2", + ports, + routableDeployments: [], + serverlessRouteSuppressedServiceIds: new Set(["svc_serverless"]), + }); + + expect(routes.httpRoutes).toEqual([]); + expect(buildTraefikCertificateDomains(ports)).toEqual([ + "sleepy.example.com", + ]); + }); + it("keeps worker-only serverless services on direct routes", () => { const routes = buildTraefikRoutes({ serverId: "proxy_1",