From dd177b90f3662cb25bfe591336a96f8b0166e600 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jul 2026 09:25:38 +0000 Subject: [PATCH 1/4] Bump python from 3.12-slim to 3.14-slim in /Controller Bumps python from 3.12-slim to 3.14-slim. --- updated-dependencies: - dependency-name: python dependency-version: 3.14-slim dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- Controller/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Controller/Dockerfile b/Controller/Dockerfile index 4134d23..ef458dd 100644 --- a/Controller/Dockerfile +++ b/Controller/Dockerfile @@ -5,7 +5,7 @@ # (adds a BusyBox shell). Never push the debug variant. # --- builder --------------------------------------------------------------- -FROM python:3.12-slim@sha256:423ed6ab25b1921a477529254bfeeabf5855151dc2c3141699a1bfc852199fbf AS builder +FROM python:3.14-slim@sha256:b877e50bd90de10af8d82c57a022fc2e0dc731c5320d762a27986facfc3355c1 AS builder WORKDIR /app COPY requirements.txt ./requirements.txt RUN pip install --no-cache-dir -r requirements.txt From 7561d561c1be599e4c53ccbb64e7cb931862b9ab Mon Sep 17 00:00:00 2001 From: Robert van 't Hof Date: Wed, 16 Sep 2026 10:03:05 +0100 Subject: [PATCH 2/4] Fix Bandit annotation for deployment history pruning --- Controller/app/deploy_history.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Controller/app/deploy_history.py b/Controller/app/deploy_history.py index b21546c..9a024c7 100644 --- a/Controller/app/deploy_history.py +++ b/Controller/app/deploy_history.py @@ -105,7 +105,7 @@ def record(app_name: str, operation: str, record: AppRecord, status: str, def _prune(app_name: str) -> None: """Keep only the newest _KEEP_PER_APP rows for this app.""" - # nosec B608 - _TABLE is a fixed constant and _KEEP_PER_APP an int literal; + # _TABLE comes from deployment configuration and _KEEP_PER_APP is an int literal; # app_name is parameterized (bound twice, once per subquery reference). sf.execute_sql( f""" @@ -117,7 +117,7 @@ def _prune(app_name: str) -> None: ORDER BY ts DESC, id DESC LIMIT {_KEEP_PER_APP} ) - """, + """, # nosec B608 (app_name, app_name), ) From 374dfcbf2fa0c9ee636d9be1c7a0fc626f704dc9 Mon Sep 17 00:00:00 2001 From: Robert van 't Hof Date: Wed, 16 Sep 2026 10:10:56 +0100 Subject: [PATCH 3/4] Refresh service runtime images for OpenSSL security fix --- Admin UI/Dockerfile | 2 +- Controller/Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Admin UI/Dockerfile b/Admin UI/Dockerfile index 4cb5f75..4918beb 100644 --- a/Admin UI/Dockerfile +++ b/Admin UI/Dockerfile @@ -42,7 +42,7 @@ RUN mkdir -p /opt/runtime-libs \ # GLIBC_2.38 symbols libpython3.12.so needs. # NOTE: no RUN is possible in this stage (no shell). Anything needing mkdir/ # chown at build time goes in the builder stage above. -FROM gcr.io/distroless/cc-debian13:nonroot@sha256:aded2458d026e046cb68199db0e5793e1028ffa143f7258f3c4278253e20add7 +FROM gcr.io/distroless/cc-debian13:nonroot@sha256:54df941ed0d06a1bd95ef5e0ce391fd8d9f94b64782dc9a60062727849ee3f97 # /usr/local carries the interpreter, stdlib C extensions (lib-dynload), # libpython3.12.so, and all pip-installed packages in one consistent copy. COPY --from=builder --chown=65532:65532 /usr/local /usr/local diff --git a/Controller/Dockerfile b/Controller/Dockerfile index 52beba0..18c63d2 100644 --- a/Controller/Dockerfile +++ b/Controller/Dockerfile @@ -41,7 +41,7 @@ RUN mkdir -p /opt/runtime-libs \ # 2.36 predates the GLIBC_2.38 symbols libpython3.12.so needs. # NOTE: no RUN is possible in this stage (no shell). Anything needing mkdir/ # chown at build time goes in the builder stage above. -FROM gcr.io/distroless/cc-debian13:nonroot@sha256:aded2458d026e046cb68199db0e5793e1028ffa143f7258f3c4278253e20add7 +FROM gcr.io/distroless/cc-debian13:nonroot@sha256:54df941ed0d06a1bd95ef5e0ce391fd8d9f94b64782dc9a60062727849ee3f97 # /usr/local carries the interpreter, stdlib C extensions (lib-dynload), # libpython3.12.so, and all pip-installed packages in one consistent copy. COPY --from=builder --chown=65532:65532 /usr/local /usr/local From 9118951b49db1801adc2e160dc046f47efae8b13 Mon Sep 17 00:00:00 2001 From: Robert van 't Hof Date: Wed, 16 Sep 2026 10:11:53 +0100 Subject: [PATCH 4/4] Validate Controller runtime on Python 3.14 --- .github/workflows/security-scan.yml | 12 ++++++++++++ .github/workflows/tests.yml | 10 ++++++---- Controller/Dockerfile | 8 ++++---- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml index d7241c3..750acd9 100644 --- a/.github/workflows/security-scan.yml +++ b/.github/workflows/security-scan.yml @@ -88,6 +88,18 @@ jobs: # Same platform flag as native-app/scripts/build-and-push.ps1; # --provenance only matters for the registry push, not a local scan. run: docker build --platform linux/amd64 -t "${{ matrix.image }}:scan" "${{ matrix.context }}" + - name: Check runtime imports + if: matrix.image != 'mendix-base' + env: + IMAGE: ${{ matrix.image }} + run: | + imports="import ssl, ctypes, bz2, lzma, sqlite3, uuid, dbm, readline; import snowflake.connector" + if [ "$IMAGE" = "mendix-deploy-controller" ]; then + imports="$imports; import fastapi, uvicorn, pydantic, yaml, psycopg" + else + imports="$imports; import streamlit, httpx" + fi + docker run --rm --entrypoint /usr/local/bin/python "$IMAGE:scan" -c "$imports" - name: Trivy scan (full report, SARIF) uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 with: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 31a0a07..a3e8e70 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -31,11 +31,13 @@ concurrency: jobs: pytest: - name: pytest (${{ matrix.service }}) + name: pytest (${{ matrix.service }}, Python ${{ matrix.python-version }}) runs-on: ubuntu-latest strategy: fail-fast: false matrix: + service: [Controller, Admin UI] + python-version: ['3.12', '3.14'] include: - service: Controller slug: controller @@ -56,8 +58,8 @@ jobs: - uses: actions/checkout@v7 - uses: actions/setup-python@v6 with: - # Matches the python:3.12-slim base of both service images. - python-version: '3.12' + # Cover both runtimes while the service images move to Python 3.14. + python-version: ${{ matrix.python-version }} cache: pip cache-dependency-path: | ${{ matrix.requirements }} @@ -77,5 +79,5 @@ jobs: if: always() uses: actions/upload-artifact@v7 with: - name: coverage-${{ matrix.slug }} + name: coverage-${{ matrix.slug }}-${{ matrix.python-version }} path: coverage-${{ matrix.slug }}.xml diff --git a/Controller/Dockerfile b/Controller/Dockerfile index fb36bab..1a36572 100644 --- a/Controller/Dockerfile +++ b/Controller/Dockerfile @@ -1,5 +1,5 @@ # Bases pinned to immutable digests for reproducible, scannable builds (NAAAPS). -# Refresh: docker pull python:3.12-slim && docker inspect --format '{{index .RepoDigests 0}}' python:3.12-slim +# Refresh: docker pull python:3.14-slim && docker inspect --format '{{index .RepoDigests 0}}' python:3.14-slim # Refresh: docker pull gcr.io/distroless/cc-debian13:nonroot && docker inspect --format '{{index .RepoDigests 0}}' gcr.io/distroless/cc-debian13:nonroot # Local-only debug variant: swap the final FROM to gcr.io/distroless/cc-debian13:debug-nonroot # (adds a BusyBox shell). Never push the debug variant. @@ -35,15 +35,15 @@ RUN mkdir -p /opt/runtime-libs \ # --- runtime --------------------------------------------------------------- # distroless/cc-debian13 = glibc + libssl + libstdc++, no shell, no package -# manager. Same Debian 13 (trixie) userland as the python:3.12-slim builder +# manager. Same Debian 13 (trixie) userland as the python:3.14-slim builder # (glibc 2.41), so native wheels (cryptography, pydantic-core, uvloop, # httptools) are ABI-compatible. cc-debian12 does NOT work here: its glibc -# 2.36 predates the GLIBC_2.38 symbols libpython3.12.so needs. +# 2.36 predates the GLIBC_2.38 symbols libpython3.14.so needs. # NOTE: no RUN is possible in this stage (no shell). Anything needing mkdir/ # chown at build time goes in the builder stage above. FROM gcr.io/distroless/cc-debian13:nonroot@sha256:aded2458d026e046cb68199db0e5793e1028ffa143f7258f3c4278253e20add7 # /usr/local carries the interpreter, stdlib C extensions (lib-dynload), -# libpython3.12.so, and all pip-installed packages in one consistent copy. +# libpython3.14.so, and all pip-installed packages in one consistent copy. COPY --from=builder --chown=65532:65532 /usr/local /usr/local # Stdlib-required shared libs absent from distroless cc (see builder stage). COPY --from=builder /opt/runtime-libs/ /usr/lib/x86_64-linux-gnu/