Add CSP + security.txt, PurgeCSS, and accessibility CI audit#6
Merged
Conversation
Implements three modernization recommendations. The three changes were developed in parallel by separate subagents against non-overlapping files; shared files (package.json, ci.yml, _config.yml, lockfile) were integrated here. Security headers + security.txt (rec #5): - Add a strict Content-Security-Policy and Referrer-Policy via <meta> tags in head.html (GitHub Pages cannot set HTTP headers). Policy is default-src 'self' with same-origin CSS/img/font, object-src 'none', frame-ancestors 'none'. style-src keeps 'unsafe-inline' because several Webflow-exported pages use inline style= attributes; a CSP that breaks styling is worse than none. X-Content-Type-Options / X-Frame-Options are intentionally NOT emitted as meta tags (header-only directives) — documented inline. - Add /.well-known/security.txt (RFC 9116). Requires the .well-known dir in the _config.yml include list, since Jekyll excludes dot-dirs by default (verified against Jekyll 4.4.1 EntryFilter source). PurgeCSS (rec #1): - Add purgecss.config.js + scripts/purge-css.js and a "Purge unused CSS" CI step that runs after the Jekyll build and rewrites only the CSS in _site/ (source assets/css/ is untouched). Conservative safelist covers Webflow runtime/state classes and the checkbox-toggled mobile nav. Fixture test showed the 127 KB inog-website.webflow.css dropping sharply; real per-page reduction will be validated by the first CI run. Accessibility audit (rec #4): - Add .pa11yci.json (WCAG2AA, axe + htmlcs runners) and a test-a11y script that serves _site via http-server and runs pa11y-ci over all 8 pages. - The CI step is NON-BLOCKING (continue-on-error) for now: a real run against the built site showed 0/8 pages passing, with pre-existing errors including missing <title>/<html lang> on some Webflow-exported pages, an image-only link missing alt text, and untested iframes. Gating on these would make CI red on merge. The check reports the debt on every PR; remove continue-on-error once the baseline is fixed in a follow-up. Verification: prettier, YAML, JSON, and JS-config parsing all pass locally. The Jekyll build, PurgeCSS, and pa11y runs were exercised against real built output during development; a full local build is not possible in the commit environment (offline), so the build itself is confirmed by CI on this PR. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements three modernization recommendations (#5 security headers, #1 PurgeCSS, #4 a11y audit). Developed in parallel by three Sonnet subagents against non-overlapping files; shared files (
package.json,ci.yml,_config.yml, lockfile) integrated in the final commit.#5 — Security headers + security.txt
<meta>tags inhead.html(GitHub Pages can't set HTTP headers). Policy:default-src 'self', same-origin img/style/font,object-src 'none',frame-ancestors 'none',base-uri 'self',form-action 'self'.style-srckeeps'unsafe-inline'— several Webflow-exported pages (projekte.html,offenerbrief-epa-2025.html) use inlinestyle=attributes; a CSP that breaks styling is worse than none. Documented inline.X-Content-Type-Options/X-Frame-Optionsare deliberately not emitted as meta tags (header-only directives) — noted in a comment; they'd need a header-capable front (e.g. Cloudflare)./.well-known/security.txt(RFC 9116), contactkontakt@inoeg.de. Added.well-knownto the_config.ymlinclude:list — Jekyll excludes dot-dirs by default (verified against Jekyll 4.4.1EntryFiltersource).#1 — PurgeCSS
purgecss.config.js+scripts/purge-css.js+ a "Purge unused CSS" CI step that runs afterjekyll buildand rewrites only_site/assets/css/(sourceassets/css/untouched, so every build starts from the original export).w-*,w--*,wf-*) and the checkbox-toggled mobile nav, reasoned per-entry in comments. Over-purging is silent breakage, so the safelist errs toward keeping.inog-website.webflow.cssis the main target. Please spot-check all pages render correctly after the first CI purge — real per-page reduction is validated by CI, not by the single-page dev fixture.#4 — Accessibility audit (pa11y-ci)
.pa11yci.json(WCAG2AA, axe + htmlcs runners) +test-a11yscript that serves_sitewithhttp-serverand runs pa11y-ci over all 8 pages (start-server-and-testfor a race-free server startup; Chromium--no-sandboxfor CI).continue-on-error: true). A real run against the built site showed 0/8 pages passing, with pre-existing errors:<html>element missing alangattribute<title>(on some Webflow-exported pages)alttext ("Links must have discernible text")continue-on-errorto make it a hard gate. Some (missing title/lang) may be real defects on the raw Webflow pages and warrant investigation.Verification
Prettier, YAML, JSON, and JS-config parsing all pass locally. The Jekyll build, PurgeCSS, and pa11y runs were exercised against real built output during development (subagents ran actual builds). A full build isn't runnable in the authoring env (offline), so the build itself is confirmed by CI on this PR.
🤖 Generated with Claude Code