From ea2de2dc2b65370be31a3d6115d889304e37ec7e Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Tue, 28 Jul 2026 19:19:33 +0200 Subject: [PATCH] ci(pr-review): label-only manual trigger, thin dispatcher (#23449) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses the review feedback on #23418 (Paul + Copilot + cubic) and switches the manual trigger from comments to **labels**, consistent with the e2e labels. ## What changed - **Manual reviews are label-driven** — add `pr-review-security` / `pr-review-triage` / `pr-review-standard`. Labeling requires write access (team-only). The **`/pr-review` comment trigger is removed.** - Like the e2e labels, a check runs on every push **while its label is present** (the orchestrator reads the PR's current labels each run) — so `pr-review-standard` keeps the deep review current until removed. - **Dispatcher is now dumb** — it forwards only `pr_number`. All resolution + validation lives in the privileged orchestrator (Paul's suggestion: it fetches PR metadata, incl. labels, there anyway). This fixes the bot findings (regex allowlist bypass, `/pr-review`→standard default, delimiter edge cases) at the source. - `cancel-in-progress: true` (latest-push-wins, matching the previous dispatcher). Fires on non-draft PR events (the auto `security,triage` gate) and on `pr-review-*` label adds. ## Depends on A companion change to the privileged CI (reads labels + resolves/validates checks) — merge that first; it's backward-compatible, so nothing breaks in between. --- .github/workflows/pr-review-dispatch.yaml | 60 +++-------------------- 1 file changed, 8 insertions(+), 52 deletions(-) diff --git a/.github/workflows/pr-review-dispatch.yaml b/.github/workflows/pr-review-dispatch.yaml index 5a2d6e39fd7..e3c00d61ee8 100644 --- a/.github/workflows/pr-review-dispatch.yaml +++ b/.github/workflows/pr-review-dispatch.yaml @@ -1,67 +1,25 @@ name: PR Review Dispatch -run-name: "PR Review Dispatch (${{ github.event_name }})" +run-name: "PR Review Dispatch #${{ github.event.pull_request.number }}" on: pull_request_target: types: [ready_for_review, synchronize, labeled] - issue_comment: - types: [created] permissions: {} concurrency: - group: pr-review-dispatch-${{ github.event.pull_request.number || github.event.issue.number }} - cancel-in-progress: false + group: pr-review-dispatch-${{ github.event.pull_request.number }} + cancel-in-progress: true jobs: dispatch: if: > - (github.event_name == 'pull_request_target' && github.event.action != 'labeled' && github.event.pull_request.draft == false) || - (github.event_name == 'pull_request_target' && github.event.action == 'labeled' && startsWith(github.event.label.name, 'pr-review-')) || - (github.event_name == 'issue_comment' && github.event.issue.pull_request != null && startsWith(github.event.comment.body, '/pr-review') && contains(fromJSON('["MEMBER", "OWNER", "COLLABORATOR"]'), github.event.comment.author_association)) + github.event.pull_request.draft == false && + (github.event.action != 'labeled' || startsWith(github.event.label.name, 'pr-review-')) runs-on: ubuntu-latest timeout-minutes: 5 steps: - - name: Resolve target + checks - id: resolve - env: - EVENT_NAME: ${{ github.event_name }} - ACTION: ${{ github.event.action }} - PR_NUMBER: ${{ github.event.pull_request.number }} - ISSUE_NUMBER: ${{ github.event.issue.number }} - LABEL_NAME: ${{ github.event.label.name }} - COMMENT_BODY: ${{ github.event.comment.body }} - run: | - set -euo pipefail - allowed="security triage standard" - is_valid() { printf '%s\n' $allowed | grep -qx "$1"; } - - if [ "$EVENT_NAME" = "issue_comment" ]; then - NUM="$ISSUE_NUMBER" - CHECK=$(printf '%s' "$COMMENT_BODY" | sed -nE 's#^/pr-review[[:space:]]+([a-z]+).*#\1#p' | head -1) - CHECKS="${CHECK:-standard}" - elif [ "$ACTION" = "labeled" ]; then - NUM="$PR_NUMBER" - CHECKS="${LABEL_NAME#pr-review-}" - else - NUM="$PR_NUMBER" - CHECKS="security,triage" - fi - - ok=true - IFS=',' read -ra parts <<< "$CHECKS" - for p in "${parts[@]}"; do is_valid "$p" || ok=false; done - - if [ "$ok" = true ] && [ -n "$NUM" ]; then - echo "pr_number=$NUM" >> "$GITHUB_OUTPUT" - echo "checks=$CHECKS" >> "$GITHUB_OUTPUT" - echo "dispatch=true" >> "$GITHUB_OUTPUT" - else - echo "dispatch=false" >> "$GITHUB_OUTPUT" - fi - - name: Mint ci-privileged dispatch token - if: steps.resolve.outputs.dispatch == 'true' id: app-token uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 with: @@ -71,12 +29,10 @@ jobs: repositories: ci-privileged permission-actions: write - - name: Dispatch to ci-privileged - if: steps.resolve.outputs.dispatch == 'true' + - name: Forward to PR review env: GH_TOKEN: ${{ steps.app-token.outputs.token }} - PR_NUMBER: ${{ steps.resolve.outputs.pr_number }} - CHECKS: ${{ steps.resolve.outputs.checks }} + PR_NUMBER: ${{ github.event.pull_request.number }} run: | gh workflow run pr-review.yaml --repo twentyhq/ci-privileged --ref main \ - -f pr_number="$PR_NUMBER" -f checks="$CHECKS" + -f pr_number="$PR_NUMBER"