diff --git a/src/outbound-fetch-policy.ts b/src/outbound-fetch-policy.ts index f3cf72fdc..4a18b1669 100644 --- a/src/outbound-fetch-policy.ts +++ b/src/outbound-fetch-policy.ts @@ -438,7 +438,8 @@ export function isTrustedCredentialEgressRequest( if (!authorization) { return url.href === TRUSTED_GITHUB_API_META && method === "GET" - && !bodyPresent; + && !bodyPresent + && hasNoHeaders(headers); } const rawAuthorization = rawHeaderValueFromInit(init?.headers, "authorization"); if ( @@ -573,7 +574,7 @@ export function ensureGlobalOutboundFetchPolicy( /** * Restores an installed fetch host during tests while leaving production policy installation one-way for normal operation. * @param host Mutable fetch host whose test-only installation state should be removed. - * @returns Nothing; cleanup is best-effort and never masks the security behavior being tested. + * @returns Nothing; cleanup is best-effort and never masks the security behavior under examination. */ export function resetGlobalOutboundFetchPolicy( host: FetchHost = globalThis, diff --git a/test/outbound-fetch-anonymous-authority.test.ts b/test/outbound-fetch-anonymous-authority.test.ts index 35bcd7cc3..9ab3f2636 100644 --- a/test/outbound-fetch-anonymous-authority.test.ts +++ b/test/outbound-fetch-anonymous-authority.test.ts @@ -26,6 +26,24 @@ describe("anonymous GitHub API egress authority", () => { expect(response.headers.get("x-noema-egress-policy")).toBe("blocked-request-policy"); }); + it("rejects reviewed headers on the anonymous /meta diagnostic", async () => { + const metaUrl = "https://api.github.com/meta"; + const request = { + method: "GET", + headers: { accept: "application/vnd.github+json" }, + } satisfies RequestInit; + + expect(isTrustedCredentialEgressRequest(metaUrl, request)).toBe(false); + + const rawFetch = vi.fn(async () => new Response(null, { status: 204 })); + const wrapped = createFailClosedFetch(rawFetch); + const response = await wrapped(metaUrl, request); + + expect(rawFetch).not.toHaveBeenCalled(); + expect(response.status).toBe(502); + expect(response.headers.get("x-noema-egress-policy")).toBe("blocked-request-policy"); + }); + it("rejects arbitrary anonymous GitHub REST destinations outside reviewed operations", async () => { const unreviewedUrl = "https://api.github.com/repos/ContextualWisdomLab/noema/issues"; diff --git a/test/outbound-fetch-preaborted-signal.test.ts b/test/outbound-fetch-preaborted-signal.test.ts index 38fc18292..562be4a45 100644 --- a/test/outbound-fetch-preaborted-signal.test.ts +++ b/test/outbound-fetch-preaborted-signal.test.ts @@ -140,8 +140,8 @@ describe("credential-egress caller cancellation authority", () => { ); await pullStarted; caller.abort(reason); - releaseBody(); await expect(pending).rejects.toBe(reason); + releaseBody(); }); }); diff --git a/test/patch-validator-static-runtime.test.ts b/test/patch-validator-static-runtime.test.ts index 429031b20..89b560726 100644 --- a/test/patch-validator-static-runtime.test.ts +++ b/test/patch-validator-static-runtime.test.ts @@ -20,9 +20,13 @@ describe("patch-validator static scratch runtime", () => { expect(dockerfile).toContain("ARG NODE_VERSION=24.19.0"); expect(dockerfile).toContain(`ARG NODE_SOURCE_SHA256=${nodeSourceSha256}`); expect(dockerfile).toContain( - '"https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}.tar.xz"', + [ + " download_exact \\", + ' "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}.tar.xz" \\', + ' "$NODE_SOURCE_SHA256" \\', + " /tmp/node.tar.xz; \\", + ].join("\n"), ); - expect(dockerfile).toContain('"$NODE_SOURCE_SHA256"'); expect(dockerfile).toContain("sha256sum --check --strict"); expect(dockerfile).toContain("timeout --signal=TERM --kill-after=30s 5m"); expect(dockerfile).toContain("--connect-timeout 20"); @@ -80,4 +84,4 @@ describe("patch-validator static scratch runtime", () => { expect(workflow).toContain("--severity MEDIUM,HIGH,CRITICAL"); expect(workflow).toContain("--exit-code 1"); }); -}); \ No newline at end of file +});