ci(release): fail tag-push if tag is not reachable from main#40
ci(release): fail tag-push if tag is not reachable from main#40Alezander9 merged 2 commits intomainfrom
Conversation
Releases must be cut from main. Tagging a feature branch (e.g. when a stacked PR has merged into a parent feature branch but not yet into main) silently produces a release whose contents diverge from the canonical history. Precedent: v0.0.8 / v0.0.9 were tagged from feat/embed-lmnr-key after PR #33 merged into the feature branch (not into main). Main moved on without it and the bcode-laminar package had to be re-landed in PR #39. This guard fails the release workflow early — before any binaries are built or uploaded — when the tag's commit is not an ancestor of origin/main.
There was a problem hiding this comment.
1 issue found across 1 file
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".github/workflows/release.yml">
<violation number="1" location=".github/workflows/release.yml:74">
P1: The ancestry check uses `GITHUB_SHA`, which is incorrect for manual `workflow_dispatch` runs with `inputs.tag`; it can validate the dispatch ref commit instead of the selected tag commit.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
…ness Cubic review on PR #40: \GITHUB_SHA\ is the SHA of the ref that triggered the workflow, not necessarily the selected tag's commit. For push: tags they're equivalent, but for workflow_dispatch with inputs.tag, GITHUB_SHA is the dispatch ref's HEAD (typically main) — letting any feature-branch tag pass the ancestry check trivially. Fix: resolve refs/tags/\^{commit} via git rev-parse and ancestry- check that. Fails loudly with an actionable message if the tag doesn't exist yet (the workflow_dispatch path's failure mode for a fresh tag should be 'create the tag deliberately first', not 'silently tag at checkout HEAD').
|
Valid, fixed in d81b758. Root cause: Fix: resolve |
Why
Releases must be cut from
main. The currentrelease.ymltriggers on anyv*tag push regardless of which commit the tag points at. That means a feature-branch tag (especially when a stacked PR has merged into a parent feature branch but not yet intomain) silently ships a release whose contents diverge from the canonical history.Precedent.
v0.0.8andv0.0.9were tagged fromfeat/embed-lmnr-keyafter PR #33 merged into the feature branch — not intomain.mainmoved on without it (harness work, upstream syncs, PR #35 curl-upgrade), and thepackages/bcode-laminar/directory simply was not onmainuntil I re-landed it in PR #39. The fact that a release shipped from a non-maincommit was invisible until it caused friction with the eval team.What
One step in
release.yml, inserted right afteractions/checkoutand beforesetup-bun:actions/checkout@v5already runs withfetch-depth: 0so the full history is local; the explicitgit fetch origin mainis just to ensure the remote-tracking ref is current.Behaviour
maincommit -> step succeeds (~1s), release proceeds as before.::error::annotation, nogh release create, no binaries uploaded.workflow_dispatchpath (manualtaginput) is also covered:$GITHUB_SHAis the resolved tag SHA either way.Companion changes
main; stacked PRs land bottom-up before any tag. Already pushed toagent-bcode/AGENTS.md.v*tags. Together with this CI guard, that means tags only land frommain, only from approved actors.Verification
YAML is well-formed (one
run:block, no newuses:). Thegit merge-base --is-ancestorexit code is0when ancestor /1otherwise: both standard, both quiet on success.