Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 23 additions & 11 deletions .github/workflows/release-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ jobs:
fi

# 5. Deterministic metadata: the build date is the tagged commit's
# own timestamp, so re-running the same release reproduces the
# same image config instead of minting a new digest per run.
# own timestamp, so the image label and the binary's build time
# are the same in every run of the release.
BUILD_DATE=$(TZ=UTC git show -s --date=format-local:'%Y-%m-%dT%H:%M:%SZ' --format=%cd "$SHA")

{
Expand Down Expand Up @@ -287,8 +287,14 @@ jobs:
VERSION=${{ needs.gate.outputs.version }}
VCS_REF=${{ needs.gate.outputs.sha }}
BUILD_DATE=${{ needs.gate.outputs.build_date }}
cache-from: type=gha,scope=${{ matrix.arch }}
cache-to: type=gha,mode=max,scope=${{ matrix.arch }}
# No gha build cache, as in release-dev-image.yml. The image built
# here is the one that is scanned, pushed and signed, so a layer
# restored from the Actions cache would ship in a signed release
# (actions/cache-poisoning/poisonable-step). The cache did little
# for release builds: the cargo build layer's inputs change with
# every release, so it was restored only when the same release was
# built a second time, and exporting the cache took up to two and
# a half minutes per build.

- name: Confirm the image really is ${{ matrix.arch }}
# Cheap guard against a silent platform fallback: a mislabelled image
Expand Down Expand Up @@ -415,13 +421,19 @@ jobs:
CANDIDATE="sha-${SHA}"

# Idempotent no-overwrite: if the candidate tag exists and holds
# EXACTLY what this run built, fall through to sign and propagate
# (a failed earlier run must be finishable by re-dispatch, or the
# failure-prone tail strands a published-but-unsigned candidate no
# re-dispatch can fix). Identity is compared by per-arch image
# config digest — the image ID, which docker save/load preserves
# and the smoke test certified — with NO registry mutation: a
# different artifact errors before anything is pushed.
# EXACTLY what this run built, fall through to sign and propagate,
# so a run that failed after pushing can still be finished.
# Identity is compared by per-arch image config digest (the image
# ID, which docker save/load preserves and the smoke test
# certified) with NO registry mutation: a different artifact
# errors before anything is pushed. The build has no layer cache,
# so a new dispatch builds images with different IDs and, if the
# earlier run pushed the candidate, stops here. To finish a failed
# run, use "Re-run failed jobs" on that run while its image
# artifacts are kept (retention-days: 1 above); this job then
# reloads the images it pushed and they match. Once the artifacts
# have expired the run cannot be finished this way; sign-image.yml
# covers signing a candidate that was pushed but not signed.
if EXISTING=$(docker buildx imagetools inspect "${REPO}:${CANDIDATE}" --format '{{.Manifest.Digest}}' 2>/dev/null); then
RAW=$(skopeo inspect --no-creds --raw "docker://${REPO}@${EXISTING}")
MATCH=true
Expand Down
Loading