Runner: self-hosted arm64. Deploy target: amd64 (Hetzner). Cross-arch is
safe because Astro output is plain static HTML/CSS/JS — nothing in the
bundle is arch-specific.
Changes:
- runs-on: ubuntu-latest (most portable act_runner label — override per your
runner's registered labels if needed).
- Install Chromium from apt at workflow time (Google Chrome has no Linux/arm64
stable build; Chromium does). Handles both chromium and chromium-browser
package names, sudo-less runners, and idempotently skips if already present.
- Export CHROME_PATH so LHCI picks the right binary.
- Add chromeFlags to lighthouserc.cjs: --no-sandbox --headless=new
--disable-gpu --disable-dev-shm-usage (required in containerized/root
Chromium on CI runners).
- timeout-minutes on both jobs.
- Defense-in-depth install of rsync + openssh in deploy job if the runner
image doesn't ship them.
- Null-guard SFTP_KEY and SFTP_KNOWN_HOSTS secrets.
- Switch echo to printf for deterministic newline handling when writing key
material to ~/.ssh files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Remove Sitemap line from robots.txt (no @astrojs/sitemap installed; was
pointing to a 404 that would trip Google Search Console).
- Align Permissions-Policy across all three enforcement layers (middleware,
.htaccess, Cloudflare Transform Rule in OPERATOR-CHECKLIST) by dropping the
stray fullscreen=(self) from the middleware.
- Bump Lighthouse CI numberOfRuns from 1 to 3 to dampen CI-runner noise.
- Add CI guard that fails the build if any <TBD:...> marker survives into
dist/ — prevents a legally incomplete imprint from shipping by accident.
- Add SFTP_* secret null-guard before the rsync --delete step so a missing
secret fails loudly instead of targeting the SSH user's home root.
- Document the set:html compile-time-constant invariant in DualValueProps.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- .htmlvalidate.json with relaxed rules for design-system inline styles
- linkinator.config.json skipping mail, external auth/platform origins
- Fix lint:html npm script quoting for Windows-shell compatibility
- Switch astro build.format to 'directory' so /pricing resolves without MultiViews
- trailingSlash: 'ignore' lets both /pricing and /pricing/ work naturally
- Add aria-label to both <nav> landmarks (Primary, Footer) to satisfy html-validate
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Exports buildSecurityHeaders() (pure, testable) and wires it into the
Astro onRequest middleware. Adds astro:middleware alias in vitest config
so the unit tests run outside Astro's build context. 14 tests pass (7
existing + 7 new).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Captures brainstormed architecture: Astro 5 static site on Hetzner
Webhosting L, Cloudflare profile B (WAF, rate limit, HSTS, security
headers), redirect-to-Logto auth at auth.cameleer.io. Four pages (home,
pricing, imprint, privacy), English-only with i18n-ready scaffold, no
analytics in v1. Homepage uses dual-register 6-section weave serving
both manager and engineer audiences at every scroll depth.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>