Skip to content
File

Blob: tests/worker/lib/security-headers.test.ts

typescript72 lines
1import { describe, expect, it } from "vitest";
2import {
3 applyDocumentSecurityHeaders,
4 applySitesSecurityHeaders,
5 buildDocumentCsp,
6} from "@/worker/lib/security-headers";
7 
8describe("document security headers", () => {
9 it("includes the Sentry origin in connect-src when a DSN is configured", () => {
10 const csp = buildDocumentCsp({
11 nonce: "nonce-test",
12 requestUrl: "https://bland.tools/acme/page-1",
13 sentryDsn: "https://public@example.ingest.sentry.io/1",
14 });
15 
16 expect(csp).toContain("connect-src 'self' https://cloudflareinsights.com https://example.ingest.sentry.io");
17 expect(csp).toContain("script-src 'self' 'nonce-nonce-test' https://static.cloudflareinsights.com");
18 expect(csp).not.toContain("challenges.cloudflare.com");
19 expect(csp).toContain("upgrade-insecure-requests");
20 });
21 
22 it("omits the Sentry origin when no DSN is configured", () => {
23 const csp = buildDocumentCsp({
24 nonce: "nonce-test",
25 requestUrl: "https://bland.tools/acme/page-1",
26 sentryDsn: null,
27 });
28 
29 expect(csp).not.toContain("ingest.sentry.io");
30 expect(csp).not.toContain("fonts.googleapis.com");
31 expect(csp).not.toContain("fonts.gstatic.com");
32 expect(csp).toContain("style-src 'self' 'unsafe-inline'");
33 expect(csp).toContain("font-src 'self' https://esm.sh");
34 });
35 
36 it("relaxes connect-src for localhost without forcing insecure upgrades", () => {
37 const csp = buildDocumentCsp({
38 nonce: "nonce-test",
39 requestUrl: "http://localhost:8787/acme/page-1",
40 sentryDsn: null,
41 });
42 
43 expect(csp).toContain("connect-src 'self' https://cloudflareinsights.com http: https: ws: wss:");
44 expect(csp).toContain("script-src 'self' https://static.cloudflareinsights.com 'unsafe-inline' 'unsafe-eval'");
45 expect(csp).not.toContain("upgrade-insecure-requests");
46 });
47 
48 it("applies CSP and baseline headers to document responses", async () => {
49 const response = applyDocumentSecurityHeaders(new Response("<html></html>"), {
50 nonce: "nonce-test",
51 requestUrl: "https://bland.tools/acme/page-1",
52 sentryDsn: null,
53 });
54 
55 expect(response.headers.get("Content-Security-Policy")).toContain("'nonce-nonce-test'");
56 expect(response.headers.get("X-Frame-Options")).toBe("DENY");
57 expect(response.headers.get("Referrer-Policy")).toBe("strict-origin-when-cross-origin");
58 expect(response.headers.get("X-Content-Type-Options")).toBe("nosniff");
59 expect(await response.text()).toBe("<html></html>");
60 });
61 
62 it("allows same-origin scripts and Cloudflare Insights on Sites responses", () => {
63 const response = applySitesSecurityHeaders(new Response("<html></html>"));
64 const csp = response.headers.get("Content-Security-Policy");
65 
66 expect(csp).toContain("script-src 'self' https://static.cloudflareinsights.com");
67 expect(csp).toContain("connect-src 'self' https://cloudflareinsights.com");
68 expect(csp).not.toContain("script-src 'self' 'unsafe-inline'");
69 expect(csp).not.toContain("'unsafe-eval'");
70 });
71});