Skip to content

fix: block single-arch images from reaching production#103

Merged
andig merged 1 commit into
mainfrom
fix/verify-amd64-manifest-before-deploy
Jul 24, 2026
Merged

fix: block single-arch images from reaching production#103
andig merged 1 commit into
mainfrom
fix/verify-amd64-manifest-before-deploy

Conversation

@andig

@andig andig commented Jul 24, 2026

Copy link
Copy Markdown
Member

Why

evcc/optimizer:latest pushed by hand on 2026-07-24T13:26Z carried only a linux/arm64 manifest. Azure Container Apps nodes are amd64, found no matching manifest, and every replica looped in ImagePullBackOffoptimizer.evcc.io was down until latest was rebuilt multi-arch. Every earlier tag was amd64+arm64; there was no Publish Docker run that day, so the buildx path was bypassed.

Nothing in the pipeline noticed. deploy.yml deployed the broken tag to 100% traffic a minute after the push.

What

deploy.yml — inspects the tag before touching Azure, fails with an explicit error if linux/amd64 is absent. Multi-platform tags publish an index (.Manifest.Manifests); single-platform tags publish a bare manifest, for which that template exits 1 and the fallback reads the config blob.

Makefiledocker-build now builds linux/amd64,linux/arm64 (override via DOCKER_PLATFORMS).

Behaviour changes worth reviewing

Buildx cannot load a manifest list into the local image store, so a multi-platform tag only exists once pushed. Consequences:

  • docker-build pushes directly; the separate docker-push target is gone.
  • Local iteration moves to docker-build-local — host arch, --load, never pushes.
  • default uses docker-build-local, so a bare make no longer publishes anything (previously it built a local image that a later make docker-push could ship single-arch — the exact outage path).

Verification

Check logic run against the real registry, all three manifest shapes:

image resolved platforms result
latest (multi-arch) linux/amd64 linux/arm64 pass
eacd365… (single-arch amd64) linux/amd64 pass, via fallback
sha256:29a91f79… (the outage image) linux/arm64 fail, as intended

deploy.yml parses as YAML with the step in the right position; Actions leaves the bare Go-template braces alone. make -n for default, docker-build, docker-run all expand as intended.

Not covered: the check reads the tag at deploy time, so a tag overwritten between check and pull still slips through. Digest-pinned deploys would close that; out of scope here.

🤖 Generated with Claude Code

A hand-pushed evcc/optimizer:latest carrying only a linux/arm64 manifest
took production down: Container Apps nodes are amd64, found no matching
manifest, and every replica looped in ImagePullBackOff.

Deploy now inspects the tag before touching Azure and fails with an
explicit error when linux/amd64 is missing. The index template covers
multi-platform tags; single-platform tags publish a bare manifest, for
which that template fails and the fallback reads the config blob.

docker-build builds linux/amd64,linux/arm64. Buildx cannot load a
manifest list into the local image store, so it pushes directly and the
separate docker-push target is gone. Local iteration moves to
docker-build-local, which is host-arch and never pushes; the default
target uses it, so a bare make no longer publishes anything.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@andig
andig merged commit 16b1fc7 into main Jul 24, 2026
1 check passed
@andig
andig deleted the fix/verify-amd64-manifest-before-deploy branch July 24, 2026 13:54
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.

1 participant