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 = "<html><body><form action='https://evil.test'></form></body></html>";
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("</body>"));
});
test("appends the banner to HTML fragments without a body element", async () => {
const text = await hardenScratchResponse(
new Response("<h1>hi</h1>", { headers: { "content-type": "text/html; charset=utf-8" } }),