deploy: build without provenance attestations so cached rebuilds keep their id #353

Merged
mysticalsoap merged 1 commit from fix/deploy-stable-build-ids into trunk 2026-10-01 19:38:46 -04:00
Owner

Problem

just deploy --dry-run on a freshly synced trunk, with nothing changed:

would recreate media/compose.yml: metadata (changed)
would recreate web/compose.yml: knock-web (changed), knock-worker (changed)

The dry run builds build: images first so a rebuilt image is visible to compose, but BuildKit attaches a fresh provenance attestation to every build, so a fully cached rebuild still gets a new manifest digest. Compose compares image ids, sees a new one, and reports the service changed. A real deploy then recreates those containers every run for no reason, and the drift list is never trustworthy for local builds. This is also why #306's first run found "stale" local images.

Measured on media-metadata with the layer cache warm:

build image id
before eab260da…
default rebuild dc971215…
rebuild, BUILDX_NO_DEFAULT_ATTESTATIONS=1 a57c5ddd…
rebuild again, same var a57c5ddd…

Fix

deploy.py sets BUILDX_NO_DEFAULT_ATTESTATIONS=1 in its own environment, so both of its builds (the dry-run build -q and the deploy's up --build) produce reproducible ids. Nothing in the stack consumes the attestations; the image scan reads the image itself.

Verification

On the live stack: just recreate of metadata, knock-web and knock-worker onto attestation-free images, then BUILDX_NO_DEFAULT_ATTESTATIONS=1 python3 _helper/deploy.py --dry-run twice in a row:

No changed stacks to deploy.
No changed stacks to deploy.

All three containers healthy afterwards. Live already runs images with stable ids, so after merge the first dry run is quiet too.

🤖 Generated with Claude Code

## Problem `just deploy --dry-run` on a freshly synced trunk, with nothing changed: ``` would recreate media/compose.yml: metadata (changed) would recreate web/compose.yml: knock-web (changed), knock-worker (changed) ``` The dry run builds `build:` images first so a rebuilt image is visible to compose, but BuildKit attaches a fresh provenance attestation to every build, so a fully cached rebuild still gets a new manifest digest. Compose compares image ids, sees a new one, and reports the service changed. A real deploy then recreates those containers every run for no reason, and the drift list is never trustworthy for local builds. This is also why #306's first run found "stale" local images. Measured on `media-metadata` with the layer cache warm: | build | image id | |---|---| | before | `eab260da…` | | default rebuild | `dc971215…` | | rebuild, `BUILDX_NO_DEFAULT_ATTESTATIONS=1` | `a57c5ddd…` | | rebuild again, same var | `a57c5ddd…` | ## Fix `deploy.py` sets `BUILDX_NO_DEFAULT_ATTESTATIONS=1` in its own environment, so both of its builds (the dry-run `build -q` and the deploy's `up --build`) produce reproducible ids. Nothing in the stack consumes the attestations; the image scan reads the image itself. ## Verification On the live stack: `just recreate` of metadata, knock-web and knock-worker onto attestation-free images, then `BUILDX_NO_DEFAULT_ATTESTATIONS=1 python3 _helper/deploy.py --dry-run` twice in a row: ``` No changed stacks to deploy. No changed stacks to deploy. ``` All three containers healthy afterwards. Live already runs images with stable ids, so after merge the first dry run is quiet too. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
deploy: build without provenance attestations so cached rebuilds keep their id
All checks were successful
validate / validate (pull_request) Successful in 23s
ba12b85787
Every `build:` service showed as changed on every dry run, and a real
deploy recreated them every time. BuildKit attaches a fresh provenance
attestation to each build, so a fully cached rebuild still produces a
new manifest and compose sees a new image. Measured on media-metadata:
two default rebuilds gave two ids; two rebuilds with
BUILDX_NO_DEFAULT_ATTESTATIONS=1 gave the same id. Nothing here reads
the attestations; the image scan works from the image itself.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
mysticalsoap deleted branch fix/deploy-stable-build-ids 2026-10-01 19:38:46 -04:00
Sign in to join this conversation.
No description provided.