Base images - api, llm, docs(extract), notebooks(wheel): uv:python3.13-bookworm-slim -> uv:0.13.2-python3.13-trixie-slim. Debian 12 left regular security support in June 2026; a pinned uv tag makes base changes a reviewed diff Renovate can bump. notebooks copies /uv from the same tag instead of uv:latest. - api, llm: `uv sync --locked` — a stale lock now fails the build instead of silently re-resolving to packages pkg-supply-chain never scanned. - api, llm: uninstall the base image's system pip. Nothing runs it (uv owns the venv), and its vendored certifi/urllib3/msgpack/setuptools were the image's only language-level findings. - notebooks: the workspace resolves at build time with no committed lock, so it gets the same 7-day cooldown via ENV UV_EXCLUDE_NEWER (ENV, not a prefix — the recorded span must match at `uv run` time). - docs: pnpm 10.12.1 -> 10.34.7 to match packageManager. trivy HIGH/CRITICAL, deployed image -> this build: api 11 crit / 94 high -> 0 / 48 llm 9 / 129 -> 1 / 70 docs 0 / 38 -> 0 / 0 mc 2 / 52 -> 0 / 0 What's left is Debian `affected` with no fix released (libxml2 is the llm critical); the weekly Harden --pull rebuild picks fixes up as they land. mc sidecar MinIO archived the open-source client: quay.io/minio/mc answers 401, dl.min.io 410 Gone, and there are no more security fixes. The service keeps its name but ships rustfs/rc v0.1.36 on alpine:3.24 — same alias grammar (RC_HOST_local=http://key:secret@rustfs:9000), same admin verbs (`docker exec mc rc admin policy create local/ <name> <file>`), same hardening (uid 10002, read-only root, no caps). Verified against the live RustFS: `rc ls local/` lists all six buckets, `rc admin user list` reaches the admin API. Config dir moves to a tmpfs at /home/mc/.config/rc. Refs #1365
50 lines
2.0 KiB
Docker
50 lines
2.0 KiB
Docker
# syntax=docker/dockerfile:1
|
|
FROM ghcr.io/astral-sh/uv:0.13.2-python3.13-trixie-slim
|
|
|
|
WORKDIR /app
|
|
|
|
# Local package registry (Gitea) — set via --build-arg to pull from mirror
|
|
ARG PYPI_INDEX_URL=""
|
|
|
|
# Patch base image CVEs + install curl for healthcheck.
|
|
# (Python cold-start on this image is 10-13s — too slow for the 5s
|
|
# healthcheck timeout, so Docker marks the container unhealthy even
|
|
# though /health responds in milliseconds.)
|
|
RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/*
|
|
# uv manages the venv; the base image's system pip is never used, and its
|
|
# vendored certifi/urllib3/msgpack/setuptools copies lag and get flagged.
|
|
RUN python3 -m pip uninstall -y -q pip
|
|
|
|
# Copy project files for install
|
|
COPY pyproject.toml uv.lock README.md ./
|
|
COPY src/ src/
|
|
|
|
# Install the package (no dev deps). The server needs the cli extra
|
|
# bundle (aco + api + bib + mail): uvicorn/fastapi/pyjwt live in the
|
|
# api extra, and /health imports aco.pipe + bib.store + duckdb — a
|
|
# bare `uv sync --no-dev` installs none of them (base deps only),
|
|
# which shipped an image that crash-looped on `Failed to spawn:
|
|
# uvicorn`.
|
|
ENV UV_PYTHON_PREFERENCE=only-system \
|
|
UV_LINK_MODE=copy \
|
|
UV_PROJECT_ENVIRONMENT=.venv \
|
|
UV_INDEX_URL=${PYPI_INDEX_URL}
|
|
# --locked: a stale uv.lock fails the build instead of silently re-resolving
|
|
# to packages nobody scanned (pkg-supply-chain scans uv.lock).
|
|
RUN uv sync --locked --no-dev --extra cli --extra perf && uv pip install -e .
|
|
|
|
# Config
|
|
COPY stack.toml ./
|
|
|
|
EXPOSE 8000
|
|
|
|
# --max-time bounds curl itself: docker's timeout only stops *waiting* —
|
|
# the probe process lives on, and a wedged server once accumulated ~1500
|
|
# hung healthcheck zombies this way.
|
|
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
|
|
CMD curl -sf --max-time 4 http://localhost:8000/health || exit 1
|
|
|
|
CMD ["uv", "run", "--no-sync", "uvicorn", "api.server:app", \
|
|
"--host", "0.0.0.0", "--port", "8000", \
|
|
"--workers", "1", "--log-level", "info"]
|