fix(release): hand off digest-pinned action at cut time (#872) #875

Merged
pullings merged 1 commit from i/872-release-docker-digest into main 2026-08-25 18:30:08 +02:00
Owner

What changed

Refs #872. This keeps #794 as the parent Docker-action feature and #863 as the runner-contract precedent; it does not close either tracker or change the public-registry/fetch-rt.sh scope.

  • Move publish-image and verify-image-pull to the measured docker-build:host runner. The go label resolves to forgejo-ci-go, where the original cut failed with docker: command not found.
  • Add a fail-loud Docker preflight: CLI presence, daemon access, and a busybox digest pull/run positive control. The live host control recorded /usr/bin/docker, daemon 29.7.2, before=present, after=present.
  • Capture the registry RepoDigest, reject empty and all-zero values, bake it into action.yml, commit only that file, and force-update the cut tag with --force-with-lease after reading the original tag target.
  • Upload action.yml plus release-action.json as a run-scoped artifact. The verifier downloads it, checks the manifest/image/tag fields, fetches the updated tag, compares the tagged action.yml byte-for-byte with the handed-off artifact, rejects the all-zero placeholder, then authenticates and runs the digest-pinned image.
  • Make the FETCH smoke consume the digest-bearing tag after publication, while retaining the existing rt --version and cache-hit checks.

The tag handoff is the release mechanism: the previous job-local git diff could not affect the immutable tag adopters resolve. The lease and remote read-back refuse a concurrent tag move rather than overwriting it silently.

Verification

  • bats tests/workflows.bats -> 37/37 pass, including the #872 producer/consumer edge and empty-PATH Docker negative control.
  • go test ./... -> pass.
  • go vet ./... -> pass.
  • shellcheck scripts/*.sh -> pass.
  • Dockerfile build and container execution -> rt v0.45.0.
  • Temporary bare-Forgejo-shaped Git remote -> E2E_HANDOFF_OK; the remote tag commit matched release-action.json.tag_commit and the tag's action.yml matched the uploaded artifact byte-for-byte.
  • Zero-digest mutation of the exact verifier block -> refusal with tagged action artifact still carries the all-zero digest placeholder, rc=1.
  • Missing-Docker mutation of the exact preflight block -> rc nonzero with Docker capability missing.

Pullings will request Lookout once the PR exists. No reviewer was requested and no merge was attempted.

## What changed Refs #872. This keeps #794 as the parent Docker-action feature and #863 as the runner-contract precedent; it does not close either tracker or change the public-registry/fetch-rt.sh scope. - Move publish-image and verify-image-pull to the measured docker-build:host runner. The go label resolves to forgejo-ci-go, where the original cut failed with docker: command not found. - Add a fail-loud Docker preflight: CLI presence, daemon access, and a busybox digest pull/run positive control. The live host control recorded /usr/bin/docker, daemon 29.7.2, before=present, after=present. - Capture the registry RepoDigest, reject empty and all-zero values, bake it into action.yml, commit only that file, and force-update the cut tag with --force-with-lease after reading the original tag target. - Upload action.yml plus release-action.json as a run-scoped artifact. The verifier downloads it, checks the manifest/image/tag fields, fetches the updated tag, compares the tagged action.yml byte-for-byte with the handed-off artifact, rejects the all-zero placeholder, then authenticates and runs the digest-pinned image. - Make the FETCH smoke consume the digest-bearing tag after publication, while retaining the existing rt --version and cache-hit checks. The tag handoff is the release mechanism: the previous job-local git diff could not affect the immutable tag adopters resolve. The lease and remote read-back refuse a concurrent tag move rather than overwriting it silently. ## Verification - bats tests/workflows.bats -> 37/37 pass, including the #872 producer/consumer edge and empty-PATH Docker negative control. - go test ./... -> pass. - go vet ./... -> pass. - shellcheck scripts/*.sh -> pass. - Dockerfile build and container execution -> rt v0.45.0. - Temporary bare-Forgejo-shaped Git remote -> E2E_HANDOFF_OK; the remote tag commit matched release-action.json.tag_commit and the tag's action.yml matched the uploaded artifact byte-for-byte. - Zero-digest mutation of the exact verifier block -> refusal with tagged action artifact still carries the all-zero digest placeholder, rc=1. - Missing-Docker mutation of the exact preflight block -> rc nonzero with Docker capability missing. Pullings will request Lookout once the PR exists. No reviewer was requested and no merge was attempted.
fix(release): hand off digest-pinned action at cut time (#872)
All checks were successful
check-self-bootstrap / check (pull_request) Successful in 5s
fragment-check / toolkit-self gate (PR's own rt) (pull_request) Successful in 4s
fragment-check / changelog fragment-kind (pull_request) Successful in 6s
fragment-check / check (pull_request) Successful in 0s
go-ci / lint + build + test (pull_request) Successful in 23s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 6s
manifest-check / check (pull_request) Successful in 0s
register-check / register-drift check (pull_request) Successful in 6s
register-check / check (pull_request) Successful in 0s
tests / workflow-schema (pull_request) Successful in 3s
tests / bats (pull_request) Successful in 7s
tests / shellcheck (pull_request) Successful in 3s
check-self-bootstrap / check (push) Successful in 5s
go-ci / lint + build + test (push) Successful in 23s
release / decide + act (push) Successful in 7s
release / release (push) Successful in 0s
tests / workflow-schema (push) Successful in 5s
tests / bats (push) Successful in 7s
tests / shellcheck (push) Successful in 3s
bd643d639c
lookout approved these changes 2026-08-25 18:27:31 +02:00
lookout left a comment

Reviewed exact head bd643d639c and APPROVED.\n\nThe release handoff is sound: publish-image and verify-image-pull use the measured docker-build:host runner; the Docker preflight checks CLI, daemon access, and a pull/run control; the producer rejects empty/all-zero RepoDigests; and the verifier rejects an all-zero artifact before pulling. The external tag lease/read-back and run-scoped artifact bind the digest-bearing action to the tag, and the verifier compares the fetched tag's action.yml byte-for-byte with that artifact. verify-fetch-arm now consumes the post-publication tag.\n\nI independently ran the host Docker preflight and its missing-CLI and daemon-access controls, zero-digest mutations in both producer and verifier, and a local bare-Forgejo-shaped E2E handoff with lease/read-back plus a deliberate byte-mismatch refusal. Full go test ./... -count=1, go vet ./..., go build ./..., 54 Bats arms, shellcheck, and workflow checks pass. Forgejo reports mergeable=true and all 12 contexts successful.

Reviewed exact head bd643d639cb4bb32c5a4b2d79b622f44abdd8ae4 and APPROVED.\n\nThe release handoff is sound: publish-image and verify-image-pull use the measured docker-build:host runner; the Docker preflight checks CLI, daemon access, and a pull/run control; the producer rejects empty/all-zero RepoDigests; and the verifier rejects an all-zero artifact before pulling. The external tag lease/read-back and run-scoped artifact bind the digest-bearing action to the tag, and the verifier compares the fetched tag's action.yml byte-for-byte with that artifact. verify-fetch-arm now consumes the post-publication tag.\n\nI independently ran the host Docker preflight and its missing-CLI and daemon-access controls, zero-digest mutations in both producer and verifier, and a local bare-Forgejo-shaped E2E handoff with lease/read-back plus a deliberate byte-mismatch refusal. Full go test ./... -count=1, go vet ./..., go build ./..., 54 Bats arms, shellcheck, and workflow checks pass. Forgejo reports mergeable=true and all 12 contexts successful.
lookout approved these changes 2026-08-25 18:27:31 +02:00
lookout left a comment

Reviewed exact head bd643d639c and APPROVED.\n\nThe release handoff is sound: publish-image and verify-image-pull use the measured docker-build:host runner; the Docker preflight checks CLI, daemon access, and a pull/run control; the producer rejects empty/all-zero RepoDigests; and the verifier rejects an all-zero artifact before pulling. The external tag lease/read-back and run-scoped artifact bind the digest-bearing action to the tag, and the verifier compares the fetched tag's action.yml byte-for-byte with that artifact. verify-fetch-arm now consumes the post-publication tag.\n\nI independently ran the host Docker preflight and its missing-CLI and daemon-access controls, zero-digest mutations in both producer and verifier, and a local bare-Forgejo-shaped E2E handoff with lease/read-back plus a deliberate byte-mismatch refusal. Full go test ./... -count=1, go vet ./..., go build ./..., 54 Bats arms, shellcheck, and workflow checks pass. Forgejo reports mergeable=true and all 12 contexts successful.

Reviewed exact head bd643d639cb4bb32c5a4b2d79b622f44abdd8ae4 and APPROVED.\n\nThe release handoff is sound: publish-image and verify-image-pull use the measured docker-build:host runner; the Docker preflight checks CLI, daemon access, and a pull/run control; the producer rejects empty/all-zero RepoDigests; and the verifier rejects an all-zero artifact before pulling. The external tag lease/read-back and run-scoped artifact bind the digest-bearing action to the tag, and the verifier compares the fetched tag's action.yml byte-for-byte with that artifact. verify-fetch-arm now consumes the post-publication tag.\n\nI independently ran the host Docker preflight and its missing-CLI and daemon-access controls, zero-digest mutations in both producer and verifier, and a local bare-Forgejo-shaped E2E handoff with lease/read-back plus a deliberate byte-mismatch refusal. Full go test ./... -count=1, go vet ./..., go build ./..., 54 Bats arms, shellcheck, and workflow checks pass. Forgejo reports mergeable=true and all 12 contexts successful.
Sign in to join this conversation.
No description provided.