Backport Slugkit browser security headers with trusted site nonce wiring #20

Merged
erik merged 1 commit from task-dae6192b-security-headers into main 2026-10-05 16:50:56 -05:00
Owner

Summary

Scoped backport for task-dae6192b of merged Slugkit PR #296 / fdfd33ea485b8800c4aee86751d0d985d0bb46e8 onto deployed 0.3.12, preserving site branding/CSRF/API/federation. Adds global nonce CSP, DENY framing, nosniff, referrer and minimal permissions policy; trusted nonce wiring includes the site's About/Fediverse follow script and existing setup/settings/public scripts. Swagger major-5 scripts are nonced; its CDN style exception is docs-only and remote validator disabled. No unsafe-inline/eval, added isolation policies, wildcard executable origins, HTML rewriting or forwarding-header HSTS inference.

HSTS stays off by default/local. Companion homelab PR prepares explicit production max-age=300, no subdomains/preload, alongside already-verified HTTPS origin/Traefik TLS. Both merges/publication remain human-gated; image publication auto-deploys. Proposed release is 0.3.13, not yet published. No new backup/secret/database operation.

Verification

  • Build/lint/whitespace pass; 468 full local tests and 392 deterministic CI-safe tests pass (31 new header/configuration cases).
  • 40 local Playwright browser checks pass, including 6 header cases: color mode/live search, blob previews, real virtual-authenticator passkeys, actual Swagger CDN/OpenAPI/Try it out, framing and blocked unapproved executable/style/handler/connect sources. Existing geometry and CSRF flows remain covered. Browser fixture is loopback/in-memory with fake storage/mail; no production workflow tests or personal credentials.
  • Existing local federation test asserts actor header/MIME compatibility. Existing About page test checks nonce coverage for its site-owned script; existing behavioral tests still run.
  • Local 0.3.13 production-image build/health/API/homepage validation pass. Source headers.ts exactly matches upstream; site-specific differences are explicit nonce hooks/docs/test adaptation.
  • Generated CSS adds only .inline{display:inline}, discovered from test source; no layout stylesheet rewrite. Raw diff is large because existing CSS is minified.
  • Dependencies/lockfile, Playwright config, CI/release workflows and release skill unchanged. No new browser/integration/container tests or runtime provisioning in workflows.

Deployment/closure evidence

Review current implementation/configuration; actual deployed-header/post-publication criteria remain pending, not claimed met by local tests. After approved merge/publication, production verification is read-only release/image/header inspection, not login/passkey/upload/key/user/other workflow tests. Documented rollback retains CSRF by pinning prior 0.3.12 index through approved GitOps automation suspension, preserves data/secrets, and maintains HTTPS while the short cached HSTS lifetime expires.

## Summary Scoped backport for task-dae6192b of merged Slugkit PR #296 / fdfd33ea485b8800c4aee86751d0d985d0bb46e8 onto deployed 0.3.12, preserving site branding/CSRF/API/federation. Adds global nonce CSP, DENY framing, nosniff, referrer and minimal permissions policy; trusted nonce wiring includes the site's About/Fediverse follow script and existing setup/settings/public scripts. Swagger major-5 scripts are nonced; its CDN style exception is docs-only and remote validator disabled. No unsafe-inline/eval, added isolation policies, wildcard executable origins, HTML rewriting or forwarding-header HSTS inference. HSTS stays off by default/local. Companion homelab PR prepares explicit production max-age=300, no subdomains/preload, alongside already-verified HTTPS origin/Traefik TLS. Both merges/publication remain human-gated; image publication auto-deploys. Proposed release is 0.3.13, not yet published. No new backup/secret/database operation. ## Verification - Build/lint/whitespace pass; 468 full local tests and 392 deterministic CI-safe tests pass (31 new header/configuration cases). - 40 local Playwright browser checks pass, including 6 header cases: color mode/live search, blob previews, real virtual-authenticator passkeys, actual Swagger CDN/OpenAPI/Try it out, framing and blocked unapproved executable/style/handler/connect sources. Existing geometry and CSRF flows remain covered. Browser fixture is loopback/in-memory with fake storage/mail; no production workflow tests or personal credentials. - Existing local federation test asserts actor header/MIME compatibility. Existing About page test checks nonce coverage for its site-owned script; existing behavioral tests still run. - Local 0.3.13 production-image build/health/API/homepage validation pass. Source headers.ts exactly matches upstream; site-specific differences are explicit nonce hooks/docs/test adaptation. - Generated CSS adds only `.inline{display:inline}`, discovered from test source; no layout stylesheet rewrite. Raw diff is large because existing CSS is minified. - Dependencies/lockfile, Playwright config, CI/release workflows and release skill unchanged. No new browser/integration/container tests or runtime provisioning in workflows. ## Deployment/closure evidence Review current implementation/configuration; actual deployed-header/post-publication criteria remain pending, not claimed met by local tests. After approved merge/publication, production verification is read-only release/image/header inspection, not login/passkey/upload/key/user/other workflow tests. Documented rollback retains CSRF by pinning prior 0.3.12 index through approved GitOps automation suspension, preserves data/secrets, and maintains HTTPS while the short cached HSTS lifetime expires.
feat: backport nonce-based browser headers without replacing site templates
All checks were successful
CI / build-lint-test (push) Successful in 39s
fdcee3f2ee
Author
Owner

Independent bounded review — website PR #20

Task: task-dae6192b
PR: #20
Reviewed head: fdcee3f2ee
Companion: homelab #139 at e1e5def43b0742b47d60eb5ed9de9c2bfc7434f8

Summary and provenance

Reviewed current open PR title/body and all non-CSS diff blocks in /tmp/evc-headers-pr20-noncss.patch, excluding only a/src/styles/public.css from /tmp/evc-headers-pr20-full.patch. Independently compared raw CSS old/new lines and tracked CSS against origin/main: exactly one added .inline{display:inline}, otherwise byte-identical; new test source has the inline identifier, consistent with Tailwind source detection. This is not a stylesheet rewrite.

Independently byte-compared src/security/headers.ts to merged Slugkit #296 commit fdfd33ea485b8800c4aee86751d0d985d0bb46e8 at template/site/src/security/headers.ts: identical. Middleware precedes setup/CSRF/routes; AsyncLocalStorage isolates trusted request nonces and HTML no-store prevents nonce reuse via caches. Trusted public/settings/setup/About hooks and scoped Swagger renderer reviewed. No arbitrary HTML rewriting or new executable-origin allowance.

Changed-path inventory contains no dependency/lockfile/Playwright-config/CI-release-workflow/release-skill changes. No API/federation/CSRF behavioral changes. Existing setup-gate liveness test adaptation avoids unrelated upstream behavior adoption.

Evidence reused, not rerun

Read existing /tmp/evc-headers-{build,lint,tests,ci-tests,browser,image-build,image-check,homelab-tests,homelab-dry-run}.log summaries: build/lint, 468 full tests, 392 CI-safe tests, 40 local browser checks, local image build/0.3.13 validation, 47 offline homelab tests and schema-client dry-run. Task/PR evidence reports 31 header/config cases, full Kustomize/whitespace and isolated fake mail/media/virtual authenticator. Parent resolved website CI #73 success at this exact head; reused that result without new CI/network checks. Homelab has no applicable workflow, not a green CI claim.

No tests/builds/browser/containers/production operations were run in this review. Local image evidence does not establish published/deployed headers.

Original acceptance criteria (all six)

  1. partial — Representative deployed HTML, authentication/settings, API, media, feed and federation responses include intended headers. Global middleware and local MIME/status/header tests plus the existing actor integration assertion demonstrate implementation. Actual deployed response evidence is pending separately approved rollout; current production remains 0.3.12.
  2. met — CSP blocks unapproved executable/frame/resource sources while applicable browser features continue working. Nonce-only scripts, denied attributes/frames/objects and same-origin connections are covered by deterministic tests and existing local browser evidence for color mode/search, previews, virtual passkeys, real Swagger CDN/OpenAPI/Try it out and negative CSP/framing cases. API/federation/CSRF contracts remain intact.
  3. partial — Local HTTP emits no HSTS; production transport matches verified HTTPS configuration. Defaults/non-production/forwarded-header tests demonstrate no inferred HSTS. Paired config prepares exactly max-age=300 for explicit production HTTPS origin, without subdomains/preload. Previously recorded TLS/proxy baseline supports this opt-in; actual deployed HSTS remains pending approval.
  4. met — Site/proxy policies are consistent and customizations preserved. App owns headers; existing verified Traefik TLS/canonical redirects have no competing security-header middleware. About/Fediverse trusted script is nonced; branding/forms/CSRF/media/federation routing remain unchanged. Proxy-only redirects are explicitly outside application header coverage.
  5. partial — Local verification evidence and post-deployment checks recorded. Existing local logs and task/PR evidence cover implementation; post-deployment release/image/header observations are deliberately deferred, not supplied or inferred from local success.
  6. met — Site exceptions, TLS/proxy assumptions, deployment and rollback documented. Website rollout/security docs and companion runbook specify docs-only Swagger major-5 style path, nonced CDN script/initializer, disabled remote validator, HTTPS/data/blob image/media exceptions, explicit TLS assumptions, paired approvals/restarts and GitOps-only rollback preserving 0.3.12 CSRF/data/secrets/TLS.

Counts: criteria_total=6; criteria_met=3; criteria_partial=3; criteria_missing=0. Here missing counts not-evident criteria; partial criteria are explicitly not fully met.

Decision and approval boundary

approved, for implementation/configuration review only. No not-evident criterion, missing logic test, correctness issue or policy violation found. The three partial criteria have substantive repository/local evidence; their outstanding production observations belong to the separately approved deployment phase, not an implementation defect. This is not task completion or a claim of public headers.

Blocking issues: 0. Warnings: 0. Deferred approval-gated observations are recorded as partial criteria, not invented remediation requirements.

Require explicit human merge approval for each PR; homelab main auto-applies and may restart production. Publication/deployment/HSTS activation and task closure require separate approval. Proposed 0.3.13 remains unpublished; neither PR was merged. Later production verification is limited to read-only release/image/header inspection. No production workflow/browser/auth tests, new backups, secrets or dependency remediation are prerequisites for this header-only scope.

# Independent bounded review — website PR #20 Task: task-dae6192b PR: https://forge.caradoc.com/erik/erikvancraddock.com/pulls/20 Reviewed head: fdcee3f2ee7c7f2da847a859f218a7d6ad5f8f35 Companion: homelab #139 at e1e5def43b0742b47d60eb5ed9de9c2bfc7434f8 ## Summary and provenance Reviewed current open PR title/body and all non-CSS diff blocks in /tmp/evc-headers-pr20-noncss.patch, excluding only a/src/styles/public.css from /tmp/evc-headers-pr20-full.patch. Independently compared raw CSS old/new lines and tracked CSS against origin/main: exactly one added .inline{display:inline}, otherwise byte-identical; new test source has the inline identifier, consistent with Tailwind source detection. This is not a stylesheet rewrite. Independently byte-compared src/security/headers.ts to merged Slugkit #296 commit fdfd33ea485b8800c4aee86751d0d985d0bb46e8 at template/site/src/security/headers.ts: identical. Middleware precedes setup/CSRF/routes; AsyncLocalStorage isolates trusted request nonces and HTML no-store prevents nonce reuse via caches. Trusted public/settings/setup/About hooks and scoped Swagger renderer reviewed. No arbitrary HTML rewriting or new executable-origin allowance. Changed-path inventory contains no dependency/lockfile/Playwright-config/CI-release-workflow/release-skill changes. No API/federation/CSRF behavioral changes. Existing setup-gate liveness test adaptation avoids unrelated upstream behavior adoption. ## Evidence reused, not rerun Read existing /tmp/evc-headers-{build,lint,tests,ci-tests,browser,image-build,image-check,homelab-tests,homelab-dry-run}.log summaries: build/lint, 468 full tests, 392 CI-safe tests, 40 local browser checks, local image build/0.3.13 validation, 47 offline homelab tests and schema-client dry-run. Task/PR evidence reports 31 header/config cases, full Kustomize/whitespace and isolated fake mail/media/virtual authenticator. Parent resolved website CI #73 success at this exact head; reused that result without new CI/network checks. Homelab has no applicable workflow, not a green CI claim. No tests/builds/browser/containers/production operations were run in this review. Local image evidence does not establish published/deployed headers. ## Original acceptance criteria (all six) 1. **partial** — Representative deployed HTML, authentication/settings, API, media, feed and federation responses include intended headers. Global middleware and local MIME/status/header tests plus the existing actor integration assertion demonstrate implementation. Actual deployed response evidence is pending separately approved rollout; current production remains 0.3.12. 2. **met** — CSP blocks unapproved executable/frame/resource sources while applicable browser features continue working. Nonce-only scripts, denied attributes/frames/objects and same-origin connections are covered by deterministic tests and existing local browser evidence for color mode/search, previews, virtual passkeys, real Swagger CDN/OpenAPI/Try it out and negative CSP/framing cases. API/federation/CSRF contracts remain intact. 3. **partial** — Local HTTP emits no HSTS; production transport matches verified HTTPS configuration. Defaults/non-production/forwarded-header tests demonstrate no inferred HSTS. Paired config prepares exactly max-age=300 for explicit production HTTPS origin, without subdomains/preload. Previously recorded TLS/proxy baseline supports this opt-in; actual deployed HSTS remains pending approval. 4. **met** — Site/proxy policies are consistent and customizations preserved. App owns headers; existing verified Traefik TLS/canonical redirects have no competing security-header middleware. About/Fediverse trusted script is nonced; branding/forms/CSRF/media/federation routing remain unchanged. Proxy-only redirects are explicitly outside application header coverage. 5. **partial** — Local verification evidence and post-deployment checks recorded. Existing local logs and task/PR evidence cover implementation; post-deployment release/image/header observations are deliberately deferred, not supplied or inferred from local success. 6. **met** — Site exceptions, TLS/proxy assumptions, deployment and rollback documented. Website rollout/security docs and companion runbook specify docs-only Swagger major-5 style path, nonced CDN script/initializer, disabled remote validator, HTTPS/data/blob image/media exceptions, explicit TLS assumptions, paired approvals/restarts and GitOps-only rollback preserving 0.3.12 CSRF/data/secrets/TLS. Counts: criteria_total=6; criteria_met=3; criteria_partial=3; criteria_missing=0. Here missing counts not-evident criteria; partial criteria are explicitly not fully met. ## Decision and approval boundary **approved**, for implementation/configuration review only. No not-evident criterion, missing logic test, correctness issue or policy violation found. The three partial criteria have substantive repository/local evidence; their outstanding production observations belong to the separately approved deployment phase, not an implementation defect. This is not task completion or a claim of public headers. Blocking issues: **0**. Warnings: **0**. Deferred approval-gated observations are recorded as partial criteria, not invented remediation requirements. Require explicit human merge approval for each PR; homelab main auto-applies and may restart production. Publication/deployment/HSTS activation and task closure require separate approval. Proposed 0.3.13 remains unpublished; neither PR was merged. Later production verification is limited to read-only release/image/header inspection. No production workflow/browser/auth tests, new backups, secrets or dependency remediation are prerequisites for this header-only scope.
erik merged commit 2d42718b77 into main 2026-10-05 16:50:56 -05:00
erik deleted branch task-dae6192b-security-headers 2026-10-05 16:50:56 -05:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
erik/erikvancraddock.com!20
No description provided.