diff --git a/src/infra/net/fetch-guard.ssrf.test.ts b/src/infra/net/fetch-guard.ssrf.test.ts index 8a13c68bf248..5f07897757cc 100644 --- a/src/infra/net/fetch-guard.ssrf.test.ts +++ b/src/infra/net/fetch-guard.ssrf.test.ts @@ -102,24 +102,38 @@ function getSecondRequestHeaders(fetchImpl: ReturnType): Headers { return new Headers(secondInit.headers); } +function requireRecord(value: unknown, label: string): Record { + if (!value || typeof value !== "object" || Array.isArray(value)) { + throw new Error(`expected ${label}`); + } + return value as Record; +} + +function getFirstRequestInit(fetchImpl: ReturnType): RequestInit { + const [call] = fetchImpl.mock.calls; + if (!call) { + throw new Error("expected first fetch call"); + } + const [, init] = call as [string, RequestInit | undefined]; + return requireRecord(init, "first fetch init") as RequestInit; +} + function getSecondRequestInit(fetchImpl: ReturnType): RequestInit { const [, secondInit] = fetchImpl.mock.calls[1] as [string, RequestInit]; return secondInit; } function expectAgentConstructorOptions(params: { bodyTimeout: number; headersTimeout: number }) { - const options = agentCtor.mock.calls[0]?.[0] as - | { - connect?: { lookup?: unknown }; - allowH2?: boolean; - bodyTimeout?: number; - headersTimeout?: number; - } - | undefined; - expect(typeof options?.connect?.lookup).toBe("function"); - expect(options?.allowH2).toBe(false); - expect(options?.bodyTimeout).toBe(params.bodyTimeout); - expect(options?.headersTimeout).toBe(params.headersTimeout); + const [call] = agentCtor.mock.calls; + if (!call) { + throw new Error("expected Agent constructor call"); + } + const options = requireRecord(call[0], "Agent constructor options"); + const connect = requireRecord(options.connect, "Agent connect options"); + expect(typeof connect.lookup).toBe("function"); + expect(options.allowH2).toBe(false); + expect(options.bodyTimeout).toBe(params.bodyTimeout); + expect(options.headersTimeout).toBe(params.headersTimeout); } async function expectRedirectFailure(params: { @@ -708,7 +722,7 @@ describe("fetchWithSsrFGuard hardening", () => { }); expect(result.response.status).toBe(200); - const firstHeaders = fetchImpl.mock.calls[0]?.[1]?.headers; + const firstHeaders = getFirstRequestInit(fetchImpl).headers; expect(firstHeaders).not.toBe(headers); expect(Object.getOwnPropertySymbols(firstHeaders as object)).toStrictEqual([]); const secondHeaders = getSecondRequestHeaders(fetchImpl); diff --git a/src/infra/net/http-connect-tunnel.test.ts b/src/infra/net/http-connect-tunnel.test.ts index 337340570c83..b01e1b7cef17 100644 --- a/src/infra/net/http-connect-tunnel.test.ts +++ b/src/infra/net/http-connect-tunnel.test.ts @@ -95,6 +95,14 @@ vi.mock("node:tls", () => ({ connect: tlsConnectSpy, })); +function requireFirstTlsConnectOptions(): unknown { + const [call] = tlsConnectSpy.mock.calls; + if (!call) { + throw new Error("expected TLS connect call"); + } + return call[0]; +} + describe("openHttpConnectTunnel", () => { beforeEach(() => { vi.useRealTimers(); @@ -151,7 +159,7 @@ describe("openHttpConnectTunnel", () => { targetPort: 443, }); - expect(tlsConnectSpy.mock.calls[0]?.[0]).toEqual({ + expect(requireFirstTlsConnectOptions()).toEqual({ host: "proxy.example", port: 8443, servername: "proxy.example", diff --git a/src/infra/net/ssrf.dispatcher.test.ts b/src/infra/net/ssrf.dispatcher.test.ts index 782aa5e74e42..07231bf72dcc 100644 --- a/src/infra/net/ssrf.dispatcher.test.ts +++ b/src/infra/net/ssrf.dispatcher.test.ts @@ -77,6 +77,21 @@ function createDispatcherWithPinnedOverride(lookup: PinnedHostname["lookup"]) { ?.connect?.lookup; } +function requireRecord(value: unknown, label: string): Record { + if (!value || typeof value !== "object" || Array.isArray(value)) { + throw new Error(`expected ${label}`); + } + return value as Record; +} + +function requireFirstAgentOptions(): Record { + const [call] = agentCtor.mock.calls; + if (!call) { + throw new Error("expected Agent constructor call"); + } + return requireRecord(call[0], "Agent constructor options"); +} + describe("createPinnedDispatcher", () => { it("uses pinned lookup and inherits the shared undici family policy", () => { const lookup = vi.fn() as unknown as PinnedHostname["lookup"]; @@ -105,10 +120,10 @@ describe("createPinnedDispatcher", () => { }, allowH2: false, }); - const firstCallArg = agentCtor.mock.calls[0]?.[0] as - | { connect?: Record } - | undefined; - expect(firstCallArg?.connect?.autoSelectFamily).toBe(true); + const firstCallArg = requireFirstAgentOptions(); + expect(requireRecord(firstCallArg.connect, "Agent connect options").autoSelectFamily).toBe( + true, + ); }); it("reuses the global WSL2 autoSelectFamily policy for pinned dispatchers", () => {