sangtran.dev: a strict-CSP static site
AstroTypeScriptCloudflare WorkersVitestPlaywrightaxe-coreLighthouse CIGitHub ActionsCodeQL
Problem: a personal site is easy to ship once and let drift. Security headers get loosened to make one feature work, accessibility regresses unnoticed, and dependencies age. For a security engineer’s site, the page itself is part of the portfolio.
Approach: treat each rule as something the build must prove, not something I remember to do.
- Strict CSP. The site is built with Astro under a
default-src 'self'policy with nounsafe-inlineorunsafe-eval. Inline scripts are allowed only by SHA-256 hash, and the response headers add HSTS,frame-ancestors 'none', a locked-downPermissions-Policy, and COOP and CORP. - Build-output tests. A test suite runs against the built
dist/folder and fails the build if any page has an inlinestyleattribute or event handler, an unhashed inline script, a third-party resource, or a broken internal link. It also checks thatsecurity.txtexists and expires within a year. - Accessibility and quality gates. axe-core audits every page, and the interactive pages are audited again in each of their states at desktop and phone sizes. Lighthouse must score 100 for accessibility.
- End-to-end tests in real Chrome. They cover keyboard use, focus, touch input and phone layouts. I confirm that a test can fail by removing a fix on purpose and checking that the right tests go red.
- Supply chain. CI actions are pinned by commit SHA, Dependabot proposes updates, CodeQL and secret scanning run on every change, and
npm auditis part of the pipeline. Tools that would add audit findings to the lockfile, like Lighthouse CI, run through a pinnednpxcall instead. - Safe rendering. Content is always rendered as text, never parsed as HTML, and tests scan the source for
innerHTML,evaland network calls in the interactive code.
Outcome: as of October 2026, the repository has unit, build-output and end-to-end test suites, a clean npm audit, and automated accessibility and Lighthouse checks that gate every change. The checks have caught real bugs, including a keyboard-focus defect and a phone layout overflow, which I describe in a write-up on the blog.
What it does not do yet: there is no CSP violation reporting, and the end-to-end tests run only in Chrome with emulated phones, not on real devices or Safari.