Pin the floating node:22-bookworm-slim tag to its index digest. The re-resolve
of this unpinned docker.io tag every build was the recurring CI 'hang'. Paired
with the bastion runner now pulling through the zot mirror, the base is fetched
once and cached. (nginx runtime stage was already digest-pinned.)
All JS moved to external /site.js → script-src 'self' with no inline JS,
hashes or eval. Full header set via nginx (CSP, nosniff, frame-deny,
referrer, permissions, COOP/CORP); HSTS stays at the CF edge. Shared
headers include avoids the location add_header reset footgun. Build-time
secret/inline-script/third-party scan gate. SECURITY.md documents posture.