Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ WORKDIR /app

# Install runtime system dependencies (ffmpeg and nodejs v22)
# gnupg is required for the Nodesource setup script
RUN apt-get update && apt-get install -y --no-install-recommends \
# `apt-get upgrade` applies Debian security updates the pinned base layer
# predates (e.g. zlib1g 1:1.3.dfsg+really1.3.1-1+deb13u1, DSA-6613-1).
# Refs #2396: fixable OS findings must not ride in from a stale base layer.
RUN apt-get update && apt-get upgrade -y --no-install-recommends \
&& apt-get install -y --no-install-recommends \
ffmpeg \
curl \
gnupg \
Expand All @@ -72,6 +76,13 @@ RUN rm -rf /usr/local/lib/python3.11/site-packages/*
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin

# pip is an install-time tool. Its wheel ships pip/_vendor/bom.cdx.json, which
# declares the vendored pkg_resources as setuptools 70.3.0, so image scanners
# report CVE-2025-47273 against it even on the newest pip (26.3). The served
# app (uvicorn) never invokes pip, so drop it from the runtime image.
# Refs #2396.
RUN python -m pip uninstall --yes pip

# Copy installed Node.js packages from builder
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/apps/web/node_modules ./apps/web/node_modules
Expand Down
21 changes: 21 additions & 0 deletions tests/unit/test_merge_policy_security_scan_wording.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,27 @@ def test_image_build_constrains_python_and_runtime_npm(self):
self.assertIn("npm install --global npm@12.2.2", dockerfile)
self.assertIn("rm -rf /usr/local/lib/python3.11/site-packages/*", dockerfile)

def test_runtime_stage_applies_debian_security_updates(self):
root = Path(__file__).resolve().parents[2]
dockerfile = (root / "Dockerfile").read_text()
runtime = dockerfile.split("AS runtime", 1)[1]
update = runtime.index("apt-get update")
upgrade = runtime.index("apt-get upgrade -y --no-install-recommends")
install = runtime.index("apt-get install -y --no-install-recommends")
self.assertLess(update, upgrade)
self.assertLess(upgrade, install)
self.assertNotIn("dist-upgrade", runtime)

def test_runtime_stage_drops_pip_after_copying_builder_env(self):
root = Path(__file__).resolve().parents[2]
dockerfile = (root / "Dockerfile").read_text()
runtime = dockerfile.split("AS runtime", 1)[1]
copy_bin = runtime.index("COPY --from=builder /usr/local/bin /usr/local/bin")
uninstall = runtime.index("RUN python -m pip uninstall --yes pip")
self.assertLess(copy_bin, uninstall)
self.assertLess(uninstall, runtime.index("USER appuser"))
self.assertNotIn("pip install", runtime)


if __name__ == "__main__":
unittest.main()
Loading