From b869235224ccbacd08f3be3b79b777913ddca5db Mon Sep 17 00:00:00 2001 From: Sean Whalen <44679+seanthegeek@users.noreply.github.com> Date: Mon, 8 Jun 2026 17:42:00 -0400 Subject: [PATCH] Build multi-arch (amd64+arm64) Docker images with PostgreSQL support (#793) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Build multi-arch Docker images with PostgreSQL support The prebuilt image now installs the `[postgresql]` extra, so the optional PostgreSQL output backend (psycopg) works out of the box in the container without a separate `pip install` (#792). The wheel path is resolved into a variable before appending the extra so the shell doesn't treat `*.whl[postgresql]` as a bracket glob. The build workflow now sets up QEMU + Buildx and builds a multi-arch manifest for `linux/amd64` and `linux/arm64`, so the image runs natively on 64-bit ARM hosts such as a Raspberry Pi (#789). Every compiled dependency (psycopg[binary], lxml, maxminddb, cryptography) ships prebuilt aarch64 manylinux wheels, so the arm64 build adds no source-compilation step. A `pull_request` trigger (scoped to the build inputs) and `workflow_dispatch` are added so the multi-arch build can be validated on PRs and rebuilt on demand; pushes are still gated on the release event, so neither pushes images. Closes #789 Closes #792 Co-Authored-By: Claude Opus 4.8 (1M context) * Bump version to 10.0.4 to publish the new images The docker workflow only pushes to the registry on a `release` event, so shipping the multi-arch + PostgreSQL-enabled image requires cutting a release. 10.0.3 is already tagged, so bump to 10.0.4 and document the Docker changes in the changelog. Co-Authored-By: Claude Opus 4.8 (1M context) * Don't run the docker build on pull requests The pull_request trigger (added to validate the multi-arch build) re-ran the full ~10-minute amd64+arm64 build on every commit pushed to a docker-touching PR, because the pull_request `paths` filter matches against the PR's entire diff, not just the newest commit. That is wasteful once the build has been validated. Drop the pull_request trigger and rely on workflow_dispatch for on-demand validation (plus the existing master-push and release triggers). Also gate the registry login on the release event so that no non-release run authenticates to ghcr at all — a build can only ever be pushed from a published release. Co-Authored-By: Claude Opus 4.8 (1M context) --------- Co-authored-by: Claude Opus 4.8 (1M context) --- .github/workflows/docker.yml | 17 +++++++++++++++++ CHANGELOG.md | 7 +++++++ Dockerfile | 9 ++++++++- docs/source/usage.md | 6 +++++- parsedmarc/constants.py | 2 +- 5 files changed, 38 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 4512571..dc7e2e2 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -10,6 +10,9 @@ on: push: branches: - master + # Allow maintainers to build/validate the multi-arch image on demand + # (e.g. from a feature branch) without pushing anything to the registry. + workflow_dispatch: env: REGISTRY: ghcr.io @@ -26,6 +29,12 @@ jobs: - name: Checkout repository uses: actions/checkout@v5 + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Docker meta id: meta uses: docker/metadata-action@v5 @@ -40,6 +49,10 @@ jobs: type=semver,pattern={{major}}.{{minor}} - name: Log in to the Container registry + # Only authenticate when we will actually push (release). The master + # push and workflow_dispatch runs build for validation only and must + # never touch the registry, so they skip the login entirely. + if: github.event_name == 'release' uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} @@ -50,6 +63,10 @@ jobs: uses: docker/build-push-action@v6 with: context: . + platforms: linux/amd64,linux/arm64 + # Push only on a published release. Every other trigger (push to + # master, workflow_dispatch) builds both architectures for + # validation but never pushes. push: ${{ github.event_name == 'release' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 047b3e7..7fdb97a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 10.0.4 + +### Docker + +- **PostgreSQL backend in the prebuilt image** ([#792](https://github.com/domainaware/parsedmarc/issues/792)): the image now installs `parsedmarc[postgresql]`, so the optional PostgreSQL output backend (`psycopg`) works out of the box in the container without a separate `pip install`. +- **`arm64` images** ([#789](https://github.com/domainaware/parsedmarc/issues/789)): the release workflow now builds and publishes a multi-arch manifest for `linux/amd64` and `linux/arm64`, so `ghcr.io/domainaware/parsedmarc` runs natively on 64-bit ARM hosts such as a Raspberry Pi. All compiled dependencies (`psycopg[binary]`, `lxml`, `maxminddb`, `cryptography`) ship prebuilt `aarch64` wheels, so the build adds no source-compilation step. + ## 10.0.3 ### Bug fixes diff --git a/Dockerfile b/Dockerfile index 0325a07..c246d5e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,7 +27,14 @@ COPY --from=build /app/dist/*.whl /tmp/dist/ RUN set -ex; \ groupadd --gid ${USER_GID} ${USERNAME}; \ useradd --uid ${USER_UID} --gid ${USER_GID} -m ${USERNAME}; \ - pip install /tmp/dist/*.whl; \ + # Install the wheel with the [postgresql] extra so the prebuilt image + # ships the PostgreSQL output backend (psycopg). Resolve the globbed wheel + # path into a variable first: `*.whl[postgresql]` would otherwise be parsed + # as a shell bracket glob rather than a pip extras spec. psycopg[binary] + # has prebuilt manylinux wheels for both amd64 and arm64, so this adds no + # source-build step on either platform. + whl="$(ls /tmp/dist/*.whl)"; \ + pip install "${whl}[postgresql]"; \ rm -rf /tmp/dist USER $USERNAME diff --git a/docs/source/usage.md b/docs/source/usage.md index eb4ffd4..94ab6bb 100644 --- a/docs/source/usage.md +++ b/docs/source/usage.md @@ -381,7 +381,11 @@ The full set of configuration options are: The PostgreSQL backend is an optional extra. Install it with `pip install parsedmarc[postgresql]` (it pulls in `psycopg`); the prebuilt binary wheels are not available for every platform, which is - why it is not a mandatory dependency. + why it is not a mandatory dependency. The prebuilt Docker image + (`ghcr.io/domainaware/parsedmarc`) already bundles this extra, so the + PostgreSQL backend works out of the box in the container — `psycopg` + ships `amd64` and `arm64` binary wheels, both of which the image + supports. Tables are created automatically on first run using `CREATE TABLE IF NOT EXISTS`, so no manual schema migration is needed diff --git a/parsedmarc/constants.py b/parsedmarc/constants.py index 6a2e7f3..9730232 100644 --- a/parsedmarc/constants.py +++ b/parsedmarc/constants.py @@ -1,4 +1,4 @@ -__version__ = "10.0.3" +__version__ = "10.0.4" USER_AGENT = f"parsedmarc/{__version__}"