feat(csp): promote Trusted Types from report-only to enforcing (#130)#712
feat(csp): promote Trusted Types from report-only to enforcing (#130)#712millsmillsymills wants to merge 3 commits into
Conversation
Fold `require-trusted-types-for 'script'; trusted-types default` into both enforcing CSP headers (site + webauthn policies) and drop the standalone `Content-Security-Policy-Report-Only` TT slices. The runtime is enforce-clean (#711 removed the last injection sinks); the one legitimate sink — the PoW Worker URL — is wrapped by the fail-closed `default` policy in src/scripts/util/trusted-types.ts. Updates the /security/ control entry to match. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Review summaryDiff is correct: folds Leaving as DRAFT per the merge precondition in the PR body — the report-only → enforce flip needs the 1–2wk clean-report soak, and #711 (last-sink removal) only just landed, so the soak clock effectively just started. Merge once |
…/editor.ts #711 stripped every Trusted Types injection sink from vscode/editor.ts, so citing it as the trusted-types control evidence is drift. The lone legitimate sink is the PoW Worker URL in mail-pow.ts (which calls installDefaultTrustedTypesPolicy), matching the tradeoffs prose. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
/pr-review summaryReviewed diff (3 files, +18/-39). Quality gates green: Should-fix (resolved in
No must-fix issues. CSP strings are byte-identical across site + passkey_demo policies; the Not merging — soak gate holds. Per #130 acceptance + this PR's own merge precondition, the report-only→enforce flip merges only after the CSP report stream stays clean for the 1–2 week soak. #711 (removed the last sinks) merged today (2026-06-09), so the clean-report clock just started. Stays draft until ~2026-06-23 earliest, pending 🤖 Generated with Claude Code |
Soak baseline — clock started 2026-06-09 18:33 UTC#711 (last-sink removal) hit prod in the Queried the live report store (
Merge precondition (mechanical)Earliest clean-soak merge: ~2026-06-23 (14 days from the 06/09 18:33 deploy). Before merging, re-run: aws s3 ls s3://millsymills.com-csp-reports/reports/2026/06/ --recursive | \
awk '{print $4}' | sed -E 's#reports/([0-9/]+)/[^/]+$#\1#' | sort | uniq -cand confirm any post-06/09 reports carry no |
|
Review pass (2026-06-09, post-#715):
|
|
Superseded by #718 — same enforce flip, rebased onto main post-#715 (this branch's stale state conflicted on cloudfront.tf + security-controls.ts and its directive dropped the |
Closes #130 once merged + deployed.
What
require-trusted-types-for 'script'; trusted-types defaultinto both enforcing CSP headers (aws_cloudfront_response_headers_policy.siteand the WebAuthn policy) ininfra/cloudfront.tf.Content-Security-Policy-Report-OnlyTT slices — under enforce, violations both block and still report (the enforcing CSP keepsreport-uri/report-to).trusted-typesentry on/security/(title → "enforced",what/why/tradeoffsreworded) and the header comment insrc/scripts/util/trusted-types.ts.Why enforce is safe now
#711 made the runtime enforce-clean (removed the
command-palette+vscode/editorinjection sinks). The only legitimate sink left — the PoW Worker URL spawned bymail-pow.ts— is wrapped by the fail-closeddefaultpolicy insrc/scripts/util/trusted-types.ts, which mints only same-origin/_astro/script URLs and throws on everything else.This is the report-only → enforce flip. Per #130's acceptance, merge only after the report stream has stayed clean for the 1–2 week soak window. #711 (which removed the last sinks) merged recently, so the clean-report clock effectively just started. Verify
/api/csp-reportshows no TT violations across that window before merging. Takes effect onterraform applyafter merge + deploy.Verification done
terraform fmt -check+terraform validate✓npm run check(0 errors) ✓SITE_URL=… npm run build✓vitest tests/csp_report.test.ts(36 passed) ✓ — no test pins the CSP string🤖 Generated with Claude Code