From 8cb816b1efba3f9670a6f6438e7b72a87837ccfa Mon Sep 17 00:00:00 2001 From: bloodearnest Date: Tue, 20 Jan 2026 14:52:03 +0000 Subject: [PATCH 1/5] Update dockerfile to latest patterns As well as improving local development, this reduces layer count and also prepares us for secrets --- Dockerfile | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8bdf3af..b4ddc8b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -# syntax=docker/dockerfile:1.2 +# syntax=docker/dockerfile:1.10 ################################################# # # We need base python dependencies on both the builder and python images, so @@ -22,7 +22,11 @@ ENV ACTION_EXEC=python MAJOR_VERSION=${MAJOR_VERSION} BASE=${BASE} COPY ${MAJOR_VERSION}/dependencies.txt /opt/dependencies.txt # use space efficient utility from base image -RUN /root/docker-apt-install.sh /opt/dependencies.txt +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + --mount=type=bind,source=${MAJOR_VERSION}/dependencies.txt,target=/tmp/dependencies.txt \ + mkdir /workspace; \ + /root/docker-apt-install.sh /tmp/dependencies.txt # now we have python, set up a venv to install packages to, for isolation from # system python libraries @@ -42,8 +46,10 @@ FROM base-python as builder ARG MAJOR_VERSION # install build time dependencies -COPY ${MAJOR_VERSION}/build-dependencies.txt /opt/build-dependencies.txt -RUN /root/docker-apt-install.sh /opt/build-dependencies.txt +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + --mount=type=bind,source=${MAJOR_VERSION}/build-dependencies.txt,target=/tmp/build-dependencies.txt \ + /root/docker-apt-install.sh /tmp/build-dependencies.txt COPY ${MAJOR_VERSION}/requirements.txt /opt/requirements.txt COPY ${MAJOR_VERSION}/packages.md /opt/packages.md From 50b734070787285435bd8994d17e20faa8903c40 Mon Sep 17 00:00:00 2001 From: bloodearnest Date: Tue, 20 Jan 2026 14:53:49 +0000 Subject: [PATCH 2/5] update linters --- justfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/justfile b/justfile index 2b05e3f..f770353 100644 --- a/justfile +++ b/justfile @@ -29,8 +29,9 @@ render version *args: # run linters check: - @docker pull hadolint/hadolint:v2.12.0 - @docker run --rm -i hadolint/hadolint:v2.12.0 < Dockerfile + @docker run --rm -i hadolint/hadolint:v2.14.0 < Dockerfile + @ls scripts/*.sh | xargs docker run --rm -v "$PWD:/mnt:ro" koalaman/shellcheck:v0.11.0 + @docker run --rm -v "$PWD:/repo:ro" --workdir /repo rhysd/actionlint:1.7.10 -color # publish version (dry run by default - pass "true" to perform publish) From db87cc9530c8a88fccf3f8e97ff8da1c081dfb63 Mon Sep 17 00:00:00 2001 From: bloodearnest Date: Tue, 20 Jan 2026 14:54:05 +0000 Subject: [PATCH 3/5] Add support for ESM repo for 20.04 Uses the new support for this is base-docker. Requires an UBUNTU_PRO_TOKEN in the env, just like base-docker --- .gitignore | 3 +++ Dockerfile | 2 ++ docker-compose.yml | 6 ++++++ justfile | 17 ++++++++++++++++- tests/test_packaging.py | 11 +++++++++++ 5 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/test_packaging.py diff --git a/.gitignore b/.gitignore index acbad03..7060b29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ *~ venv +.venv __pycache__ +.env +.secrets diff --git a/Dockerfile b/Dockerfile index b4ddc8b..1c3ddb3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,6 +25,7 @@ COPY ${MAJOR_VERSION}/dependencies.txt /opt/dependencies.txt RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \ --mount=type=bind,source=${MAJOR_VERSION}/dependencies.txt,target=/tmp/dependencies.txt \ + --mount=type=secret,id=ubuntu_pro_token,required=true \ mkdir /workspace; \ /root/docker-apt-install.sh /tmp/dependencies.txt @@ -49,6 +50,7 @@ ARG MAJOR_VERSION RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \ --mount=type=bind,source=${MAJOR_VERSION}/build-dependencies.txt,target=/tmp/build-dependencies.txt \ + --mount=type=secret,id=ubuntu_pro_token \ /root/docker-apt-install.sh /tmp/build-dependencies.txt COPY ${MAJOR_VERSION}/requirements.txt /opt/requirements.txt diff --git a/docker-compose.yml b/docker-compose.yml index e9f4f17..de4a539 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,6 +5,8 @@ services: build: context: . target: base-python + secrets: + - ubuntu_pro_token cache_from: # should speed up the build in CI, where we have a cold cache - ghcr.io/opensafely-core/base-action:${BASE} - ghcr.io/opensafely-core/python:${MAJOR_VERSION} @@ -24,3 +26,7 @@ services: image: python:${MAJOR_VERSION} build: target: python + +secrets: + ubuntu_pro_token: + file: ${UBUNTU_PRO_TOKEN_FILE:-.secrets/ubuntu_pro_token} diff --git a/justfile b/justfile index f770353..bd03b18 100644 --- a/justfile +++ b/justfile @@ -1,3 +1,6 @@ +set dotenv-load := true + +export UBUNTU_PRO_TOKEN_FILE := env_var_or_default('UBUNTU_PRO_TOKEN_FILE', justfile_directory() + "/.secrets/ubuntu_pro_token") export DOCKER_BUILDKIT := "1" # technically, these could differ by 1 seconds, but thats unlikely and doesn't matter # human readable, used as label in docker image @@ -6,8 +9,20 @@ export BUILD_DATE := `date +'%y-%m-%dT%H:%M:%S.%3NZ'` export BUILD_NUMBER := `date +'%y%m%d%H%M%S'` export REVISION := `git rev-parse --short HEAD` +ensure-pro-token: + #!/bin/bash + set -euo pipefail + token_file="{{ UBUNTU_PRO_TOKEN_FILE }}" + if test -z "${UBUNTU_PRO_TOKEN:-}"; then + echo "UBUNTU_PRO_TOKEN is required to create $token_file" >&2 + exit 1 + fi + mkdir -p "$(dirname "$token_file")" + umask 077 + printf '%s' "$UBUNTU_PRO_TOKEN" > "$token_file" + # build docker image for version -build version target="python" *args="": +build version target="python" *args="": ensure-pro-token docker compose --env-file {{ version }}/env build --pull {{ args }} {{ target }} diff --git a/tests/test_packaging.py b/tests/test_packaging.py new file mode 100644 index 0000000..faf0e89 --- /dev/null +++ b/tests/test_packaging.py @@ -0,0 +1,11 @@ +from pathlib import Path +import subprocess + +import pytest + +os_release = Path("/etc/os-release").read_text() + +@pytest.mark.skipif('VERSION_ID="20.04"' not in os_release, reason="20.04 only") +def test_esm(): + output = subprocess.check_output(["dpkg-query", "-W", "-f='${Package}\t${Version}\n'", "libssl1.1"], text=True) + assert "esm" in output From 073e4b991da9beeb53ea2b8795abc734271d4db1 Mon Sep 17 00:00:00 2001 From: bloodearnest Date: Tue, 20 Jan 2026 14:57:13 +0000 Subject: [PATCH 4/5] add secret to CI env vars --- .github/workflows/build_and_publish.yaml | 3 ++- .github/workflows/tests.yaml | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_and_publish.yaml b/.github/workflows/build_and_publish.yaml index 73850c1..f41632c 100644 --- a/.github/workflows/build_and_publish.yaml +++ b/.github/workflows/build_and_publish.yaml @@ -3,7 +3,8 @@ on: workflow_dispatch: push: branches: [main] - +env: + UBUNTU_PRO_TOKEN: ${{ secrets.UBUNTU_PRO_TOKEN }} jobs: publish: # note: this builds/tests all versions in serial for two reasons. Firstly we diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 045ea7d..654f35c 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -1,6 +1,8 @@ name: Run tests on: pull_request: +env: + UBUNTU_PRO_TOKEN: ${{ secrets.UBUNTU_PRO_TOKEN }} jobs: version-tests: runs-on: ubuntu-22.04 From 24900c21be495315df10c8845d910ca825cfe2fe Mon Sep 17 00:00:00 2001 From: bloodearnest Date: Tue, 20 Jan 2026 15:06:23 +0000 Subject: [PATCH 5/5] update docs for ESM support --- DEVELOPERS.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/DEVELOPERS.md b/DEVELOPERS.md index 2328c3f..749c968 100644 --- a/DEVELOPERS.md +++ b/DEVELOPERS.md @@ -29,6 +29,14 @@ just build v2 just test v2 ``` +## ESM Packages on 20.04 images + +We still support the older python:v1, but it is based on Ubuntu 20.04, which +has reached EOL for security upgrades. So we have enabled ESM via Ubuntu Pro for these images. + +This means that you do need a valid `UBUNTU_PRO_TOKEN` environment variable to +build these images. + ## Add a new package to existing version