Skip to content

feat(csp): promote Trusted Types from report-only to enforcing (#130)#712

Closed
millsmillsymills wants to merge 3 commits into
mainfrom
feat/130-trusted-types-enforce
Closed

feat(csp): promote Trusted Types from report-only to enforcing (#130)#712
millsmillsymills wants to merge 3 commits into
mainfrom
feat/130-trusted-types-enforce

Conversation

@millsmillsymills

Copy link
Copy Markdown
Owner

Closes #130 once merged + deployed.

What

  • Folds require-trusted-types-for 'script'; trusted-types default into both enforcing CSP headers (aws_cloudfront_response_headers_policy.site and the WebAuthn policy) in infra/cloudfront.tf.
  • Removes the two standalone Content-Security-Policy-Report-Only TT slices — under enforce, violations both block and still report (the enforcing CSP keeps report-uri/report-to).
  • Updates the trusted-types entry on /security/ (title → "enforced", what/why/tradeoffs reworded) and the header comment in src/scripts/util/trusted-types.ts.

Why enforce is safe now

#711 made the runtime enforce-clean (removed the command-palette + vscode/editor injection sinks). The only legitimate sink left — the PoW Worker URL spawned by mail-pow.ts — is wrapped by the fail-closed default policy in src/scripts/util/trusted-types.ts, which mints only same-origin /_astro/ script URLs and throws on everything else.

⚠️ DRAFT — merge precondition

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-report shows no TT violations across that window before merging. Takes effect on terraform apply after 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

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>
@millsmillsymills

Copy link
Copy Markdown
Owner Author

Review summary

Diff is correct: folds require-trusted-types-for 'script'; trusted-types default into both enforcing CSP headers byte-identically, drops the two -Report-Only slices, and repoints code: at the real src/scripts/util/trusted-types.ts policy (the old command-palette.ts sink was removed in #711). No correctness findings.

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 /api/csp-report shows no TT violations across that window. Tracked by #130.

millsmillsymills and others added 2 commits June 9, 2026 14:43
…/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>
@millsmillsymills

Copy link
Copy Markdown
Owner Author

/pr-review summary

Reviewed diff (3 files, +18/-39). Quality gates green: npm run check (0 errors), SITE_URL=… npm run build ✓.

Should-fix (resolved in bbd7220):

  • security-controls.ts code: array cited src/scripts/vscode/editor.ts as Trusted Types evidence, but refactor(csp): make runtime Trusted Types enforce-clean (#130) #711 stripped every TT injection sink from that file — stale citation. Swapped to src/scripts/mail-pow.ts, the lone legitimate sink (PoW Worker URL, calls installDefaultTrustedTypesPolicy), which now matches the tradeoffs prose. Keeps the /security/ "every claim cites the implementation" invariant honest.

No must-fix issues. CSP strings are byte-identical across site + passkey_demo policies; the default TT policy fails closed (same-origin /_astro/ only). Removal of the -Report-Only slices is correct — the enforcing CSP retains report-uri/report-to so violations still report.

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 /api/csp-report showing no TT violations across the window.

🤖 Generated with Claude Code

@millsmillsymills

Copy link
Copy Markdown
Owner Author

Soak baseline — clock started 2026-06-09 18:33 UTC

#711 (last-sink removal) hit prod in the workflow_dispatch deploy at 2026-06-09 18:33 UTC (deploys don't fire on push, so the merge time isn't the soak start — the deploy time is).

Queried the live report store (s3://millsymills.com-csp-reports/reports/) to baseline the window:

  • Pre-deploy (06/04–06/05): 19 report envelopes → 64 require-trusted-types-for violations + 1 media-src + 1 script-src. Those TT hits are the command-palette + vscode/editor sinks refactor(csp): make runtime Trusted Types enforce-clean (#130) #711 removed.
  • Post-deploy (06/06 → now): zero reports of any kind. No TT violations since the sinks left prod.

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 -c

and confirm any post-06/09 reports carry no require-trusted-types-for effectiveDirective. The 30-day lifecycle means the pre-deploy TT noise ages out on its own; only post-06/09-18:33 entries gate the merge.

@millsmillsymills

Copy link
Copy Markdown
Owner Author

Review pass (2026-06-09, post-#715):

  • fix(security): remediate /security page drift + make unifi-demo TT enforce-safe #715 merged first and moved the CSP literals into local.html_csp / local.html_tt_report_only, added the unifi-demo TT policy (public/apps/unifi-demo/app.js), and relocated the trusted-types entry in security-controls.ts. This branch as-pushed conflicts on both shared files, and its enforcing directive (trusted-types default) drops unifi-demo — under enforcement createPolicy('unifi-demo') throws and the demo renders its disabled banner.
  • Branch has been rebased locally onto main (2fc8e5f) with the fixes: enforcing directive is trusted-types default unifi-demo folded into local.html_csp (report-only local + header blocks removed), single trusted-types entry citing cloudfront.tf + trusted-types.ts + mail-pow.ts + unifi-demo app.js, trusted-types.ts comment scoped to the default policy. terraform fmt/validate, npm run check, and full build all pass. Force-push to this branch pending.
  • Soak unchanged: report stream clean since 2026-06-09 18:33 UTC deploy; earliest merge ~2026-06-23.
  • Related: CI assert: Trusted Types policy names must stay in sync between CSP directive and createPolicy call sites #716 (CI assert coupling TT policy names between directive and createPolicy call sites).

@millsmillsymills

Copy link
Copy Markdown
Owner Author

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 unifi-demo policy name; repo guardrails block force-push, so the rebase ships on a fresh branch). Soak window unchanged: earliest merge ~2026-06-23.

@millsmillsymills millsmillsymills deleted the feat/130-trusted-types-enforce branch June 9, 2026 23:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Trusted Types enforcement to CSP

1 participant