Skip to content

Commit 51c8758

Browse files
ahsimbclaude
andauthored
Replaced the Docker image base with a distroless image (#296)
* #295: Replace Docker image base with distroless Switches the runtime stage to gcr.io/distroless/python3-debian13:nonroot, built from a python:3.13-slim-trixie venv. The final image no longer ships a shell, package manager, or pip, shrinking the OS-level CVE surface that recent Docker CVE-fix PRs had to chase. Also adds a Dependabot docker-ecosystem watch, since distroless removes the in-image apt-get upgrade patching path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * #295: Simplify Dockerfile comments Rewords the distroless-related comments in plainer language (removes "ABI/path compatibility", "shebangs", etc.). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * #295: Remove venv's bundled pip from the distroless image `python -m venv` installs its own copy of pip, which vendors its own copies of msgpack and setuptools carrying known CVEs (GHSA-6v7p-g79w-8964, CVE-2025-47273) -- the same ones the previous slim-based image's `pip uninstall -y pip` step addressed. That step didn't carry over to the distroless rewrite since distroless itself never has pip, but the venv copied into it still did. Confirmed via a Trivy scan on a real build (VM with Docker): before this fix the image carried 2 HIGH findings (msgpack, setuptools); after, 0. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * #295 Shortened changelog record * #295: Add cooldown to Dependabot docker config zizmor's dependabot-cooldown audit (run in CI's Audit Workflows job) flags Dependabot updates without an explicit cooldown as insufficiently conservative. Set a 7-day default cooldown for the docker ecosystem entry added in 8ed26ba. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 4e329bf commit 51c8758

4 files changed

Lines changed: 38 additions & 20 deletions

File tree

‎.github/dependabot.yml‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "docker"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"
7+
cooldown:
8+
default-days: 7

‎Dockerfile‎

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,35 @@
1-
# Use Python base image
2-
FROM python:3.13-slim AS build
1+
# Build a virtual environment using the Debian version that matches the
2+
# distroless image below, so the venv still works once copied over.
3+
# See https://github.com/GoogleContainerTools/distroless/blob/main/python3/README.md
4+
FROM python:3.13-slim-trixie AS build
5+
6+
# The distroless image's Python is at /usr/bin/python, but this builder
7+
# image's Python is at /usr/local/bin/python. Add a matching /usr/bin/python
8+
# link here so the virtual environment we create points to a path that will
9+
# also exist in the final image.
10+
RUN pip install poetry \
11+
&& ln -s /usr/local/bin/python /usr/bin/python \
12+
&& /usr/bin/python -m venv /venv
313

4-
# Install Poetry
5-
RUN pip install poetry
6-
7-
# Set working directory
814
WORKDIR /app
915

1016
# Copy project files
1117
COPY pyproject.toml poetry.lock README.rst ./
1218
COPY exasol/ ./exasol/
1319

14-
# Build and install the wheel
15-
RUN poetry build
16-
17-
FROM python:3.13-slim
18-
20+
# Build the wheel and install it, with its extras, into the venv. Then
21+
# remove pip itself: `python -m venv` installs its own copy of pip into
22+
# the venv, and pip vendors its own copies of other packages (e.g.
23+
# msgpack, setuptools) that can carry known vulnerabilities.
24+
RUN poetry build \
25+
&& WHEEL=$(ls dist/*.whl) \
26+
&& /venv/bin/pip install --disable-pip-version-check "${WHEEL}[dynamodb,redis,mongodb]" \
27+
&& /venv/bin/pip uninstall -y pip
28+
29+
# This distroless base image has no shell, no package manager, and no pip.
30+
FROM gcr.io/distroless/python3-debian13:nonroot
1931
WORKDIR /app
20-
COPY --from=build app/dist dist
21-
22-
RUN apt-get update && apt-get upgrade -y && rm -rf /var/lib/apt/lists/*
23-
24-
RUN WHEEL=$(ls dist/*.whl) && pip install "${WHEEL}[dynamodb,redis,mongodb]" \
25-
&& pip uninstall -y pip
26-
32+
COPY --from=build --chown=nonroot:nonroot /venv /venv
2733

2834
# Set entrypoint
29-
ENTRYPOINT ["exasol-mcp-server-http"]
35+
ENTRYPOINT ["/venv/bin/exasol-mcp-server-http"]

‎doc/changes/unreleased.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
# Unreleased
22

33
## Summary
4+
5+
## Security
6+
7+
* #295: Replaced the Docker image's base with `gcr.io/distroless/python3-debian13`.

‎doc/user_guide/deployment.rst‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ Now create and run the Docker container.
5959
-e EXA_AUTH_BASE_URL=my_mcp_server \
6060
-e EXA_MCP_SETTINGS=/app/settings.json \
6161
-v local_path_to_settings.json:/app/settings.json \
62-
exadockerci4/exasol-mcp-server:latest
62+
exasol/mcp-server:latest
6363
--port 4896
6464
6565
In this example, the server is configured to use the generic OAuth Proxy provider.

0 commit comments

Comments
 (0)