Skip to content

fix(build-and-sign-image): only tag releases on a release event - #29

Draft
kdaula wants to merge 2 commits into
mainfrom
kavi/gate-version-tags-on-release
Draft

fix(build-and-sign-image): only tag releases on a release event#29
kdaula wants to merge 2 commits into
mainfrom
kavi/gate-version-tags-on-release

Conversation

@kdaula

@kdaula kdaula commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Problem

Two independent paths republish release tags onto a rebuild. Docker builds aren't bit-for-bit reproducible, so either one leaves vX.Y.Z pointing at an artifact that was never released.

  1. git describe --exact-match --tags runs against whatever commit is checked out, with no reference to what triggered the run. Any non-release run landing on an already-tagged commit re-emits vX.Y.Z, X.Y, X, stable, latest.
  2. The type=semver lines feeding docker/metadata-action. procSemver gates on github.ref matching refs/tags/, not on event name (src/meta.ts:156 at the pinned dc80280), and latest rides along via the default flavor.latest=auto. So gh workflow run release-artifacts.yml --ref v1.12.0 moves all six tags — same drift, one trigger over.

This is what drifted v1.12.0: release/1.12 sat at its tag and the workflow was re-run on that commit.

Fix

  • The action already takes an event input — declared required, passed by callers, read by nothing. Now it's read.
  • Path 1: gated in capture-version-tags.sh.
  • Path 2: gated per-tag with metadata-action's enable attribute (enable= placed after pattern= so the handlebars }} doesn't terminate the GitHub expression early).
  • Every non-release event now publishes the short-sha tag alone.

Testability

selftest.yml loads three actions and this isn't one of them — it needs registry credentials and a real build — so nothing here caught a template error before it reached protect's release workflow.

  • Tag computation moved into build-and-sign-image/capture-version-tags.sh.
  • .github/tests/capture-version-tags.test.sh runs it against a fabricated repo for release, push, schedule, workflow_dispatch and empty. Verified it goes red if the gate is removed.
  • Invoked as bash <path>, so it doesn't depend on the file mode surviving.

Heads up: behavior change

Removes the workflow_dispatch "rebuild from a tag" path (edera-dev/protect#1248). That path is the drift — a rebuild can't reproduce the original digest, so re-tagging it as the release was never safe. If we want it back it should be an explicit opt-in input.

Test plan

  • bash .github/tests/capture-version-tags.test.sh — 19 checks pass
  • Fails when the gate is removed
  • shellcheck clean, YAML parses
  • Merge, cut a new version
  • Repin in edera-dev/protect#3692

Separate issue, spotted in passing

Cosign sign all images is gated if: '${{ inputs.push == true }}'inputs.push is the string 'true', and GitHub casts across types to a number, so 'true' → NaN and the condition is always false. Every other push-gated step in this file uses == 'true'. Came in with 0d91715 (#5).

If that reading holds, released images carry SBOM attestations but no signature, and cosign verify fails on all of them. I could not confirm against the registry — no read:packages on my token, no cosign/crane here. Not touching it in this PR since it's unrelated to tag drift; worth a two-minute check by someone who can pull.

Refs edera-dev/protect#3692, PRT-553

The version tag block runs `git describe --exact-match --tags` against whatever commit is checked out, with no reference to how the run was triggered. Any non-release run that lands on an already-tagged commit - a push or nightly on a release branch sitting at its tag, or a manual rebuild of a released commit - therefore republishes vX.Y.Z, stable and latest onto a freshly built digest. Docker builds are not bit-for-bit reproducible, so the released tag silently moves off the artifact that was actually released, and anyone pulling the version tag gets the rebuild.

The `event` input already existed for this and was passed by callers, but was never read anywhere in the action. Read it: version tags are applied only when the event is `release`, and every other event publishes the short-sha tag alone.

This drops the workflow_dispatch "rebuild from a tag" behaviour added in edera-dev/protect#1248 - that path is the drift. If it is wanted back it should be an explicit opt-in input rather than implicit by describe.

Refs edera-dev/protect#3692
@kdaula kdaula changed the title fix(build-and-sign-image): only apply version tags on a release event fix(build-and-sign-image): only tag releases on a release event Sep 6, 2026
@kdaula
kdaula marked this pull request as draft September 6, 2026 15:46
The gate added in the first commit only covered the `git describe` block. The `type=semver` lines feeding docker/metadata-action were still live: procSemver gates on github.ref matching refs/tags/, not on event name (src/meta.ts:156 at the pinned dc80280), and `latest` rides along via the default flavor.latest=auto. A run dispatched from a tag ref - `gh workflow run release-artifacts.yml --ref v1.12.0` - therefore still moved vX.Y.Z, X.Y, X, stable and latest onto the rebuild. Gate them per-tag with the `enable` attribute.

Nothing exercised the step being changed: selftest.yml loads three actions and build-and-sign-image is not one of them, so a template error here would ship straight to protect's release workflow. Move the tag computation into capture-version-tags.sh and cover it from selftest with a fabricated event, the same move protect made in edera-dev/protect#3692. The test fails if the gate is removed.

The script is invoked as `bash <path>` rather than executed directly, so it does not depend on the file mode surviving.

Refs edera-dev/protect#3692
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