Skip to content
Merged
Show file tree
Hide file tree
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
3 changes: 3 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,9 @@ jobs:
docker pull --platform "$platform" "$IMAGE@$DIGEST"
docker run --rm --platform "$platform" "$IMAGE@$DIGEST" \
grep -qx "$GITHUB_REF_NAME" /usr/local/lib/squarebox/VERSION
# Docker's classic image store cannot associate two platform
# members with the same manifest-list digest at once.
docker image rm "$IMAGE@$DIGEST" >/dev/null
done

- name: Create, sign, and verify digest-bound release assets
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@
- Release-candidate failures caused by a Compose UID-remap startup race,
cross-UID Evidence file permissions, LazyGit's lowercase Linux asset name,
Gum release binaries built with a vulnerable Go standard library, and raw
lifecycle assertions racing synchronous Box-tier reconciliation.
lifecycle assertions racing synchronous Box-tier reconciliation; release
preparation now isolates multi-platform pulls in Docker's local image store.

### Removed

Expand Down
20 changes: 20 additions & 0 deletions tests/test-e2e-evidence.sh
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,26 @@ for release_doc in \
grep -Fq 'immutable' "$release_doc"
done

# Docker's classic image store must release the shared manifest-list digest
# only after each explicit-platform image has verified its embedded version.
ruby - "$WORKFLOW" <<'RUBY'
require "yaml"

workflow = YAML.safe_load_file(ARGV.fetch(0), aliases: true)
step = workflow.fetch("jobs").fetch("prepare-release").fetch("steps").find do |candidate|
candidate["name"] == "Verify exact Candidate identity and architecture content"
end
abort "Candidate identity verification step is missing" unless step
script = step.fetch("run")
loop_body = script[/for platform in linux\/amd64 linux\/arm64; do\n(?<body>.*?)\n\s*done/m, :body]
abort "Candidate platform verification loop is missing" unless loop_body
pull = loop_body.index('docker pull --platform "$platform" "$IMAGE@$DIGEST"')
verify = loop_body.index('grep -qx "$GITHUB_REF_NAME" /usr/local/lib/squarebox/VERSION')
remove = loop_body.index('docker image rm "$IMAGE@$DIGEST"')
ordered = pull && verify && remove && pull < verify && verify < remove
abort "Candidate platform images are not isolated after verification" unless ordered
RUBY

# Stable Release preparation and publication are deliberately separate jobs.
# The final job selects the protected production environment only for stable
# versions; prereleases use an unprotected environment and continue
Expand Down