mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[PR #343] [MERGED] fix(cursor-review): close four ways a stale or unearned auto-approval keeps counting #344
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#344
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/343
Author: @mattmillerai
Created: 10/6/2026
Status: ✅ Merged
Merged: 10/6/2026
Merged by: @mattmillerai
Base:
main← Head:matt/be-19297-auto-approve-gaps📝 Commits (3)
fed980ffix(cursor-review): close four ways a stale or unearned auto-approval keeps counting74c7386fix(cursor-review): read approval staleness from the PR's live head and base53dfd3cMerge origin/main: reconcile #342's reviewed-SHA anchor with the base record📊 Changes
9 files changed (+699 additions, -101 deletions)
View changed files
📝
.github/cursor-review/README.md(+1 -1)📝
.github/cursor-review/auto-approve.py(+171 -56)📝
.github/cursor-review/tests/test_auto_approve.py(+199 -12)➕
.github/detect-unreviewed-merge/tests/approval.test.cjs(+102 -0)📝
.github/workflows/cursor-review.yml(+76 -18)📝
.github/workflows/detect-unreviewed-merge.yml(+48 -4)➕
.github/workflows/test-detect-unreviewed-merge.yml(+27 -0)📝
docs/callers/cursor-review.md(+62 -10)📝
docs/callers/detect-unreviewed-merge.md(+13 -0)📄 Description
Closes four gaps in the opt-in auto-approve added by #340. In each one, a bot approval that is stale or was never earned keeps counting on rulesets with
dismiss_stale_reviews_on_push: false. A review panel found them on the first caller to enableapprove_max_severity. Until this merges, callers should not set that input.Changes
dismiss-stale-approvalused to requireinputs.approve_max_severity != ''. It now runs for every same-repopull_requestevent of an open PR. It only acts on reviews that have the auto-approve marker and come from the approver identity. On a repo that never auto-approved, it lists the reviews, finds none of its own, and does nothing.BOT_APP_PRIVATE_KEYis present (the sameBOT_CONFIGUREDpatternover-cap-commentuses). Without this, everybot_app_idcaller would get a red job on Dependabot pushes, which don't receive Actions secrets. Ifbot_app_idis set but the key is missing, the job runs read-only with an empty approver login: it dismisses nothing, and it goes red if any stale marked approval exists. More generally, a stale marked approval by any login the run can't act as goes red instead of passing unchecked. That coversAPPROVER_TOKENbeing unavailable on a Dependabot PR and a rotated approver identity.dismiss-staledismisses any marked approval whose recorded SHA isn't the live head, or whose recorded base differs from the live base. A retarget therefore dismisses the on-head approval too: the head didn't move, but the diff did.synchronize/reopened/edited. Any event in the same concurrency slot can cancel an in-flight dismissal. Because staleness comes from live state, whichever run comes next redoes it.editedwithchanges.basestill passes--all-approvals, for approvals posted before the base was recorded.dismiss-stalefalls back to the event's head (--head-sha, kept from #342) and skips the base check for that run; the next event redoes it from live state. With no event head either, or if the reviews can't be listed, it prints a clean::error::instead of a traceback.decidetakes--base-ref(the round's base). It refuses to approve if the base was retargeted mid-round, and the post-write re-read withdraws the review if the head or base moved.decidereads the reviewed diff (--reviewed-diff /tmp/pr-diff.patch, the same artifactpost-reviewalready downloads). If it has no@@content hunk, the round counts as untrusted: no review is posted and earlier approvals are withdrawn. That covers diffs that are empty or fully excluded bydiff_excludesor the generated-file classifier, plus pure renames, mode changes and binary-only changes. A missing patch is treated the same way (fail closed).detect-unreviewed-mergecan ignore automated approvers. Newignore-approversinput: logins separated by whitespace or commas, case-insensitive,[bot]suffix included. Reviews by those logins are removed before bothany-approvalandlatest-per-reviewercheck for an approval. When the list is set, a review with no usable login (a deleted account) doesn't count either. A warning fires when every counted approval came from aBotaccount. The input defaults to'', so existing callers see no change.Docs:
docs/callers/cursor-review.md:types:now includesreopenedandedited;approve_max_severity;editeddoesn't cancel a panel on widened callers;ignore-approvers.docs/callers/detect-unreviewed-merge.md: inputs-table row and a section on automated approvers..github/cursor-review/README.md: row updated.Tests
.github/cursor-review/tests/test_auto_approve.py:reviewed_diff_is_emptyon empty, rename, binary and missing patches;BASE_FROMredoes a cancelled retarget dismissal, using the recorded base;if:doesn't mentionapprove_max_severityor filter by action, requires an open PR, and thatdecidegets--base-ref..github/detect-unreviewed-merge/tests/approval.test.cjsplustest-detect-unreviewed-merge.yml. The test runs the shipped github-script, extracted by sentinels the same way the assign-reviewers harness does it, against API fixtures in both modes. Also covered: a review with no usable login, and the bot-only warning. A mutation check (removing the filter) made 4 of the original 11 tests fail.Verified locally, all green:
check_workflow_pins.py;check_agents_md.py;shellcheckon the extracted dismiss step.Residual
reopenedandeditedto itstypes:;ignore-approversto itsdetect-unreviewed-mergecaller.pull_requestruns the caller from the PR head, so a commit can removesynchronize(or the caller itself) and no dismissal runs. This is documented, not fixed, as the ticket asked. Closing it needs a dismiss-onlypull_request_targetjob driven by base-controlled code.APPROVER_TOKENorbot_app_idwhile approvals are live, the new identity can't dismiss the old identity's approvals. The job goes red on the next stale one until someone dismisses it by hand. This is documented in the guide.editedrun. None exist yet, since no caller is enabled.Provenance
check_workflow_pins.py,check_agents_md.pyand the org-repo-literal lint passshellcheckon the extracted dismiss step, and a YAML parse of both changed workflowssynchronize/reopened/edited🤖 Generated with Claude Code
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.