From 9d3ce1d2c49ebd757b0f02e92c3a5b276733a96b Mon Sep 17 00:00:00 2001 From: hermes Date: Mon, 9 Nov 2026 11:23:22 +1000 Subject: [PATCH 1/2] fix: build the image on Python 3.14 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The image build failed on master: ERROR: Ignored the following versions that require a different python version: 4.19.0 Requires-Python >=3.11 ERROR: Could not find a version that satisfies the requirement pymongo==4.19.0 The base image was `python:3.10` but the pinned pymongo 4.19 needs Python >= 3.11. The image is now `python:3.14-slim` — the current stable release, so it is not carrying the CVEs fixed in 3.11, 3.12 and 3.13. All the runtime dependencies ship a cp314 wheel (pymongo included), so no compiler toolchain is needed. The old apt-get line installed libsasl2-dev, python-dev-is-python3, libldap2-dev and libssl-dev for packages that are no longer in the dependency list, so it is gone and the image is smaller. The build now asserts the interpreter version, so a base image change that breaks the pinned requirements fails the build with a clear message rather than a pip resolution error. --- base.Dockerfile | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/base.Dockerfile b/base.Dockerfile index 3a367e1..87470f2 100644 --- a/base.Dockerfile +++ b/base.Dockerfile @@ -1,11 +1,22 @@ -FROM python:3.10 AS beer_base_image +FROM python:3.14-slim AS beer_base_image WORKDIR /beer_data COPY requirements.txt . -RUN apt-get update -y && apt-get upgrade -y && apt-get install -y libsasl2-dev python-dev-is-python3 libldap2-dev libssl-dev +# The runtime dependencies (flask, flask-wtf, waitress, pymongo, requests) all +# ship as wheels for 3.14, so no compiler toolchain is needed. The old image +# installed libsasl2-dev, python-dev-is-python3, libldap2-dev and libssl-dev +# for packages that are no longer in the dependency list. +# +# The Python version matters: +# - pymongo 4.19 requires Python >= 3.11, so the base image could not stay +# on 3.10 once the requirements were pinned. +# - 3.14 is the current stable release, so the image is not carrying the +# CVEs fixed in 3.11, 3.12 and 3.13. +RUN pip install --upgrade pip --no-cache-dir -RUN pip install --upgrade pip +RUN pip --default-timeout=1000 install --no-cache-dir -r requirements.txt -RUN pip --default-timeout=1000 install -r requirements.txt +# Fail the build if the interpreter is not the one the image claims. +RUN python -c "import sys; assert sys.version_info[:2] == (3, 14), sys.version" -- 2.39.5 From c0c6b4c1fc999a158cafd4104673c6c61e8383ec Mon Sep 17 00:00:00 2001 From: hermes Date: Mon, 9 Nov 2026 11:25:58 +1000 Subject: [PATCH 2/2] fix: pin the Python patch version and run the app as a non-root user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two follow-ups to the review of the base image change. 1. Pin the patch version: `python:3.14-slim` is a floating tag, so a rebuild could silently pick up a different base image. It is now `python:3.14.10-slim`, so a rebuild is reproducible. 2. Run the app as an unprivileged user. The app only reads its own source and talks to Mongo over the network — it writes no files — so it does not need to be root. A `beer` system user is created and the image ends with `USER beer`. --- base.Dockerfile | 10 +++++++--- flask.Dockerfile | 8 ++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/base.Dockerfile b/base.Dockerfile index 87470f2..ca91d21 100644 --- a/base.Dockerfile +++ b/base.Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.14-slim AS beer_base_image +FROM python:3.14.10-slim AS beer_base_image WORKDIR /beer_data @@ -12,8 +12,12 @@ COPY requirements.txt . # The Python version matters: # - pymongo 4.19 requires Python >= 3.11, so the base image could not stay # on 3.10 once the requirements were pinned. -# - 3.14 is the current stable release, so the image is not carrying the -# CVEs fixed in 3.11, 3.12 and 3.13. +# - 3.14 is a stable release (first released 2025-10-07, in its bugfix +# phase until 2030-10), so the image is not carrying the CVEs fixed in +# 3.11, 3.12 and 3.13. +# - The patch version is pinned rather than the floating `3.14-slim` tag so +# a rebuild is reproducible and does not silently pick up a base image +# change. RUN pip install --upgrade pip --no-cache-dir RUN pip --default-timeout=1000 install --no-cache-dir -r requirements.txt diff --git a/flask.Dockerfile b/flask.Dockerfile index 2cbd69c..e242e30 100644 --- a/flask.Dockerfile +++ b/flask.Dockerfile @@ -8,6 +8,12 @@ ADD src /beer_data/src # (``import brewing``), so that directory is the working directory. WORKDIR /beer_data/src/flask +# Run as an unprivileged user. The app only needs to read its own source +# and talk to Mongo over the network — it writes no files — so it does not +# need to be root. +RUN useradd --system --create-home --home-dir /home/beer --shell /usr/sbin/nologin beer \ + && chown -R beer:beer /beer_data + # The app is served by waitress, not the Flask development server. # FLASK_DEBUG stays OFF: the old entrypoint ran the Werkzeug debugger in # production, which exposes an interactive console on any unhandled error. @@ -21,6 +27,8 @@ ENV PORT=5000 # session-signing key. # ENV SECRET_KEY=... +USER beer + EXPOSE 5000 ENTRYPOINT ["python", "-m", "waitress", "--listen=0.0.0.0:5000", "--call", "beer_data:create_app"] -- 2.39.5