From a002e62e8414ede87315199e66966203ad812317 Mon Sep 17 00:00:00 2001 From: bompus Date: Sat, 24 Oct 2026 22:25:10 -0600 Subject: [PATCH 1/3] Run the private reviewer on every pull request in shadow mode --- .github/workflows/review.yml | 54 ++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .github/workflows/review.yml diff --git a/.github/workflows/review.yml b/.github/workflows/review.yml new file mode 100644 index 0000000000..3af5d15b69 --- /dev/null +++ b/.github/workflows/review.yml @@ -0,0 +1,54 @@ +name: pr-reviewer +# Shadow mode: the review step cannot fail the job. The reviewer code runs from the +# host's primary checkout ($PR_REVIEWER_HOME), not from the pull request. +on: + pull_request: + # labeled/unlabeled: an author: label changes which reviewer runs. + types: [opened, synchronize, reopened, ready_for_review, converted_to_draft, labeled, unlabeled] + +permissions: + contents: read + pull-requests: write + +jobs: + review: + # Same-repository pull requests only. A pull request runs its own copy of this file, + # so this check is a second layer: the enforced guard is the repository setting that + # keeps fork pull requests from running workflows, checked by the runner installer + # (ubuntu/install-pr-reviewer-runner.sh in setupLinuxHost). Only people with access + # to this private repository can fork it. + # Drafts are skipped per step, not here, so converting to draft still starts a job + # that takes the concurrency slot and cancels a review in progress. + if: >- + github.event.pull_request.head.repo.full_name == github.repository && + (!contains(fromJSON('["labeled","unlabeled"]'), github.event.action) || + startsWith(github.event.label.name, 'author:')) + # On the job, not the workflow, so a skipped run (an unrelated label) cancels nothing. + concurrency: + group: pr-reviewer-${{ github.event.pull_request.number }} + cancel-in-progress: true + runs-on: [self-hosted, private-reviewer] + timeout-minutes: 45 + steps: + - if: github.event.pull_request.draft != true + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 0 + persist-credentials: false + - name: Review + if: github.event.pull_request.draft != true + continue-on-error: true + timeout-minutes: 40 + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} + BASE_SHA: ${{ github.event.pull_request.base.sha }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + PR_TITLE: ${{ github.event.pull_request.title }} + PR_BODY: ${{ github.event.pull_request.body }} + PR_LABELS: ${{ toJson(github.event.pull_request.labels.*.name) }} + # Run from the reviewer's own checkout: Bun reads .env and bunfig.toml from its + # working directory, and the pull request's checkout must not configure the reviewer. + run: cd "${PR_REVIEWER_HOME:-$HOME/pr-reviewer}" && CHECKOUT="$GITHUB_WORKSPACE" bun src/review.ts From 19f34d544cea76517a8f772550f04ff81722c508 Mon Sep 17 00:00:00 2001 From: bompus Date: Sat, 24 Oct 2026 22:32:37 -0600 Subject: [PATCH 2/3] Keep private paths out of the workflow and fail loudly when the checkout is unset --- .github/workflows/review.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/review.yml b/.github/workflows/review.yml index 3af5d15b69..1cddc85c77 100644 --- a/.github/workflows/review.yml +++ b/.github/workflows/review.yml @@ -1,6 +1,6 @@ name: pr-reviewer # Shadow mode: the review step cannot fail the job. The reviewer code runs from the -# host's primary checkout ($PR_REVIEWER_HOME), not from the pull request. +# host's configured checkout ($PR_REVIEWER_HOME), never from the pull request. on: pull_request: # labeled/unlabeled: an author: label changes which reviewer runs. @@ -14,9 +14,7 @@ jobs: review: # Same-repository pull requests only. A pull request runs its own copy of this file, # so this check is a second layer: the enforced guard is the repository setting that - # keeps fork pull requests from running workflows, checked by the runner installer - # (ubuntu/install-pr-reviewer-runner.sh in setupLinuxHost). Only people with access - # to this private repository can fork it. + # keeps fork pull requests from running workflows without maintainer approval. # Drafts are skipped per step, not here, so converting to draft still starts a job # that takes the concurrency slot and cancels a review in progress. if: >- @@ -49,6 +47,8 @@ jobs: PR_TITLE: ${{ github.event.pull_request.title }} PR_BODY: ${{ github.event.pull_request.body }} PR_LABELS: ${{ toJson(github.event.pull_request.labels.*.name) }} - # Run from the reviewer's own checkout: Bun reads .env and bunfig.toml from its - # working directory, and the pull request's checkout must not configure the reviewer. - run: cd "${PR_REVIEWER_HOME:-$HOME/pr-reviewer}" && CHECKOUT="$GITHUB_WORKSPACE" bun src/review.ts + # Run from the reviewer's own checkout, which the runner supplies: Bun reads + # .env and bunfig.toml from its working directory, and the pull request's + # checkout must not configure the reviewer. Fail loudly when it is unset rather + # than guessing a path, so a misconfigured runner is visible in the job log. + run: cd "${PR_REVIEWER_HOME:?PR_REVIEWER_HOME is not set on this runner}" && CHECKOUT="$GITHUB_WORKSPACE" bun src/review.ts From b86f4e3c43d09f9b18284d3a2c4ee0c3f7a847ef Mon Sep 17 00:00:00 2001 From: bompus Date: Sat, 24 Oct 2026 23:45:10 -0600 Subject: [PATCH 3/3] Name the shadow review job so it does not name a private project and a gate can recognize it --- .github/workflows/review.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/review.yml b/.github/workflows/review.yml index 1cddc85c77..38716af726 100644 --- a/.github/workflows/review.yml +++ b/.github/workflows/review.yml @@ -1,4 +1,4 @@ -name: pr-reviewer +name: shadow-review # Shadow mode: the review step cannot fail the job. The reviewer code runs from the # host's configured checkout ($PR_REVIEWER_HOME), never from the pull request. on: @@ -12,6 +12,7 @@ permissions: jobs: review: + name: shadow review # Same-repository pull requests only. A pull request runs its own copy of this file, # so this check is a second layer: the enforced guard is the repository setting that # keeps fork pull requests from running workflows without maintainer approval. @@ -23,7 +24,7 @@ jobs: startsWith(github.event.label.name, 'author:')) # On the job, not the workflow, so a skipped run (an unrelated label) cancels nothing. concurrency: - group: pr-reviewer-${{ github.event.pull_request.number }} + group: shadow-review-${{ github.event.pull_request.number }} cancel-in-progress: true runs-on: [self-hosted, private-reviewer] timeout-minutes: 45