import { describe, expect, it } from "vitest"; import { safeResponseMetadata } from "./CdpSafeMetadata.js"; const origin = "https://app.example.test"; describe("structured COOP and COEP declarations", () => { it.each([ ["same-origin", "same-origin"], ['same-origin; report-to="coop"', "same-origin"], ['require-corp; report-to="coep"', "require-corp"], ['credentialless; report-to="a; b, c"', "credentialless"], [String.raw`same-origin; report-to="a\"b\\c"`, "same-origin"], [ "same-origin; enabled; n=-999999999999999; f=999999999999.999", "same-origin", ], ["same-origin; flag=?0; bin=:YQ:; date=@123", "same-origin"], ['same-origin; label=%"%c3%a9"', "same-origin"], ["same-origin; value=one; value=two", "same-origin"], [' same-origin; report-to="coop" ', "same-origin"], ["FuturePolicy", "FuturePolicy"], ['same-origin; report-to="unterminated', null], [String.raw`same-origin; report-to="bad\q"`, null], ["same-origin; Report-To=endpoint", null], ["same-origin ; report-to=endpoint", null], ["same-origin; report-to =endpoint", null], ["same-origin; report-to= endpoint", null], ["same-origin; report-to=", null], ["same-origin;", null], ["same-origin, require-corp", null], ["same-origin\nrequire-corp", null], ['"same-origin"; report-to="coop"', null], ["same-origin; n=1000000000000000", null], ["same-origin; f=1.1234", null], ["same-origin; b=?2", null], ["same-origin; bin=:a:", null], ["same-origin; bin=:YQ=:", null], ['same-origin; label=%"%ff"', null], ['same-origin; label=%"%C3%A9"', null], ['same-origin; label="é"', null], ["same-origin\t", null], ["", null], [undefined, null], ] as const)( "parses the complete structured token item %j", (value, expected) => { const captured = safeResponseMetadata( "policies", `${origin}/page`, { headers: { "Cross-Origin-Opener-Policy": value, "Cross-Origin-Embedder-Policy": value, "Cross-Origin-Resource-Policy": 'same-origin; report-to="not-structured"', "X-Content-Type-Options": 'nosniff; report-to="not-structured"', }, }, new Set([origin]), ); expect(captured.response.policies).toMatchObject({ coop: expected, coep: expected, corp: null, x_content_type_options: null, }); }, ); }); describe("safe CDP response metadata", () => { it("drops credential headers and preserves complete local link URLs", () => { const captured = safeResponseMetadata( "request-1", `${origin}/api`, { mimeType: "application/json", headers: { Authorization: "Bearer credential-secret", Cookie: "session=cookie-secret", "Set-Cookie": "session=response-secret", Link: `; rel="mcp service-desc"; title="a,b", ; rel="mcp"`, "Content-Security-Policy": "default-src 'self'; script-src 'nonce-nonce-secret' 'sha256-hash-secret' https://private.example.test", "Permissions-Policy": "camera=(), geolocation=(self), invalid secret=()", "X-Model-Context": "agent-header-secret", }, }, new Set([origin]), ); expect(captured.response).toMatchObject({ url: `${origin}/api`, csp: { nonce_count: 1, hash_count: 1, directives: expect.arrayContaining([ expect.objectContaining({ name: "script-src", sources: expect.arrayContaining([ { kind: "external_origin", value: null }, ]), }), ]), }, links: [ { href: `${origin}/agent?token=link-secret`, destination_scope: "approved", rel: ["mcp", "service-desc"], as: null, type: null, crossorigin: null, }, expect.objectContaining({ href: "https://private.example.test/x", destination_scope: "outside_policy", }), ], policies: { permissions_policy_features: ["camera", "geolocation"] }, }); expect(captured.agentHints).toEqual( expect.arrayContaining([ expect.objectContaining({ mechanism: "link_rel" }), expect.objectContaining({ mechanism: "response_header", declaration: "x-model-context", }), ]), ); const serialized = JSON.stringify(captured); for (const secret of [ "credential-secret", "cookie-secret", "response-secret", "nonce-secret", "hash-secret", "agent-header-secret", ]) expect(serialized).not.toContain(secret); expect(serialized).toContain("link-secret"); expect(serialized).toContain("private.example.test/x"); }); it("reports well-known agent resources as untrusted observations", () => { const captured = safeResponseMetadata( "request-2", `${origin}/.well-known/mcp?token=secret`, { headers: {} }, new Set([origin]), ); expect(captured.agentHints).toEqual([ { mechanism: "well_known_resource", declaration: "/.well-known/mcp", url: `${origin}/.well-known/mcp?token=secret`, trust: "page-declared-untrusted", }, ]); }); it.each(["/.well-known/MCP", "/.WELL-KNOWN/mcp"])( "does not case-fold a different well-known resource path: %s", (path) => { const captured = safeResponseMetadata( "request-case-variant", `${origin}${path}`, { headers: {} }, new Set([origin]), ); expect(captured.response.url).toBe(`${origin}${path}`); expect(captured.agentHints).toEqual([]); }, ); it("retains every parsed header, CSP directive, link, relation, and policy feature", () => { const csp = Array.from( { length: 105 }, (_, index) => `x-${String(index)} 'self'`, ).join("; "); const links = Array.from( { length: 105 }, (_, index) => `; rel="mcp service-desc"`, ).join(", "); const permissions = Array.from( { length: 205 }, (_, index) => `feature-${String(index)}=()`, ).join(", "); const headers = Object.fromEntries( Array.from({ length: 501 }, (_, index) => [ `x-extra-${String(index)}`, "ok", ]), ); const captured = safeResponseMetadata( "request-1", `${origin}/api`, { mimeType: "application/json", headers: { ...headers, "Content-Security-Policy": csp, Link: links, "Permissions-Policy": permissions, "X-Model-Context": "present-after-many-headers", }, }, new Set([origin]), ); expect(captured.response.csp.directives).toHaveLength(105); expect(captured.response.links).toHaveLength(105); expect(captured.response.policies.permissions_policy_features).toHaveLength( 205, ); expect(captured.agentHints).toContainEqual( expect.objectContaining({ declaration: "x-model-context" }), ); }); }); describe("safe CDP response metadata CSP sources", () => { it("classifies scheme-less CSP host sources by their own host, not the page origin", () => { const captured = safeResponseMetadata( "request-csp", `${origin}/api`, { headers: { "Content-Security-Policy": "script-src cdn.example.test *.trusted.test * 'self' https://api.other.test", }, }, new Set([origin]), ); expect(captured.response.csp.directives).toEqual([ { name: "script-src", sources: [ { kind: "external_origin", value: null }, { kind: "external_origin", value: null }, { kind: "external_origin", value: null }, { kind: "keyword", value: "'self'" }, { kind: "external_origin", value: null }, ], }, ]); }); it("inherits the protected resource scheme for a scheme-less host source", () => { const captured = safeResponseMetadata( "request-csp-scheme", `${origin}/api`, { headers: { "Content-Security-Policy": "script-src cdn.example.test app.example.test", }, }, new Set([origin, "https://cdn.example.test"]), ); expect(captured.response.csp.directives[0]?.sources).toEqual([ { kind: "approved_origin", value: "https://cdn.example.test" }, { kind: "approved_origin", value: origin }, ]); }); }); describe("Link header value delimiters", () => { const captureLinks = (link: string) => safeResponseMetadata( "owned", "https://owned.test/page", { headers: { Link: link }, }, new Set(["https://owned.test"]), ).response.links; it.each([", ", "\n", "\r\n"])( "preserves repeated field declarations and agent hints joined by %j", (separator) => { const captured = safeResponseMetadata( "document-response", `${origin}/page`, { headers: { Link: [ '; rel="preload"; type="text/javascript; charset=utf-8"; title="a,b"', '; rel="mcp service-desc"', ].join(separator), }, }, new Set([origin]), ); expect(captured.response.links).toMatchObject([ { href: `${origin}/assets/red,blue.js`, rel: ["preload"], type: "text/javascript; charset=utf-8", }, { href: `${origin}/agent?selected=keep`, rel: ["mcp", "service-desc"], }, ]); expect(captured.agentHints).toContainEqual({ mechanism: "link_rel", declaration: "mcp service-desc", url: `${origin}/agent?selected=keep`, trust: "page-declared-untrusted", }); }, ); it("keeps delimiters scoped to each CDP field line", () => { const links = captureLinks( '; title="unterminated\n; rel=mcp', ); expect(links.map(({ href }) => href)).toEqual([ "https://owned.test/first", "https://owned.test/agent", ]); expect(links[1]?.rel).toEqual(["mcp"]); }); it("preserves commas in URI references and separates later links", () => { const links = captureLinks( '; rel="preload"; as=script, ; rel="modulepreload"', ); expect(links.map(({ href }) => href)).toEqual([ "https://owned.test/assets/red,blue.js", "https://owned.test/ordinary.js", ]); expect(links[0]?.as).toBe("script"); }); it("preserves semicolons and commas inside quoted parameter values", () => { const links = captureLinks( '; rel="preload"; type="text/javascript; charset=utf-8"; title="a,b", ; rel="modulepreload"', ); expect(links).toHaveLength(2); expect(links[0]?.type).toBe("text/javascript; charset=utf-8"); expect(links[1]?.href).toBe("https://owned.test/ordinary.js"); }); it("counts quoted-pair escapes rather than treating every preceding slash as an escape", () => { const links = captureLinks( String.raw`; title="ends with \\"; rel="preload", ; rel="modulepreload"`, ); expect(links.map(({ href }) => href)).toEqual([ "https://owned.test/one.js", "https://owned.test/two.js", ]); expect(links[0]?.rel).toEqual(["preload"]); }); it("keeps a quoted escaped quote from exposing a delimiter", () => { const links = captureLinks( String.raw`; title="quoted \" comma, value"; rel="preload", ; rel="modulepreload"`, ); expect(links).toHaveLength(2); expect(links[0]?.rel).toEqual(["preload"]); }); it("retains the existing outside-policy classification", () => { const links = captureLinks( '; rel="preload", ; rel="modulepreload"', ); expect(links[0]?.destination_scope).toBe("outside_policy"); expect(links[1]?.destination_scope).toBe("approved"); }); }); describe("safe CDP response metadata referrer policy", () => { it.each<[string | undefined, string | null]>([ [ "no-referrer, strict-origin-when-cross-origin", "strict-origin-when-cross-origin", ], ["origin, future-policy", "origin"], ["future-policy, no-referrer", "no-referrer"], ["unsafe-url, NO-REFERRER", "no-referrer"], ["origin,, no-referrer", "no-referrer"], ["future-policy", null], ['unsafe-url, "no-referrer"', null], ["no-referrer; report-to=x, origin", null], ["", null], [undefined, null], ...[ "no-referrer", "no-referrer-when-downgrade", "same-origin", "origin", "strict-origin", "origin-when-cross-origin", "strict-origin-when-cross-origin", "unsafe-url", ].map((policy): [string, string] => [policy, policy]), ])("normalizes declared Referrer-Policy %s", (raw, expected) => { const captured = safeResponseMetadata( "request-referrer", `${origin}/api`, { headers: { "Referrer-Policy": raw, "Cross-Origin-Opener-Policy": "same-origin", }, }, new Set([origin]), ); expect(captured.response.policies.referrer_policy).toBe(expected); expect(captured.response.policies.coop).toBe("same-origin"); }); it.each<[string | number | undefined, number | null]>([ ["100", 100], [" 0 ", 0], [100, 100], ["-5", null], ["+12", null], ["0x10", null], ["1e3", null], ["9007199254740991", 9007199254740991], ["9007199254740992", null], [undefined, null], ])("declares Content-Length %j only for decimal digits", (raw, expected) => { const captured = safeResponseMetadata( "request-length", `${origin}/api`, { headers: raw === undefined ? {} : { "Content-Length": raw } }, new Set([origin]), ); expect(captured.response.content_length).toBe(expected); }); });