chore: phase 6 hardening — CSP/HSTS, access log, docker, backup, CI
Ships the cross-cutting hardening set: - SecurityHeadersMiddleware: per-request nonce-based CSP, HSTS (production only), Referrer-Policy, Permissions-Policy, X-Content-Type-Options, frame-ancestors 'none', form-action 'self'. - AccessLogMiddleware: one http_request INFO event per request (method/path/status/duration_ms/ip/ua). Skips /healthz, redacts /admin/auth/consume/<token> paths, logs 500 + re-raises on downstream exceptions. - Public base.html inline nav-toggle script gets a nonce so it passes strict CSP without relaxing to 'unsafe-inline'. - Dockerfile: non-root app user (uid/gid 10001) + stdlib-only HEALTHCHECK against /healthz. - scripts/backup.sh: sqlite3 .backup + tar data/media with 14-entry retention; host-side cron install documented. - .gitea/workflows/build-image.yml: on push to master / workflow_dispatch, builds and publishes git.sneakygeek.net/ptarrant/chicken_babies_site:latest + sha-<short>, with GIT_COMMIT_SHA threaded as a build-arg so /healthz keeps reporting the right commit in deployed images. - 8 new tests (security headers + access log). Pre-existing dev failures (logo asset rename + RESEND env pollution) remain unchanged; verified not Phase 6 regressions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
17
Dockerfile
17
Dockerfile
@@ -77,8 +77,25 @@ COPY app /app/app
|
||||
ARG GIT_COMMIT_SHA=unknown
|
||||
ENV GIT_COMMIT_SHA=${GIT_COMMIT_SHA}
|
||||
|
||||
# Phase 6 hardening: create a dedicated non-root user with a stable
|
||||
# UID/GID so host bind mounts (data/, media/) have predictable
|
||||
# ownership. We pin 10001 because values < 1000 collide with Debian
|
||||
# system accounts on some host distros.
|
||||
RUN groupadd -g 10001 app \
|
||||
&& useradd -m -u 10001 -g app app \
|
||||
&& chown -R app:app /app /opt/venv
|
||||
|
||||
USER app
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
# Phase 6 healthcheck: hits /healthz over the loopback with stdlib
|
||||
# urllib so we don't have to install curl/wget in the runtime image.
|
||||
# Intervals tuned for a small VM: probe every 30s, give a fresh
|
||||
# container 10s to finish startup before the first probe counts.
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
|
||||
CMD python -c "import urllib.request,sys; urllib.request.urlopen('http://127.0.0.1:8000/healthz', timeout=2); sys.exit(0)" || exit 1
|
||||
|
||||
# Run Uvicorn directly. --proxy-headers + --forwarded-allow-ips make
|
||||
# Starlette's ProxyHeadersMiddleware trust X-Forwarded-* only from the
|
||||
# listed peer IPs (Caddy on the host). No --reload: this is a prod-shape
|
||||
|
||||
Reference in New Issue
Block a user