From 177295183beef41948787d05cbf72981bae594b3 Mon Sep 17 00:00:00 2001 From: Erik Darling <2136037+erikdarlingdata@users.noreply.github.com> Date: Sat, 25 Jul 2026 11:04:38 -0400 Subject: [PATCH] Add Claude Code PR review workflows claude-code-review.yml runs automatically on every non-draft PR (opened/synchronize/ready_for_review) and posts a top-level comment plus inline comments. The prompt encodes the repo conventions CI cannot check: zero-warning standard, the hand-maintained PlanViewer.Ssms version pair, the linked-source requirement in PlanViewer.Web.csproj, TRY_CAST over TRY_CONVERT, and the security severity calibration for a single-user local install so it does not file loopback issues as High. claude.yml is the on-demand @claude mention workflow. Fork PRs are deliberately excluded from the automatic review: GitHub withholds repository secrets from pull_request runs on forks and issues a read-only token, so the job would fail rather than review. The job is skipped instead of failing a contributor's PR with a red X. The fix is NOT pull_request_target, which would expose a writable token and this repo's secrets to an agent running untrusted fork code. claude.yml covers fork PRs instead - comment events run in the base-repo context, and the action checks the commenter has write access first. Cost/noise controls: concurrency cancels an in-flight review when a second push lands, docs-only changes are filtered out via paths-ignore mirroring ci.yml, drafts are skipped, and --max-turns is capped at 20. Co-Authored-By: Claude Fable 5 --- .github/workflows/claude-code-review.yml | 103 +++++++++++++++++++++++ .github/workflows/claude.yml | 43 ++++++++++ 2 files changed, 146 insertions(+) create mode 100644 .github/workflows/claude-code-review.yml create mode 100644 .github/workflows/claude.yml diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml new file mode 100644 index 0000000..d73366c --- /dev/null +++ b/.github/workflows/claude-code-review.yml @@ -0,0 +1,103 @@ +name: Claude Code Review + +# Automatic review on every PR. Fork PRs are skipped on purpose - see the note +# at the bottom of this file. +on: + pull_request: + types: [opened, synchronize, ready_for_review] + paths-ignore: + - '**.md' + - 'LICENSE' + - '.gitattributes' + - '.gitignore' + - 'CITATION.cff' + - 'llms.txt' + - '.github/ISSUE_TEMPLATE/**' + - 'docs/**' + - 'screenshots/**' + +permissions: + contents: read + pull-requests: write + id-token: write + +# One review at a time per PR; a rapid second push cancels the in-flight run +# instead of paying for two reviews of the same branch. +concurrency: + group: claude-review-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + review: + # Drafts aren't ready for review, and a fork PR gets no secrets (so + # CLAUDE_CODE_OAUTH_TOKEN would be empty) and a read-only token it could + # not post with. Skip rather than fail a contributor's PR with a red X. + if: | + github.event.pull_request.draft == false && + github.event.pull_request.head.repo.full_name == github.repository + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 1 + + - uses: anthropics/claude-code-action@v1 + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + prompt: | + REPO: ${{ github.repository }} + PR NUMBER: ${{ github.event.pull_request.number }} + + Review this pull request. The PR branch is already checked out in + the working directory. + + Performance Studio is a cross-platform Avalonia desktop app (plus a + CLI, a Blazor WASM viewer, and an SSMS extension) that analyzes SQL + Server execution plans. Prioritize, in this order: + + 1. Correctness and crashes - null/empty plan XML, malformed + showplan attributes, off-by-one in operator tree walking. + 2. Untrusted input. Execution plan XML is untrusted (users open + .sqlplan files they were emailed). Any generated T-SQL must stay + inert: identifiers bracket-escaped with ']' doubled, values + emitted only as self-contained literals. Flag string + concatenation into SQL that isn't a SqlParameter. + 3. Security, calibrated to the deployment. This runs on a + single-user personal machine and its MCP tools are read-only, so + loopback-bound, opt-in, or local-IPC issues are Low here. Reserve + High for remotely reachable vectors (missing Host/Origin checks, + DNS rebinding) or credential disclosure. + 4. Repo conventions that CI does not catch: + - The build standard is zero warnings. Flag new warnings and any + new NoWarn that lacks a comment explaining it. + - src/Directory.Build.props is the single source of + truth, but PlanViewer.Ssms is a legacy non-SDK project: its + version must be bumped by hand in + source.extension.vsixmanifest AND Properties/AssemblyInfo.cs. + Flag a version bump that updates one and not the others. + - A PlanViewer.Core file the Blazor app needs must also be added + as a linked in PlanViewer.Web.csproj - a + ProjectReference is deliberately not used. + - T-SQL uses TRY_CAST, never TRY_CONVERT. + 5. Test coverage for the behavior actually changed. + + Be specific and concrete. Skip praise, style nits already handled by + the compiler, and restating what the diff does. If the PR looks good, + say so briefly rather than inventing findings. + + Use `gh pr comment` for top-level feedback. + Use `mcp__github_inline_comment__create_inline_comment` (with + `confirmed: true`) to flag specific lines. + Only post GitHub comments - do not return review text as a message. + + claude_args: | + --max-turns 20 + --allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*)" + +# Fork PRs: GitHub withholds repository secrets from `pull_request` runs on +# forks and issues a read-only GITHUB_TOKEN, so this workflow cannot review +# them. The fix is NOT `pull_request_target` - that would hand a writable token +# and this repo's secrets to an agent running untrusted fork code. To review a +# fork PR, comment `@claude review this` on it (claude.yml), which runs in the +# base-repo context and checks the commenter's write permission first. diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml new file mode 100644 index 0000000..60c2d22 --- /dev/null +++ b/.github/workflows/claude.yml @@ -0,0 +1,43 @@ +name: Claude + +# On-demand: mention @claude in an issue, a PR comment, or a review comment. +# +# Unlike claude-code-review.yml this DOES work on fork PRs: issue_comment and +# review-comment events run in the base-repo context, so secrets are available +# and the token can post. The action verifies the commenter has write access +# before doing anything, so an outside user cannot trigger it. +on: + issue_comment: + types: [created] + pull_request_review_comment: + types: [created] + pull_request_review: + types: [submitted] + issues: + types: [opened, assigned] + +permissions: + contents: write + pull-requests: write + issues: write + id-token: write + +jobs: + claude: + if: | + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) || + (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) || + (github.event_name == 'issues' && contains(github.event.issue.body, '@claude')) + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 1 + + - uses: anthropics/claude-code-action@v1 + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + claude_args: | + --max-turns 20