diff --git a/.trivyignore.yaml b/.trivyignore.yaml new file mode 100644 index 00000000..79dbc1c5 --- /dev/null +++ b/.trivyignore.yaml @@ -0,0 +1,15 @@ +# The CVE gate's allowlist (E32). The publish gate scans the built image and the committed tree with +# Trivy and fails on any HIGH or CRITICAL finding that has a fix available. A finding that cannot be +# fixed yet is let through ONLY by an entry here, and every entry carries both: +# statement — why it is acceptable for now (what is exposed, what is not) +# expired_at — the date it stops being accepted; after it, the gate fails again on its own +# A contract test (frontend/src/lib/gates.contract.test.ts) refuses an entry without either, and +# docs/gates.md lists them. +# +# Example: +# vulnerabilities: +# - id: CVE-2026-00000 +# statement: in libfoo's XML path, which nothing in the image calls; no fixed Debian build yet +# expired_at: 2026-12-31 +vulnerabilities: [] +secrets: [] diff --git a/Dockerfile b/Dockerfile index d6b362c5..c1c69b2a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -53,8 +53,11 @@ RUN adduser --disabled-password --gecos "" appuser \ # Harmless on hosts with no /dev/dri (the driver just goes unused). Deno: the JavaScript runtime yt-dlp # uses to solve YouTube's "n" signature challenge for the web player clients (required alongside the PO # token, else only storyboards are offered). yt-dlp auto-detects deno on PATH. +# `apt-get upgrade` (E32): the base image is a snapshot, and the Debian security fixes released since it +# was cut are only in the archive — the first Trivy scan found one (pcre2) fixed upstream but not in it. ARG DENO_VERSION=v2.9.1 RUN apt-get update \ + && apt-get upgrade -y --no-install-recommends \ && apt-get install -y --no-install-recommends ffmpeg intel-media-va-driver unzip curl ca-certificates \ && curl -fsSL "https://github.com/denoland/deno/releases/download/${DENO_VERSION}/deno-x86_64-unknown-linux-gnu.zip" -o /tmp/deno.zip \ && unzip -o /tmp/deno.zip -d /usr/local/bin \ @@ -78,9 +81,12 @@ RUN printf 'Types: deb\nURIs: http://deb.debian.org/debian\nSuites: bookworm\nCo # Install from the PINNED lock (requirements.lock, generated from requirements.txt) so the image is # byte-reproducible and the exact versions are the ones pip-audit scanned in CI — not whatever floats # up from the floor ranges on build day. Regenerate the lock when requirements.txt changes (see its header). +# pip itself is removed once it has installed the lock (E32): nothing runs it at runtime, and it carries +# its own VENDORED copies of urllib3, msgpack and setuptools, which Trivy reports as the image's own — +# an attack surface and a CVE stream for a tool the running app never calls. COPY backend/requirements.lock . RUN --mount=type=cache,target=/root/.cache/pip \ - pip install --upgrade pip && pip install -r requirements.lock + pip install --upgrade pip && pip install -r requirements.lock && pip uninstall -y pip COPY --chown=appuser backend/ . # Read at runtime by config.py as the app_version (a committed single source of truth).