fix(agent-actions): deny an unpinned staged merge on accept - #2431
Conversation
#2377 closed this gap for approve; merge had the identical fallback in performAction (mergeSha = action.expectedHeadSha ?? ctx.headSha). The usual "GitHub 409s on a stale sha" backstop doesn't cover this case: the fallback substitutes whatever head is live right now, so it trivially matches and no 409 is possible. Extend the same accept-flow denial gate to merge. Closes #2422
|
Warning 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 ⏸️ Gittensory review result - manual review recommendedReview updated: 2026-07-01 23:01:41 UTC
⏸️ Suggested Action - Manual Review
Review summary Nits — 4 non-blocking
Review context
Contributor next steps
Signal definitions
🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2431 +/- ##
=======================================
Coverage 95.88% 95.88%
=======================================
Files 224 224
Lines 25136 25137 +1
Branches 9139 9140 +1
=======================================
+ Hits 24102 24103 +1
Misses 421 421
Partials 613 613
🚀 New features to boost your workflow:
|
Summary
#2377closed the unpinned-legacy-row gap forapprove.mergehad the identical fallback inperformAction:mergeSha = action.expectedHeadSha ?? ctx.headSha.sha" backstop that protects a pinned merge doesn't cover this case: the fallback substitutes whatever head is live right now, so it trivially matches and no 409 is possible. An unpinned staged merge (noexpectedHeadSha, e.g. a row from before this head-pinning fix, or a planning pass that ran against a transiently-null stored head SHA) would silently merge whatever commit is live at accept time, under the authority of a review/merge that was never actually performed against it.#2377added forapproveto also covermerge.Closes #2422
Test plan
npm run typecheckcleannpm run test:coverage: 312 files / 5833 tests passing, no threshold failures (re-verified after rebasing onto#2423, which also merged intomainand touches the same function)npm audit --audit-level=moderate: 0 vulnerabilitiesunpinned_legacy_action), not silently executedexpectedHeadShaso they keep testing their original intent instead of hitting the new gate