import { test, expect } from './fixtures'; // Defense-in-depth response headers on document navigations (T4 in the security // audit). The CSP is emitted by SvelteKit's kit.csp config; the clickjacking / // referrer / permissions headers by hooks.server.ts. We assert on the raw // response of a document navigation, and separately confirm the inline theme // script still executes under the CSP (its sha256 is allowlisted) by checking // the data-theme attribute it sets — a CSP block would leave it unset. test('document responses carry the security headers', async ({ page }) => { const response = await page.goto('/'); expect(response, 'navigation returned a response').not.toBeNull(); const headers = response!.headers(); // Clickjacking: both the legacy header and the CSP directive. expect(headers['x-frame-options']).toBe('DENY'); expect(headers['content-security-policy']).toContain("frame-ancestors 'none'"); // Script-injection surface reduction. expect(headers['content-security-policy']).toContain("object-src 'none'"); expect(headers['content-security-policy']).toContain('script-src'); // The non-CSP hardening headers. expect(headers['referrer-policy']).toBe('strict-origin-when-cross-origin'); expect(headers['x-content-type-options']).toBe('nosniff'); expect(headers['permissions-policy']).toContain('geolocation=()'); }); test('the inline theme script executes under the CSP (hash is allowlisted)', async ({ page }) => { // If the theme script were CSP-blocked, data-theme would never be set. // Its presence proves the allowlisted sha256 matches the served script. await page.goto('/'); const theme = await page.evaluate(() => document.documentElement.getAttribute('data-theme') ); expect(theme === 'light' || theme === 'dark').toBe(true); });