The backend half of the sweep RD-18 did for the front end. git blame
holds the provenance and stays correct when the code moves; the
comment names a closed ticket and tells the reader nothing the
sentence around it does not.
public/letter.css and LetterHtml.golden.html change together, because
the renderer inlines the CSS and the golden file snapshots the
result.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The pushed WP-30 item-5 Dockerfile predated the semgrep triage's local run —
CI's now-blocking semgrep gate caught what local verification couldn't:
dockerfile.security.missing-user-entrypoint (no USER, container runs as root).
mcr.microsoft.com/dotnet/aspnet:10.0 ships a pre-created non-root user for
exactly this ($APP_UID, uid/gid 1654) — switched to it, with --chown on both
COPY layers so the app can still create/write bigregister.db (WP-22, a
relative-path SQLite connection string resolved against the container's /app
cwd) as that user.
Verified for real: rebuilt, confirmed `whoami` is `app` inside the container,
ran it and curled a live GET /api/v1/brief/preview (200), confirmed
bigregister.db was created and is actually owned by app:app. Full semgrep
re-run (this file didn't exist during the original triage) is now 0 findings.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Multi-stage backend/Dockerfile (sdk build -> aspnet:10.0 runtime, ~312MB) +
docker-compose.prod.yml, additive only — not wired into CI or the existing
dev docker-compose.yml (which keeps the SDK image for dotnet run hot-reload).
New .dockerignore keeps the build context lean (node_modules alone is
~750MB) since the Dockerfile COPYs from the repo root to pick up
public/letter.css (WP-25's FE<->BE letter contract) as a sibling of backend/.
Verified for real: built the image, ran it, and curled a live
GET /api/v1/brief/preview against the running container — got back the
actual rendered letter HTML with letter.css inlined, confirming the
walk-up-from-BaseDirectory lookup resolves inside this image layout too.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>