mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[PR #347] [MERGED] fix(cursor-review): treat an edited auto-approval as stale #346
Labels
No labels
cursor-review-catalog-drift
groom
groom
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Comfy-Org/github-workflows#346
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/Comfy-Org/github-workflows/pull/347
Author: @mattmillerai
Created: 10/6/2026
Status: ✅ Merged
Merged: 10/7/2026
Merged by: @mattmillerai
Base:
matt/dismiss-stale-live-head← Head:matt/distrust-edited-approvals📝 Commits (5)
39baaccfix(cursor-review): treat an edited auto-approval as stale72a06a8Merge matt/dismiss-stale-live-head into matt/distrust-edited-approvals88a49f0fix(cursor-review): dismiss a marker-stripped edited approval; fail closed on a short reviews read5b8860cMerge origin/matt/dismiss-stale-live-head into matt/distrust-edited-approvalsdc0a98cMerge origin/matt/dismiss-stale-live-head into matt/distrust-edited-approvals📊 Changes
2 files changed (+351 additions, -60 deletions)
View changed files
📝
.github/cursor-review/auto-approve.py(+152 -36)📝
.github/cursor-review/tests/test_auto_approve.py(+199 -24)📄 Description
ELI5
A robot reviewer approves a pull request and writes down, inside its own comment, which commit it approved — and a separate job withdraws the approval once that commit is no longer the latest. The problem is that anyone with write access to the repo can edit that comment and change the number, which makes the approval look current forever. This reads an extra flag GitHub keeps — "has this comment been edited?" — and refuses to trust an approval that someone has touched.
Motivation
A cursor-review panel thread on #342 — fix(cursor-review): judge auto-approval staleness by the reviewed SHA — flagged this when that PR moved the staleness anchor out of the server-controlled
commit_idand into the review body. The body is mutable:PATCH /repos/{owner}/{repo}/pulls/{pr}/reviews/{id}is available to the review's author, and GitHub lets write-access collaborators edit comments they did not write. The beneficiary is the PR author, and the prize is a standing approval that survives every later push — which is the entire thingdismiss-staleexists to deny. The thread also proposed cross-checkingcommit_id, which does not work here: for an approval GitHub advancescommit_idto each new head, so a forged body marker pointing at the current head satisfies that check too.lastEditedAtis the one signal that separates a review this workflow wrote from one somebody has since altered.Provenance
python3 -m unittest discover -s .github/cursor-review/tests -p 'test_*.py'→ 873 tests OK at the current head (#346's base, including #345's round cap, merged in).workflow-pinsunittest suite,check_workflow_pins.py,check_agents_md.py --root .andcheck-org-repo-literals.sh→ clean.list_reviewsover #342 read every review, with ids past 2^31-1 and the bot asgithub-actions[bot], same as REST.[bot]restoration; withoutsubmittedAt/urlthe round-cap end-to-end test fails._stale_approvals(off-head test) rather than the old keep-condition, because the base reworked that filter.ValueError) where it used to return a partial list.list_reviews, so the query now fetchessubmittedAtandurlas well (mapped tosubmitted_at/html_url).Reviewer context
dismiss-stalecmd_dismiss_staleand its reviews list. Review #346 first; this PR's own changes are its two non-merge commits, plus the GraphQL field adaptation in its latest merge of #346. GitHub retargets this tomainwhen #346 merges. Both are leftovers from #342's review.PUT …/reviews/{id}/dismissals), which is why the list has to keep carrying a REST id rather than a node id.Summary
list_reviewsnow reads GraphQL and returns the same REST shape its callers already expect (withdraw,dismiss-stale, and the base's round cap, which needssubmitted_atandhtml_url), plus aneditedflag.lastEditedAthas no REST equivalent on/pulls/{n}/reviews, which is the only reason for the switch.[bot]suffix is restored from__typename(GraphQL drops it, and--approver-logincarries it, so the identity match would have gone silently dead), and the id is read fromfullDatabaseIdbecause live review ids are past 2^31-1 whiledatabaseIdis typedInt.pullRequestorreviewsconnection, ahasNextPagepage with no new cursor, a response body of the wrong JSON shape, and a review with no id. Returning a partial list instead would read as "nothing to dismiss" and exit green, and since reviews come back oldest-first, a truncated read drops the newest approval.Test plan
unittest + shellcheckjob green on this PRsynchronizedismisses it and the job stays green🤖 Generated with Claude Code
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.