From 2fd96a90acecd11a54157036b1094ea17a62beaf Mon Sep 17 00:00:00 2001 From: Matt Miller Date: Sat, 18 Jul 2026 18:50:12 -0700 Subject: [PATCH 1/2] ci: enroll this repo in its own cursor-review and unreviewed-merge gates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit github-workflows ships the org's review panel, unreviewed-merge detector, and AGENTS.md integrity check — and until now consumed none of them: PRs here merged with no AI review and no compliance trail, in the one repo whose files become every other repo's required checks. Adds two thin callers, SHA-pinned like any external consumer (a local uses: path would run the PR's own copy of the reviewer — pinning keeps the panel tamper-proof): - ci-cursor-review.yml — direct pull_request trigger (no label dance; every non-draft PR here is worth a review). CURSOR_API_KEY is already provisioned. - ci-detect-unreviewed-merge.yml — verbatim template copy, renamed because the canonical path hosts the reusable itself. Needs UNREVIEWED_MERGES_TOKEN before it goes green; fails loudly until then. Co-Authored-By: Claude Fable 5 --- .github/workflows/ci-cursor-review.yml | 40 +++++++++++++++++++ .../workflows/ci-detect-unreviewed-merge.yml | 32 +++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 .github/workflows/ci-cursor-review.yml create mode 100644 .github/workflows/ci-detect-unreviewed-merge.yml diff --git a/.github/workflows/ci-cursor-review.yml b/.github/workflows/ci-cursor-review.yml new file mode 100644 index 0000000..6da8561 --- /dev/null +++ b/.github/workflows/ci-cursor-review.yml @@ -0,0 +1,40 @@ +name: CI - Cursor Review + +# Thin caller enrolling THIS repo in its own reusable cursor-review workflow. +# The review logic (panel matrix, judge consolidation, prompts, scripts) lives +# in cursor-review.yml in this same repo, but the caller still pins it by full +# commit SHA like every external consumer: a local `uses: ./...` path would run +# the PR's OWN copy of the reviewer, letting a PR weaken the panel judging it. +# Pinning to a merged main SHA keeps the reviewer tamper-proof; the bump-callers +# workflow keeps the pin fresh (this repo is enrolled in CURSOR_REVIEW_CALLERS). +# +# Unlike sibling callers (label-triggered, applied by tooling), this one runs on +# every non-draft PR directly: changes here propagate into every consumer +# repo's CI, the PR volume is small, and a direct trigger avoids the +# label-application dependency entirely. + +on: + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + +concurrency: + group: cursor-review-pr-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + cursor-review: + if: ${{ !github.event.pull_request.draft }} + permissions: + contents: read + pull-requests: write + uses: Comfy-Org/github-workflows/.github/workflows/cursor-review.yml@fe6b08e278c27ceacf2651cf441d0752ca2e78ee # main (fe6b08e) + with: + # Keep the assets ref in lock-step with the `uses:` ref above. + workflows_ref: fe6b08e278c27ceacf2651cf441d0752ca2e78ee + # No vendored/generated content in this repo; defensive excludes only. + diff_excludes: >- + :!**/*-lock.json + :!**/dist/** + secrets: + CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }} + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} diff --git a/.github/workflows/ci-detect-unreviewed-merge.yml b/.github/workflows/ci-detect-unreviewed-merge.yml new file mode 100644 index 0000000..b377fbb --- /dev/null +++ b/.github/workflows/ci-detect-unreviewed-merge.yml @@ -0,0 +1,32 @@ +# Caller enrolling THIS repo in its own reusable unreviewed-merge detector. +# Named ci-detect-unreviewed-merge.yml because the canonical caller path +# (detect-unreviewed-merge.yml) is occupied here by the reusable itself. +# Otherwise a verbatim copy of the template in +# Comfy-Org/unreviewed-merges/detector/detect-unreviewed-merge.yml. +# +# PREREQUISITE (operator): provision `secrets.UNREVIEWED_MERGES_TOKEN` in this +# repo's settings (see the unreviewed-merges repo README). Until it exists, +# this job fails loudly on pushes to main — deliberately, so enrollment is +# never silently inert. + +name: Detect Unreviewed Merge + +on: + push: + branches: [main] + +concurrency: + group: detect-unreviewed-merge-${{ github.sha }} + cancel-in-progress: false + +permissions: + contents: read + pull-requests: read + +jobs: + detect: + uses: Comfy-Org/github-workflows/.github/workflows/detect-unreviewed-merge.yml@4d9cb6b87f953bb7cd69954280e1465fb9bd2040 # v1 + with: + approval-mode: latest-per-reviewer + secrets: + UNREVIEWED_MERGES_TOKEN: ${{ secrets.UNREVIEWED_MERGES_TOKEN }} From f301ba644068efde9bf1098fbed62b7c98242a23 Mon Sep 17 00:00:00 2001 From: Matt Miller Date: Sat, 18 Jul 2026 18:53:52 -0700 Subject: [PATCH 2/2] ci: label-trigger the self-caller; add run_without_label input to the reusable gate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gate only honors label events, so the self-caller's direct pull_request trigger ran the shell and skipped the panel (verified live on this PR's first push). Two-step fix, pin-ordering aware: - cursor-review.yml gains an opt-in `run_without_label` input (default false — zero behavior change for existing callers): plain PR events (opened/reopened/ready_for_review/synchronize) fire the panel, with the fork skip, skip-cursor-review veto, and same-commit dedupe all still applying. For repos with no labeling automation. - ci-cursor-review.yml switches to the sibling label-triggered shape, which works at its current pin (the pinned SHA predates the new input, so passing it would be an invalid-input error). When the auto-bump advances the pin past this commit, the bump PR should add `run_without_label: true` and widen the trigger types — noted in the file header. Co-Authored-By: Claude Fable 5 --- .github/workflows/ci-cursor-review.yml | 20 +++++++++++++------- .github/workflows/cursor-review.yml | 25 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci-cursor-review.yml b/.github/workflows/ci-cursor-review.yml index 6da8561..26f9028 100644 --- a/.github/workflows/ci-cursor-review.yml +++ b/.github/workflows/ci-cursor-review.yml @@ -8,22 +8,28 @@ name: CI - Cursor Review # Pinning to a merged main SHA keeps the reviewer tamper-proof; the bump-callers # workflow keeps the pin fresh (this repo is enrolled in CURSOR_REVIEW_CALLERS). # -# Unlike sibling callers (label-triggered, applied by tooling), this one runs on -# every non-draft PR directly: changes here propagate into every consumer -# repo's CI, the PR volume is small, and a direct trigger avoids the -# label-application dependency entirely. +# Label-triggered for now (apply `cursor-review` to a PR to fire the panel; +# `skip-cursor-review` vetoes) — the reusable's gate at this pin only honors +# label events. Once the pin advances past the commit adding the reusable's +# `run_without_label` input, the auto-bump PR for this file should also add +# `run_without_label: true` under `with:` and widen the trigger types to +# [opened, reopened, ready_for_review, labeled, unlabeled] — this repo has no +# labeling automation, and every non-draft PR here is worth a review (its +# files become other repos' required checks). on: pull_request: - types: [opened, synchronize, reopened, ready_for_review] + types: [labeled, unlabeled] +# Cancel any earlier in-flight review run for the same PR when cursor-review is +# removed or re-applied. Scoping by label name ensures that removing an +# unrelated label does not kill a running cursor review. concurrency: - group: cursor-review-pr-${{ github.event.pull_request.number }} + group: cursor-review-pr-${{ github.event.pull_request.number }}-${{ github.event.label.name }} cancel-in-progress: true jobs: cursor-review: - if: ${{ !github.event.pull_request.draft }} permissions: contents: read pull-requests: write diff --git a/.github/workflows/cursor-review.yml b/.github/workflows/cursor-review.yml index cd9d447..c575012 100644 --- a/.github/workflows/cursor-review.yml +++ b/.github/workflows/cursor-review.yml @@ -107,6 +107,16 @@ on: type: string required: false default: '' + run_without_label: + description: >- + Run on plain pull_request events (opened / reopened / ready_for_review + / synchronize) instead of requiring the trigger label — for repos with + no labeling automation. The fork skip, the skip-cursor-review label, + and the same-commit dedupe all still apply. Default false + (label-triggered, unchanged for existing callers). + type: boolean + required: false + default: false secrets: CURSOR_API_KEY: description: Cursor API key for cursor-agent (the panel + judge models bill through it). @@ -149,6 +159,7 @@ jobs: GH_EVENT_ACTION: ${{ github.event.action }} HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }} BASE_REPO: ${{ github.repository }} + RUN_WITHOUT_LABEL: ${{ inputs.run_without_label }} run: | # PRs from forks can't run this review. The pull_request event grants # fork PRs no access to secrets — so CURSOR_API_KEY is empty and every @@ -170,6 +181,20 @@ jobs: exit 0 fi + # Label-free mode (run_without_label input): callers in repos with no + # labeling automation opt in to running on plain PR events. Sits + # BELOW the fork skip and skip-cursor-review checks — those still + # veto — and the same-commit dedupe below still prevents re-reviews. + if [ "$RUN_WITHOUT_LABEL" = "true" ]; then + case "$GH_EVENT_ACTION" in + opened|reopened|ready_for_review|synchronize) + echo "run_without_label mode — running on '$GH_EVENT_ACTION'." + echo "should_run=true" >> "$GITHUB_OUTPUT" + exit 0 + ;; + esac + fi + # Only adding the trigger label fires the matrix. Removing it cancels # any in-progress run via the concurrency group and then no-ops here. if [ "$LABEL_NAME" = "$REVIEW_LABEL" ] && [ "$GH_EVENT_ACTION" = "labeled" ]; then