Skip to content

feat(ci): fail when a duplocloud image tag is not published multi-arch - #22

Merged
aboutte merged 1 commit into
duplocloud:devfrom
duplo-darren:feat/multi-arch-image-check
Oct 5, 2026
Merged

aboutte merged 1 commit into
duplocloud:devfrom
duplo-darren:feat/multi-arch-image-check

Conversation

@duplo-darren

Copy link
Copy Markdown
Contributor

Per the Multi-Arch Image Guard proposal and @aboutte's reply: "check duplo images (quay)", "yes block PR merging."

What this does

Fails CI when a duplocloud image tag configured in this repo does not publish both linux/amd64 and linux/arm64.

Every devkit release is now expected to publish multi-arch — the studio platform pin was dropped on that premise (scripts/_runtime.sh, runtime_rosetta_check). Nothing currently enforces it: bump a tag to an amd64-only build and the kit silently falls back to emulation on Apple Silicon, because the retained Rosetta check only fires on an explicit amd64 pin and cannot see an unset platform resolving to the wrong image.

Scope

quay.io/duplocloud/* only, per @aboutte's decision. These are images DuploCloud itself builds and has committed to publishing multi-arch, so a failing tag here is a mistake to fix, not a legitimate choice to accommodate — unlike the Rosetta check, which has to allow for a user's own private registry. Third-party images (mongo, qdrant, busybox) stay out: stable, already multi-arch, and Docker Hub needs an auth dance this doesn't.

BUILDER_TAG is also excluded — it defaults to latest, a moving target that proves nothing about tomorrow's pull.

How it checks

Queries the registry API directly for each configured image (STUDIO_TAG, AGENT_TAG, UI_TAG, XTERM_TAG). No docker/podman pull, no runtime, no credentials needed — quay's duplocloud images are public, so this runs the same on a fork PR as it does here.

Filters out attestation manifests (quay's backend image carries two os/architecture: unknown entries alongside its real platforms) — naive parsing would count those and pass anything.

Testing

19 unit tests, all pure — canned JSON fixtures, no network. Two mutation-tested: removing the attestation filter, and loosening the digest-pin skip detection, each make a specific test fail.

Also verified against live quay, not only fixtures:

  • A real run against the current tags on dev passes.
  • A real single-arch manifest — the backend image's own per-platform digest, queried outside the multi-arch index — is correctly detected and fails.
  • The actual workflow YAML ran for real on GitHub's infrastructure: pushed temporarily to my fork's main (which was 2 commits behind origin/main and unused), dispatched, confirmed success with the expected output, then restored to its exact prior commit. Run.

Note for reviewers

GitHub only runs a pull_request-triggered workflow if it already exists on the base branch, so this will not appear as a check on this PR. It activates once merged to dev — the live-run link above is the closest available proof before then.

This fails the build but does not yet block merging: dev currently has no branch protection rules at all. Making this (and arguably extension-ci.yml's build job) a required check is a separate repo-settings change, which @aboutte said he'd make once this exists.

🤖 Generated with Claude Code

Every devkit release is now expected to publish both linux/amd64 and linux/arm64 — the studio platform
pin was dropped on that premise (scripts/_runtime.sh, runtime_rosetta_check). Nothing currently enforces
it: bump a tag to an amd64-only build and the kit silently falls back to emulation on Apple Silicon,
because the retained Rosetta check only fires on an EXPLICIT amd64 pin and cannot see an unset platform
resolving to the wrong image.

scripts/check-image-arches.sh queries the registry API directly for each configured duplocloud image
(no docker/podman pull, no runtime, no credentials needed for a public quay repo) and fails if either
required architecture is missing. Scoped to quay.io/duplocloud/* only, per @aboutte: these are images
DuploCloud itself builds and has committed to publishing multi-arch, so a failure here is a mistake to
fix, not a legitimate choice to accommodate — unlike the Rosetta check, which has to allow for a user's
own private registry. Third-party images (mongo, qdrant, busybox) are out of scope for the same reason
the design doc gives: stable, already multi-arch, and Docker Hub needs an auth dance this does not.

.github/workflows/image-arch-check.yml runs it on pull_request, gated on .env.example and
docker-compose.yml having changed (the only two files that can move a pinned tag), plus
workflow_dispatch for a manual run with no PR required. Per @aboutte's reply, this fails the build;
making it a required check in branch protection is a separate repo-settings change on his side —
dev currently has no branch protection at all, so until that setting changes, a failure here is
visible but not blocking.

Tests: 19, all pure — manifest parsing, the architecture comparison, and the skip-decisions (unset,
`latest`, a digest pin) are exercised with canned fixtures, no network. The two risk points are
mutation-tested: removing the attestation-manifest filter (quay's backend image carries two
`unknown/unknown` entries alongside its real platforms) and loosening the digest-pin skip detection
each make a specific test fail.

Verified against live quay, not only fixtures: a real run against the four tags on dev passes; a real
amd64-only manifest — the `backend` image's own per-platform digest, queried on its own outside the
multi-arch index — is correctly detected and fails.

NOTE: GitHub only runs a pull_request-triggered workflow if it already exists on the base branch, so
this workflow will not appear as a check on the PR that introduces it. It activates once merged to dev.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@aboutte
aboutte merged commit 0a888ee into duplocloud:dev Oct 5, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants