fix(release): dedup cleanup PRs, assert artifact invariant, SHA-pin upload - #85
Merged
Conversation
…pload Three related release-pipeline defects surfaced while triaging the PR backlog. 1. The release-as-cleanup job minted a duplicate PR on every release run. Its dirty-worktree check runs against a freshly checked-out main, which still carries the pin until an EARLIER cleanup PR merges — so it structurally cannot notice one that is already open. The branch name embeds `github.run_id`, so it never collides and `gh pr create` never no-ops. Result: N release runs before a human merges the cleanup PR produced N identical PRs (#65/#68/#72, now closed). Adds an explicit open-PR guard before `gh pr create`. It uses the REST list endpoint rather than `--search`, so a lagging search index cannot let a duplicate slip through — the two threadline duplicates were opened 80 minutes apart, well inside index-lag territory. 2. The integrity scanner hard-pinned an action version. `native_status_artifact` asserted the literal string `actions/upload-artifact@v4`. The real invariant is that the rollup ALWAYS uploads the status file and fails closed when it is missing — not which version does it. The frozen literal made a routine dependabot bump (#50, v4 to v7) red-line four merge-blocking lanes, and made it impossible to SHA-pin the step. Now matches any version and additionally asserts `if: ${{ always() }}`, which the old check never covered. 3. `release-please.yml:745` was the repo's only REL-05 SHA-pin violation. Every other `uses:` in the release-sensitive workflows is SHA-pinned; this one was a naked `@v4` tag, kept that way by the assertion in (2). Now pinned to ea165f8d65b6e75b540449e92b4886f43607fa02 (v4.6.2). No version change — this is the same code that was already running, now immune to tag re-pointing. Also hardens the mutation harness. `replace_in_job/4` silently returned the block unchanged when its pattern was absent, so a drifted workflow would leave the negative control asserting nothing about the check it names. It now raises at the mutation site. The phase145 control is re-pointed at a version-agnostic pattern, and a new control proves the dedup guard bites. Verified: `elixir script/check_release_workflow_integrity.exs` exits 0 WITH the SHA pin in place — the old frozen-tag check would have failed there. phase142 suite: 59 tests, 0 failures. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
szTheory
enabled auto-merge
July 28, 2026 17:01
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three related release-pipeline defects found while triaging the PR backlog. Independent of #84.
1. The cleanup job minted a duplicate PR on every release run
release-as-cleanupdecides whether to open a PR by checking whetherstrip_release_as.pydirtied the working tree. But that runs against a freshly checked-outmain, which still carries the pin until an earlier cleanup PR merges — so the check is structurally incapable of noticing one that's already open. And the branch name embeds${{ github.run_id }}, so it never collides andgh pr createnever no-ops.Net effect: N release runs before a human merges ⇒ N identical PRs. That's exactly what produced #65/#68/#72 (now closed as obsolete — the pins they stripped had already landed via #67 and #74).
Adds an explicit open-PR guard before
gh pr create. It uses the REST list endpoint, not--search— the two threadline duplicates were opened 80 minutes apart, well inside search-index lag, so a--search-based guard could still have let one through.2. The integrity scanner hard-pinned an action version
native_status_artifactasserted the literal stringactions/upload-artifact@v4. The real invariant is that the rollup always uploads the status file and fails closed when it's missing — not which version does it.That frozen literal is why dependabot #50 (
upload-artifactv4→v7) red-lines four merge-blocking lanes (phase41,phase132,phase34,phase43) plushex-page-proof. The bump itself is functionally harmless — all six artifact names are unique, the inputs used are stable across v4–v7, and the download side is already on v8.Now matches any version, and additionally asserts
if: ${{ always() }}— which the old check never covered despite it being load-bearing for the fails-closed behavior.3.
release-please.yml:745was the repo's only REL-05 SHA-pin violationEvery other
uses:in the release-sensitive workflows is SHA-pinned per REL-05 (CVE-2025-30066-class supply-chain hardening). This one was a naked@v4tag — kept that way by the assertion in #2, which required the literal string.Now pinned to
ea165f8d65b6e75b540449e92b4886f43607fa02(v4.6.2). No version change — same code that was already running, now immune to tag re-pointing.Mutation harness hardening
replace_in_job/4usedString.replace(..., global: false), which silently returns the block unchanged when the pattern is absent. A drifted workflow would leave the negative control asserting nothing about the check it names. It now raises at the mutation site with a message saying to update the control, not delete it.The phase145 control is re-pointed at a version-agnostic pattern (it was coupled to
@v4and would have broken on the SHA pin), and a new control proves the dedup guard bites.Verification
elixir script/check_release_workflow_integrity.exs→ exit 0 with the SHA pin in place. This is the load-bearing proof: the old frozen-tag check would have failed here.mix test test/crosswake/proof/phase142_release_integrity_test.exs→ 59 tests, 0 failures, including the new dedup negative control.Unblocks
Once this lands, dependabot #50 can rebase and go green.
🤖 Generated with Claude Code