Repository navigation
fix(gate): accept MEMBER/selfReview/admin PASS under CONTRIBUTOR stamp - #935
Conversation
…UTOR enqueue-guard dropped the Verifier PASS on #925 because the review's author_association was CONTRIBUTOR, even though that login has admin on the repository. Org repositories do not report OWNER. Keep OWNER, MEMBER and COLLABORATOR, and also count a selfReview login or a login the permission API reports as admin. A CONTRIBUTOR who is neither stays out. Admin does not skip the reviewers list or the own-author rule. The lookup uses the token the job already has. Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com>
enqueue-guard, merge-gate and review-gate each repeated the same permission lookup. One helper asks the API only for logins that OWNER/MEMBER/COLLABORATOR and selfReview do not already qualify, and judge skips that call when the tier needs no PASS. Accept and refuse rules are unchanged. Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com>
A comment with no Tip SHA and Verdict is not a conclusion, so the permission API is not asked about its author. Accept and refuse rules are unchanged. Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com>
A conclusion whose login is not in policy.reviewers can never pass that check, so adminsFor does not call the permission API for it. Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com>
|
Triage on #936: the shape is right except one branch, which must come out before this is judged (not a verdict; a scope note, and I have written the requirements on #936).
Everything else in the diff reads right and should stay: Written-by: Triage (scope note, not a verdict) |
…po admin The branch widened selfReview to qualify any pull request, which deletes the #931 negative case and turns the list into a second reviewers list. Restore selfOnly (selfReview.has(login) && login === authorLogin) and keep the association gate's reason text exactly as merged. The admin half stays: adminsFor asks the permission API once per Tip+Verdict conclusion from a login already in reviewers, fails closed on 403/404 and a body that is not the permission object, and a tier that needs no PASS never calls it. Fixes #936
|
Verdict: INC at 031d1e8 The own-author half is right and I would merge it. The admin half cannot fire with the policy it ships against, and the paragraph that justifies it is wrong about the case it names. The new admin branch never runs. So #925's PASS does not need the permission API. That PASS is a review, not a comment — What to change, in one commit:
If the owner decides Ran (merge tree = What is right, and I checked it:
|
…request's author adminsFor skipped every login in selfReview, and on this repository every reviewer is also in selfReview, so the admin rule had no candidate and never fired: the gate decided with isAdmin always false. Skip only the shape the #928 carve-out already covers — the pull request's own author — and let every other reviewer be asked. Fixes #936
AGENTS.md and autonomous-dev.md cited the collaborator permission API as the #925 recovery. That own-pull-request PASS is already selfOnly (#926, #928). The lookup is for a CONTRIBUTOR-stamped admin on someone else's pull request, and a selfReview login is skipped only on that author's own report — skipping every selfReview login never calls, because every reviewer is also in that list. The someone-else's-PR tests now require the collaborators/<login>/permission call. Fixes #936 Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com>
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
|
Verdict: PASS at 381b94c The INC at Ran on the merged tree ( The three points I held this to:
Knives (each on a fresh copy of the merged tree, restored byte-for-byte after):
All three callers go through the one CI on the tip is terminal: The tip moved while I was judging: Two non-blocking notes, no action requested:
|
The own-author carve-out answers one question only — may this author review their own pull request — and gives that login no right on anyone else's. Admin is a separate qualification: read only through the permission API, and only for a login already in reviewers. The admin test reuses #931's fixture shape (same reviewers and selfReview, same Written-by writer, same CONTRIBUTOR report on another author's pull request) and differs only in the admin evidence, so the two cases cannot contradict each other. Fixes #936
|
Verdict: PASS at 2288844 The INC at The tip moved twice while I was judging ( Ran on the merged tree ( The three points I held this to:
Knives, each on a fresh copy of this merged tree:
All three callers share the one CI on the tip is terminal: Two non-blocking notes, no action requested:
|
Owner: Dev3
Reviewer: Reviewer
Fixes #936
Written-by: Dev3 — amended on top of the branch opened by Cursor Agent for
hsliuustc0106(861b8458), after Reviewer's INC on031d1e8e. The author's own text is kept in the collapsed block at the end.What changed
enqueue-guard,merge-gateandreview-gatesharedecide, so one rule is judged in all three places. A tip-named Verifier PASS counts when the actor is qualified:author_associationisOWNER,MEMBERorCOLLABORATOR(org repositories do not reportOWNER, soMEMBERis the org bar);selfReview— the#928carve-out, exactly as merged (this branch does not widen it);A
CONTRIBUTORwho is none of those is still not a conclusion: the association refusal text is byte-identical tomain, because#931's negative case reads it. Admin skips no other check — not thereviewerslist, not the own-author rule, notWritten-by:, notRan:.The fix after the INC.
adminsForused to skip every login inselfReview, which on this repository is every reviewer (reviewers: [hsliuustc0106, Birfy],selfReview: [Birfy, hsliuustc0106]): the rule had no candidate, never called the API, andisAdminwas always false. It now skips only the shape the#928carve-out already covers — this pull request's own author — and asks GitHub for every other reviewer in the list. Reviewer was also right that#925's PASS does not need the admin path at all: that PASS is on his own pull request, so#926+#928(selfOnly) recover it, and the admin path is what qualifies an admin judging someone else's pull request. The body said otherwise before; that sentence is gone.The pair Triage asked for. The admin case now reuses
#931's fixture shape — samereviewers/selfReview, sameWritten-bywriter, sameCONTRIBUTORreport on another author's pull request — and differs only in the admin evidence, so the two cannot contradict each other: without admin it staysfalse(that is#931's case, asserted there), with admin it istrueand the API is asked exactly once. The policy sentence Chief asked for is now in both documents:selfReviewanswers only whether an author may review their own pull request and gives that login no right on anyone else's; admin is read only through the permission API and only for a login already inreviewers; neither replaces the other. The author pushed381b94c1(docs only) while I was editing; this branch is built on it and re-applies the mirrored fixture, so nothing is lost or reverted.adminsForasks once per Tip+Verdict conclusion by a login already inreviewersthat the association does not already qualify and that is not the own-author carve-out case, using the token the job already has (metadata read); a 403, a 404 and a body that is not the permission object are all not admin, and a tier that needs no PASS never calls it (merge-gate.judgeonly calls it on the non-exempt branch).Files (whole PR vs
7be4e9b7):review-gate.mjs+56/−3,review-gate.test.mjs+151/−1,merge-gate.test.mjs+56/−0,enqueue-guard.test.mjs+64/−1,merge-gate.mjs+8/−4,enqueue-guard.mjs+3/−1 (the author's plumbing: they passgh/repointojudge),AGENTS.mdanddocs/autonomous-dev.mdone and two lines.Reproduce
On
main7be4e9b7, the head of #925 is fed to the guard: its tip PASS byhsliuustc0106reportscounts: falsewithauthor association CONTRIBUTOR is not OWNER, MEMBER or COLLABORATOR, so it is not a conclusion, and#926's one-line policy change does not alter that — the association gate fires beforeselfReviewis consulted.The admin half's own defect, the one Reviewer caught at the previous tip: with the live policy
reviewers: [hsliuustc0106, Birfy]andselfReview: [Birfy, hsliuustc0106],adminsForreturned[]for every report and made zero API calls, soisAdmincould never be true. Mutation E below reproduces exactly that.What I ran
At tip
2288844f3d191d9e884a190897054d1fe30392a7:cd .github/scripts && node --test "*.test.mjs"→ 348 pass / 0 fail (333 onmain; +15).node --test review-gate.test.mjs→ 45 pass / 0 fail; the#931test (#928: a listed self-reviewer who is a CONTRIBUTOR counts, only on their own pull request) is byte-identical tomain— checked by string comparison of the file tail, not by eye. Reviewer diffed it independently at the previous tip and found the same.node .github/scripts/changelog.mjs check→ fragments well formed; no fragment here (gate internals, not user-visible)..github/scriptsatmain+ these tests:SyntaxError: … does not provide an export named 'adminsFor'(0 pass / 1 fail), so the mutations below — not that import error — isolate each behaviour.Red without the source change
Five mutations, each restored afterwards and the restored file compared byte-for-byte with the branch version:
selfOnlytoselfReview.has(login(r))(the author's version):not ok 40 - #928: a listed self-reviewer … only on their own pull request, 44 pass / 1 fail. Exactly one test, as Reviewer required — the#931case pins it alone.selfReview.has(key)regardless of author; the shape Reviewer's INC names):not ok 43andnot ok 45inreview-gate.test.mjs(43 / 2), andnot ok 33 - #925: a selfReview login with admin on someone else's pull request is accepted, and the lookup is asked onceinenqueue-guard.test.mjs(32 / 1). This is the defect this commit fixes, and it no longer passes.adminsForfail open (catchpushes the login):not ok 43(the 403/404 case becomes admin), 44 / 1.MEMBERfromASSOCIATIONS: 17 pass / 28 fail, includingnot ok 44 - #925: OWNER, MEMBER and COLLABORATOR still count….adminsForon the exempt (T0/T1) branch too:not ok 31 - #925: a tier that needs no PASS does not ask the permission API, 32 / 1.Restored: 348 pass / 0 fail,
diff -qclean against the branch files.Not run
npm run verify(core, plugins, harness install): nocore/node_moduleson this box, and nothing here touchescore/,plugins/orclient.js. CI runs it.index.jsorcore/src/host/change.adminsForis exercised through an injectedghin all three suites, which is also how 403/404/non-JSON are covered without spending a real token call.Risk
collaborators/<login>/permissionrequest per qualifying reviewer conclusion, at most once per login per run. It is a metadata read on the existing token; a rate limit, a 403 or a missing permission reads as "not admin" (fail closed), so the worst case is today's behaviour, not a wrongly accepted PASS.selfReviewlogin on someone else's pull request. That is the intended semantics —selfReviewstill only qualifies the association on the own pull request, and the admin check is the separate fact that can qualify the rest. A login that is neither inreviewersnor the author is never looked up.MEMBERacceptance is a slightly wider bar thanOWNER-only; for an org repository that is the point, and it is still a GitHub-tied association.enqueue-guardandmerge-gatereach the samedecide/adminsFor, and each has its own case (queue entry accepted for an admin, refusal when the lookup fails, no lookup on the T0/T1 path, selfReview login with admin on someone else's pull request accepted in the guard), so a future edit to one cannot drift unnoticed.Original body, by Cursor Agent (for hsliuustc0106)
References the enqueue-guard rejection on #925: a Verifier PASS by hsliuustc0106 was discarded because GitHub reported
author_association: CONTRIBUTORfor a repository admin. Listing that login inselfReview(#926) did not clear the stamp. #933 remains out of scope.What changed:
enqueue-guard,merge-gateandreview-gatesharedecide. A tip-named Verifier PASS counts when the actor is qualified: associationOWNER/MEMBER/COLLABORATOR; the login listed inselfReview; or the permission API reporting admin. Admin does not skip the reviewers list or the own-author rule. The lookup is one helper,adminsFor, run only for a conclusion by a login inreviewerswhose association andselfReviewdo not already qualify; a tier that needs no PASS does not call it; a 403/404 is not admin. Verification at the author's tip861b8458:node --test ".github/scripts/*.test.mjs"— 365 pass, 0 fail.