Repository navigation
ci: auto-approve held fork runs after a Kodiak branch update - #3584
brandon-pereira wants to merge 2 commits into
Conversation
Duplicate code analysisNo new duplicate code introduced by this PR. jscpd compared this branch against |
E2E Test Results✅ All tests passed • 462 passed • 1 skipped • 1415s
Tests ran across 4 shards in parallel. |
| }, | ||
| 'no runs for the previous head': { beforeRuns: [] }, | ||
| 'previous head runs still held': { | ||
| beforeRuns: [ |
There was a problem hiding this comment.
🔵 minor — No test checks the action_required rule on its own: deleting it from decideApproval still passes every test
The 'previous head runs still held' case pairs action_required with contributor, who has no write permission, so the actor check rejects it anyway. Change it to run('action_required', 'maintainer') so the r.conclusion === 'action_required' condition in kodiak-run-approval.js:92 is actually tested, and assert on decision.reason in the rejected cases so each one proves which check fired.
Advisory. Fix if it is a small defect in code this PR changes; otherwise reply in the thread. Do not widen the PR or touch files it did not already change. How to respond
| }) | ||
| ).filter( | ||
| r => | ||
| r.head_repository?.full_name === pr.head.repo.full_name && |
There was a problem hiding this comment.
🔵 minor — A null pr.head.repo (deleted fork) crashes listRuns before decideApproval can handle it
decideApproval reads pr.head.repo?.full_name, but listRuns (called first, at line 69) reads pr.head.repo.full_name and throws a TypeError. Either check pr.head.repo before any API calls and return early with a reason, or use ?. here as well so both places handle it the same way.
Advisory. Fix if it is a small defect in code this PR changes; otherwise reply in the thread. Do not widen the PR or touch files it did not already change. How to respond
| if (pr.head.sha !== after) | ||
| return no(`PR head moved past ${after} to ${pr.head.sha}`); | ||
|
|
||
| if (headCommit.sha !== after) |
There was a problem hiding this comment.
🔵 minor — The headCommit.sha !== after guard can never trigger
headCommit comes from repos.getCommit({ ref: after }) in approve-kodiak-update-runs.js:45, and after is a full SHA, so the returned sha always equals after. Remove the guard, or pass headCommit in a form where a mismatch is actually possible.
Advisory. Fix if it is a small defect in code this PR changes; otherwise reply in the thread. Do not widen the PR or touch files it did not already change. How to respond
PR Review
3 finding(s): 🔴 0 critical · 🟠 0 major · 🔵 3 minor 3 posted as inline comment(s) on the changed lines. Severity is the reviewer's own estimate and is used for ordering, not filtering. No finding blocks merge automatically; a maintainer decides. |
Deep Review✅ No critical issues found. The trust boundary is well-constructed: 🟡 P2 -- recommended
🔵 P3 nitpicks (5)
Reviewers (7): testing, maintainability, project-standards, reliability, kieran-typescript, agent-native, learnings-researcher. The correctness, security, and adversarial reviewers were dispatched but did not return before finalization; the orchestrator analyzed that surface directly (sender/merge-shape/vouched-runs trust boundary, Testing gaps: The orchestration layer in No finding blocks merge automatically. A maintainer will expect P0/P1 findings in code this PR changes to be fixed; P2/P3 are your call -- fix or reply. Never fix findings about surrounding code here; reply instead. Do not widen the PR. How to respond |
Summary
When a maintainer adds
automergeto a first-time contributor's fork PR, Kodiak mergesmaininto the branch. GitHub then holds the newpull_requestruns for approval again, even though the contributor's code was already reviewed and its runs approved. The PR sits until someone clicks "Approve workflows to run" a second time; on #3532 that took about 40 minutes.This adds a
pull_request_targetworkflow that approves those held runs when the push is only Kodiak's merge ofmain. It approves only when all of these hold:kodiakhq[bot], the PR is from a fork, and it has theautomergelabelpull_requestrun on the previous head, on this PR's fork branch, was started by someone with write access or by this workflow on an earlier Kodiak updateThe last check is the security boundary. Reviews aren't tied to a commit, and held runs can leave
action_requiredwithout approval (expired after 30 days, cancelled, startup failure). Those runs keep the contributor astriggering_actor, so they fail this check. Any commit the contributor pushes still waits for a maintainer.The job checks out only
.github/scriptsfrom the base branch and never runs PR code. The decision logic is in.github/scripts/kodiak-run-approval.js, with unit tests run from theMainlint job. No changeset: CI only.Not verified yet
GITHUB_TOKENwithactions: writecan callPOST /actions/runs/{id}/approve. Other repos report it works; the first Kodiak update on a first-time contributor's PR will confirm.triggering_actoris recorded after this workflow approves a run. If it isn'tgithub-actions[bot], a second Kodiak update on the same PR is refused and needs a manual click. That fails closed.pull_request_targetby default on December 2, 2026. The event policy that keeps the Claude and Deep review workflows running needs to cover this workflow too.How to reproduce
On
main:automergeoncemainhas moved ahead.maininto the branch, and the new runs show "Approve workflows to run" again.On this branch:
References