fix: Add resolver-bound recovery dispatch mode to native CLI publish#1797
Conversation
The first real release after the publish trust boundary landed exposed a gap: when a workflow bug is fixed after a release commit exists but before its assets are published, the branch head no longer equals the resolver target, and the approved-commit guard correctly refuses to publish. There was no path that builds the release commit source while running the fixed workflow definition. A workflow_dispatch recovery-target input now lets the unprivileged build job check out the resolver-derived release commit after verifying it is an ancestor of the approved event commit. The build guard compares the target against the actual build source commit, which keeps push-event semantics unchanged. The privileged publish job re-verifies ancestry through the GitHub compare API instead of trusting the build artifact, and anchors every tag operation on a single RELEASE_SHA that equals the event commit outside recovery. No free-form SHA input exists; the target is always bound to the resolver output, and the cli-release environment approval still gates publishing.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe release workflow accepts a resolver-derived recovery target, checks its ancestry, builds from the checked-out commit, and propagates the resulting release SHA through validation and publishing. Workflow tests verify the recovery-target constraints and updated mismatch messages. ChangesNative CLI recovery release
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant WorkflowDispatch
participant BuildJob
participant PublishJob
participant GitHubRelease
WorkflowDispatch->>BuildJob: provide recovery-target
BuildJob->>BuildJob: verify ancestry and checkout TARGET_SHA
BuildJob->>PublishJob: pass BUILD_SHA and TARGET_SHA
PublishJob->>PublishJob: derive and validate RELEASE_SHA
PublishJob->>GitHubRelease: create and publish release using RELEASE_SHA
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
Adds a
recovery-targetworkflow_dispatch input tonative-cli-publish.ymlso a pending release whose assets were never published can be rebuilt and tagged at its release commit, while the workflow definition runs from the fixed branch head.Root cause
The publish trust boundary requires the resolver-derived release target to equal the built commit. When a workflow bug is fixed after a release commit exists but before its assets publish (the current
uloop-project-runner-v3.0.0-beta.48situation), the branch head moves past the release commit and the guard correctly fails every re-dispatch. No path existed that builds the release commit source under the fixed workflow definition.Fix
recovery-targetboolean dispatch input (defaultfalse). Push-event and default-dispatch semantics are unchanged.git merge-base --is-ancestorthat the resolver target is an ancestor of the approved event commit, then checks out that target. The existing guard now compares the target against the actual build source commit (git rev-parse HEAD), which is identical to the previous check outside recovery.RELEASE_SHAfor all tag operations. Outside recovery it must equal the event commit exactly as before. In recovery it must equal the build SHA, and ancestry against the event commit is re-verified through the GitHub compare API — an input independent of the unprivileged build artifact.cli-releaseenvironment approval continues to gate publishing.scripts/test-native-cli-publish-workflow.shgainstest_recovery_dispatch_is_bound_to_the_resolver_targetcovering the input, ancestor checks, ordering, and theRELEASE_SHAanchoring; the existing no-checkout/no-scripts publish assertions still pass.The dispatcher workflow needs no change: its resolver falls back to the branch head for an absent tag, and the dispatcher source is identical between the release commit and the current head, with the pin gating dispatchers by semver floor.
Verification
scripts/test-native-cli-publish-workflow.shscripts/test-dispatcher-publish-workflow.shgo run ./cmd/check-release-triggers --base origin/v3-beta --head HEADgit diff --checkahead, self-compare toidenticalRecovery sequence after merge (owner approval already granted)
Expected: native resolver target
uloop-project-runner-v3.0.0-beta.48tagged at2d8d1b9443843f45b48479134f846b6f540e928b; dispatcher targetdispatcher-v3.1.0-beta.13tagged at the branch head. Both publish jobs then wait forcli-releaseenvironment approval.