feat: per-file Cache-Control, navigation-scoped SPA fallback, nosniff, non-root image; v1.7.0

- Cache-Control per file: no-cache for index.html + service workers, immutable 1y for
  content-hashed assets, 1h for the rest (Vite/CRA/Angular). Closes the stale-release
  trap at the HTTP layer that the v1.6.0 image fix closed at the container layer.
- SPA fallback scoped to navigation: a missing asset (path w/ extension) or a non-HTML
  Accept now returns 404 instead of index.html (no more HTML-as-JS 'Unexpected token <').
- X-Content-Type-Options: nosniff on every response.
- Image runs as a non-root 'spa' user.
- README: caching table, fallback contract, and the Angular dist/<project>/browser/ note.
This commit is contained in:
2026-08-18 17:55:56 -06:00
parent bbc588d933
commit b73b9ee022
9 changed files with 343 additions and 18 deletions
+30
View File
@@ -6,6 +6,36 @@ This module adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html
---
## [1.7.0] — 2026-08-14
Minor — HTTP behaviour: caching, a strict SPA fallback, security headers, and a non-root image.
### Added
- **Per-file `Cache-Control`.** `index.html` and service-worker files (`ngsw.json`, `ngsw-worker.js`,
`sw.js`, `service-worker.js`, `safety-worker.js`, `workbox-*.js`) are `no-cache`; content-hashed
assets are `public, max-age=31536000, immutable`; everything else is `public, max-age=3600`.
Correct for Vite, CRA and Angular output. Closes, at the HTTP layer, the same stale-release trap
the v1.6.0 image fix closed at the container layer.
- **`X-Content-Type-Options: nosniff`** on every response.
- **Non-root container.** The image adds an unprivileged `spa` user and runs as it — a static binary
serving read-only files on `:8080` needs no privilege.
### Changed
- **The `index.html` fallback is now scoped to navigation requests.** A path that does not resolve to
a file is served `index.html` only when it has no file extension and the client accepts HTML
(`text/html` / `*/*`). A missing asset (`/main.js`) or a typed non-HTML client now gets **404**
instead of `index.html`, so a broken deploy fails loudly rather than shipping the SPA shell as
JavaScript (`Unexpected token '<'`).
- Bumped einherjar dependencies to v1.7.0.
### Docs
- README documents the caching table and the navigation-scoped fallback, and notes that **Angular**
must `COPY dist/<project>/browser/` (not `dist/`) — the application builder nests `index.html`
under `browser/`.
## [1.6.0] — 2026-08-14
Minor — coordinated framework release (lockstep versioning). No changes to this module's own API.