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 18c63d2..6056a94 100644 --- a/Controller/Dockerfile +++ b/Controller/Dockerfile @@ -1,11 +1,11 @@ # 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. # --- 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 @@ -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:54df941ed0d06a1bd95ef5e0ce391fd8d9f94b64782dc9a60062727849ee3f97 # /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/