import { describe, expect, mock, test } from "bun:test"; mock.module("cloudflare:workers", () => ({ env: {}, waitUntil: () => undefined })); const { ensureSecurityHeaders, hardenScratchResponse, SCRATCH_BANNER } = await import("./harden"); const { SECURITY_HEADERS } = await import("./static"); describe("hardenScratchResponse", () => { test("forces scratch headers over whatever a user worker set", async () => { const response = hardenScratchResponse( new Response("{}", { headers: { "content-type": "application/json", "content-security-policy": "form-action *", "x-robots-tag": "all", }, }), ); const csp = response.headers.get("content-security-policy") ?? ""; expect(csp).toContain("form-action 'self'"); expect(csp).not.toContain("https:"); expect(response.headers.get("x-robots-tag")).toContain("noindex"); expect(response.headers.get("x-content-type-options")).toBe("nosniff"); expect(await response.text()).toBe("{}"); }); test("injects the banner into HTML bodies and drops the stale length", async () => { const body = "
"; const response = hardenScratchResponse( new Response(body, { status: 404, headers: { "content-type": "text/html", "content-length": "65" } }), ); expect(response.status).toBe(404); expect(response.headers.get("content-length")).toBeNull(); const text = await response.text(); expect(text).toContain(SCRATCH_BANNER); expect(text.indexOf(SCRATCH_BANNER)).toBeLessThan(text.indexOf("")); }); test("appends the banner to HTML fragments without a body element", async () => { const text = await hardenScratchResponse( new Response("

hi

", { headers: { "content-type": "text/html; charset=utf-8" } }), ).text(); expect(text.split(SCRATCH_BANNER)).toHaveLength(2); }); test("keeps bodiless responses bodiless", () => { const response = hardenScratchResponse( new Response(null, { status: 304, headers: { "content-type": "text/html" } }), ); expect(response.status).toBe(304); expect(response.body).toBeNull(); }); }); describe("ensureSecurityHeaders", () => { test("restores stripped headers but keeps a claimed site's own choices", () => { const response = ensureSecurityHeaders( new Response("ok", { headers: { "content-security-policy": "default-src 'self'" } }), ); expect(response.headers.get("content-security-policy")).toBe("default-src 'self'"); for (const name of Object.keys(SECURITY_HEADERS)) expect(response.headers.has(name)).toBe(true); }); });