60 lines · 2.6 KB
import { describe, expect, mock, test } from "bun:test";

mock.module("cloudflare:workers", () => ({ env: {} }));

const { pageCsp, withSecurityHeaders } = await import("./security-headers");

describe("withSecurityHeaders (DEPLOY-P7)", () => {
  test("adds nosniff, referrer policy, frame denial and HSTS on https", () => {
    const response = withSecurityHeaders(new Response("ok"), new Request("https://gitfor.dev/"));
    expect(response.headers.get("x-content-type-options")).toBe("nosniff");
    expect(response.headers.get("referrer-policy")).toBe("strict-origin-when-cross-origin");
    expect(response.headers.get("x-frame-options")).toBe("DENY");
    expect(response.headers.get("strict-transport-security")).toContain("max-age=");
  });

  test("no HSTS over http or on loopback", () => {
    expect(
      withSecurityHeaders(new Response("ok"), new Request("http://localhost:3000/")).headers.has(
        "strict-transport-security",
      ),
    ).toBe(false);
  });

  test("a route's own values win and immutable redirects still get headers", () => {
    const own = new Response("ok", { headers: { "referrer-policy": "no-referrer" } });
    expect(withSecurityHeaders(own, new Request("https://gitfor.dev/")).headers.get("referrer-policy")).toBe(
      "no-referrer",
    );
    const redirect = withSecurityHeaders(
      Response.redirect("https://gitfor.dev/x", 302),
      new Request("https://gitfor.dev/"),
    );
    expect(redirect.status).toBe(302);
    expect(redirect.headers.get("x-content-type-options")).toBe("nosniff");
  });
});

describe("pageCsp", () => {
  test("app pages forbid framing, plugins and off-origin forms and base", () => {
    const csp = pageCsp("https://gitforusercontent.dev", null);