fix: produce real multi-arch images from ghcr and ecr workflows#128
Merged
fix: produce real multi-arch images from ghcr and ecr workflows#128
Conversation
Both shared workflows produced single-arch images despite advertising
linux/amd64 + linux/arm64 support, causing `exec format error` for
consumers running on the missing architecture.
ecr-build-and-push.yml had `platforms: linux/arm64` hardcoded in both
build steps, so every image pushed was arm64-only regardless of any
intent to support amd64. ghcr.yml declared a platform matrix but never
passed `${{ matrix.platform }}` to docker/build-push-action; both matrix
jobs ran on the same runner group and raced to push identical tags, and
no manifest list was assembled.
Both workflows now follow the same pattern as release-docker-ghcr.yml:
native runners per architecture (ubuntu-latest + ubuntu-24.04-arm),
push-by-digest per platform, then a `merge` job that assembles the
manifest list under the metadata-action tags via
`docker buildx imagetools create`. The ghcr workflow's build-provenance
attestation now attests the merged manifest digest rather than a single
per-arch digest.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
rymcol
approved these changes
May 5, 2026
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ecr-build-and-push.ymlhadplatforms: linux/arm64hardcoded in bothBuild and pushsteps — every image pushed to ECR through this workflow was arm64-only, causingexec format errorfor consumers running on amd64.ghcr.ymldeclared a[linux/amd64, linux/arm64]matrix but never passed${{ matrix.platform }}todocker/build-push-action. Both matrix jobs ran oninit4-runnersand raced to push identical tags ({{version}},{{major}}.{{minor}},latest,sha). Noimagetools createstep ran, so the published image was a single-arch image, not a manifest list.release-docker-ghcr.yml: matrix on native runners per arch (ubuntu-latest+ubuntu-24.04-arm),push-by-digest=true,name-canonical=true, digest artifact upload, then amergejob that assembles the manifest list under allmetadata-actiontags viadocker buildx imagetools create.attest-build-provenancestep moved into the merge job and now attests the merged multi-arch manifest digest, which is what consumers actually pull.Why amd64 builds were missing
The first failure surfaced via init4tech/builder v1.0.0: pulling the image on amd64 hosts produced
exec /usr/local/bin/zenith-builder-example: exec format error. Tracing showed the ECR workflow had no amd64 build step at all, and the GHCR workflow's matrix variable was never wired through to the build action — so both registries published arm64-only images regardless of tag.Behaviour changes for consumers
ubuntu-latest+ubuntu-24.04-arminstead of theinit4-runnersgroup. AWS OIDC + ECR login still works the same way and is performed in both the build and merge jobs.type=ref,event=prand per-major/minor semver tags from the original metadata step are preserved./tmp/.buildx-cachewas replaced with GHA cache scoped per platform — local cache made no sense across separate runners, and per-platform GHA scope is the same approach used by the original (pre-shared-workflow) ghcr.yml in init4tech/builder.Test plan
v1.0.0(or push a temporaryv1.0.1-rc.0) on init4tech/builder and confirm both ECR and GHCR artifacts are real manifest lists with bothlinux/amd64andlinux/arm64entries:docker manifest inspect <ecr-repo>/zenith-builder-example:1.0.1-rc.0docker manifest inspect ghcr.io/init4tech/builder:1.0.1-rc.0docker pull --platform=linux/amd64 ...anddocker runsucceeds on an amd64 hostdocker pull --platform=linux/arm64 ...anddocker runsucceeds on an arm64 hostrequires-private-deps: true)🤖 Generated with Claude Code