From 1953285cb6db7e22fb4dcc668e1eeb10a0dca190 Mon Sep 17 00:00:00 2001 From: Than Tibbetts Date: Thu, 28 May 2026 11:35:05 -0400 Subject: [PATCH] ci: add Claude Code reviewer + @claude responder - claude-code-review.yml: auto-reviews PRs (anthropics/claude-code-action@v1) with a Laravel/Pest-focused prompt, including a guard for the server-authoritative play API (clients must never influence payout). Reads prior review comments on re-reviews so it builds on past feedback instead of repeating itself, and reads referenced issues for context. - claude.yml: responds to @claude mentions (restricted to repo owner/member/collaborator). Requires the CLAUDE_CODE_OAUTH_TOKEN repo secret. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/claude-code-review.yml | 85 ++++++++++++++++++++++++ .github/workflows/claude.yml | 52 +++++++++++++++ 2 files changed, 137 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..d0b7767 --- /dev/null +++ b/.github/workflows/claude-code-review.yml @@ -0,0 +1,85 @@ +name: Claude Code Review + +on: + pull_request: + types: [opened, synchronize, ready_for_review, reopened] + +jobs: + claude-review: + if: github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]' + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + issues: read + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Run Claude Code Review + id: claude-review + 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 }} + + You are an expert Laravel code reviewer. Read CLAUDE.md first — it defines the project stack, versions, conventions, and architecture (Laravel + Livewire + Tailwind + Pest). Every review comment must be grounded in those standards and in composer.json for exact versions. + + This is the backend for Git Slot Machine: a public leaderboard site plus the play-recording API. The play API is intentionally **server-authoritative** — `PlayController` recomputes the pattern and payout from the commit hash via `App\Services\PatternDetector` and never trusts client-supplied pattern/payout. Treat any change that would let a client influence its own payout, bypass that server-side computation, or otherwise game the leaderboard as a serious correctness/security issue. + + If the PR body references issues (e.g., "Closes #N"), read them with `gh issue view N` for context before reviewing. + + If this PR already has prior review comments (a re-review after new commits), read them with `gh pr view ${{ github.event.pull_request.number }} --json comments` and treat them as context. Acknowledge or build on what previous reviews said and how the author responded — don't re-flag points that were already addressed, and don't restate issues the author pushed back on without engaging with their reasoning. + + Review this PR with the rigor of a senior Laravel engineer. Focus on: + + **Laravel & PHP quality:** + - Correct Eloquent use (relationships, eager loading, no N+1, no raw `DB::` unless justified) + - Form Requests for validation (not inline in controllers) + - Return type declarations and parameter type hints on all methods + - Modern PHP used appropriately (constructor promotion, enums, match) + - Config via `config()` not `env()` outside config files + - Named routes with `route()` for URL generation + - Queued jobs for heavy/slow operations (e.g. Browsershot image generation) + + **Architecture & conventions:** + - Follows the existing directory structure and naming (check sibling files) + - Controllers stay thin; pattern/scoring logic stays in the shared service so the CLI and server agree + - No new dependencies without clear justification + - Migrations are safe and repeat all column attributes when modifying + + **Security:** + - No mass-assignment, SQL injection, or SSRF vectors + - No XSS in Blade (`{{ }}` not `{!! !!}` unless justified) + - Public/unauthenticated endpoints validate and rate-appropriately; user-supplied content runs through the profanity filter / moderation where relevant + - OWASP Top 10 awareness + + **Testing (Pest):** + - Every change has corresponding Pest tests in tests/Feature or tests/Unit + - Tests use model factories (check for existing factory states before manual setup) + - Happy paths, failure paths, and edge cases covered + - Assertions use specific helpers (assertForbidden, assertNotFound) over assertStatus(...) + + **Code style:** + - Curly braces on all control structures + - PHPDoc blocks preferred over inline comments + - Descriptive names (isRegisteredForDiscounts, not discount()) + + **What NOT to flag:** + - Features or refactors beyond the PR's stated scope + - Formatting that Pint handles + - Intentional design decisions documented in CLAUDE.md + + Be direct and constructive. If the PR is solid, say so briefly — don't invent issues. If there are real problems, be specific about what is wrong and what the fix should be. + + IMPORTANT: Do NOT use #N (e.g. #1, #2, #3) to number your feedback items — GitHub auto-links #N to issue numbers. Use bullet points, letters (a, b, c), or descriptive headers instead. + + Use `gh pr comment` with your Bash tool to leave your review as a comment on the PR. + + claude_args: '--model opus --allowed-tools "Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*),Bash(php artisan test:*),Bash(vendor/bin/pint:*)"' diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml new file mode 100644 index 0000000..91be7d0 --- /dev/null +++ b/.github/workflows/claude.yml @@ -0,0 +1,52 @@ +name: Claude Code + +on: + issue_comment: + types: [created] + pull_request_review_comment: + types: [created] + issues: + types: [opened, assigned] + pull_request_review: + types: [submitted] + +jobs: + claude: + if: | + ( + github.event.sender.login == github.repository_owner || + github.event.comment.author_association == 'OWNER' || + github.event.comment.author_association == 'MEMBER' || + github.event.comment.author_association == 'COLLABORATOR' || + github.event.issue.author_association == 'OWNER' || + github.event.issue.author_association == 'MEMBER' || + github.event.issue.author_association == 'COLLABORATOR' || + github.event.review.author_association == 'OWNER' || + github.event.review.author_association == 'MEMBER' || + github.event.review.author_association == 'COLLABORATOR' + ) && ( + (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') || contains(github.event.issue.title, '@claude'))) + ) + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + issues: write + id-token: write + actions: read + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Run Claude Code + id: claude + uses: anthropics/claude-code-action@v1 + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + additional_permissions: | + actions: read