Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 64 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# code-reviewer

AI-powered code review CLI for GitLab merge requests. Uses Vertex AI (Gemini, Claude, Mistral) to analyze diffs and post actionable findings as inline comments or summary notes.
AI-powered code review CLI for GitHub pull requests and GitLab merge requests. Uses Vertex AI (Gemini, Claude, Mistral) or any OpenAI-compatible endpoint to analyze diffs and post actionable findings as inline comments.

## Install

Expand Down Expand Up @@ -45,6 +45,12 @@ cd code-reviewer && go build -o code-reviewer ./cmd/code-reviewer
- **Fix mode** — `--fix` applies suggested code fixes directly to the working tree (v0.5.0)
- **Pre-push hook** — `code-reviewer hook install` sets up automatic review before `git push` (v0.5.1)
- **Configurable** — CLI flags, env vars, per-repo `.code-reviewer.yaml`, or `REVIEW.md`
- **GitHub support** — Full PR review integration: inline comments, code suggestions, previous review cleanup (v0.6.0)
- **Code suggestions** — AI-generated fix suggestions rendered as platform-native suggestion blocks (v0.6.0)
- **Multi-line comments** — Findings can span line ranges for more precise feedback (v0.6.0)
- **Description update** — `--update-description` injects review summary into MR/PR description with idempotent markers (v0.6.0)
- **Review cleanup** — `--cleanup-mode` controls how previous bot reviews are handled: `delete` (default) or `resolve` (v0.6.0)
- **GitLab Draft Notes** — Reviews posted as draft notes and published atomically for a single notification (v0.6.0)

## Quick Start

Expand Down Expand Up @@ -114,6 +120,45 @@ code-review:

See [`.gitlab-ci.example.yml`](.gitlab-ci.example.yml) for the full setup.

### GitHub Actions

Add to `.github/workflows/code-review.yml`:

```yaml
name: Code Review
on:
pull_request:
types: [opened, synchronize]

jobs:
review:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
pull-requests: write
Comment thread
coderabbitai[bot] marked this conversation as resolved.
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
service_account: ${{ secrets.WIF_SA }}

- name: Install code-reviewer
run: go install github.com/OpticDiff/code-reviewer/cmd/code-reviewer@v0.6.0

- name: Review PR
env:
GOOGLE_CLOUD_PROJECT: ${{ secrets.GCP_PROJECT }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: code-reviewer --ci
Comment thread
coderabbitai[bot] marked this conversation as resolved.
```

The `GITHUB_TOKEN` is provided automatically by GitHub Actions. The tool detects the GitHub environment and posts review comments on the PR.
Comment on lines +127 to +160

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Git status/stat:\n'
git diff --stat || true
printf '\nRelevant README/CI-SETUP excerpts:\n'
for f in README.md docs/CI-SETUP.md; do
  if [ -f "$f" ]; then
    echo "---- $f ----"
    wc -l "$f"
    sed -n '110,210p' "$f" | sed -n '1,70p'
  else
    echo "missing $f"
  fi
done

printf '\nSearch for repository/CI setup guidance around forks/settings:\n'
rg -n "fork|Fork|read-only|permission|pull-requests: write|security-events: write|GITHUB_TOKEN" README.md docs/CI-SETUP.md .

Repository: OpticDiff/code-reviewer

Length of output: 8498


🌐 Web query:

GitHub Actions pull_request forks write token permissions fork repository pull_requests read only

💡 Result:

When a GitHub Actions workflow is triggered by a pull request from a forked repository using the pull_request event, GitHub automatically adjusts the permissions of the GITHUB_TOKEN to read-only [1][2]. This restriction is a critical security measure to prevent unauthorized users from escalating privileges or accessing repository secrets [3][4]. Key details regarding this behavior include: 1. Automatic Downgrade: For workflows triggered by a pull request from a fork, any write permissions explicitly configured in the workflow file are downgraded to read-only [2][5]. This applies to pull_request, pull_request_review, and pull_request_review_comment events [2][5]. 2. Secret Access: Workflows triggered by pull_request from a fork do not have access to repository or organization secrets [1][3]. 3. Repository Settings: Maintainers can control these behaviors through the repository's Actions settings: - Send write tokens to workflows from pull requests: If enabled, this allows fork pull requests to use a GITHUB_TOKEN with write permissions [1]. This should be used with extreme caution [6]. - Require approval for fork pull request workflows: This policy can force workflows from non-collaborators to wait for approval from someone with write access before running [1]. 4. The pull_request_target Event: Unlike the standard pull_request event, pull_request_target runs in the context of the base repository and is granted access to secrets and a read/write GITHUB_TOKEN [3][4]. Because this event runs with elevated trust, it is a frequent target for exploitation (often called pwn requests) [7][6]. It is highly recommended never to check out, build, or run untrusted code from a fork when using this trigger [3][8][6]. Recent security updates (as of June 2026) have introduced stricter defaults for actions/checkout to prevent insecure checkouts of fork code in these workflows [7]. For secure automation, it is recommended to separate build and reporting tasks. Use a pull_request workflow (read-only, no secrets) to build and test code, and use a separate, restricted workflow triggered by other means (e.g., workflow_run) or with careful validation in pull_request_target to handle tasks requiring write access or secrets [4][8][6].

Citations:


Document the fork PR token limitation in the GitHub workflows.

pull_request workflows from forks receive read-only GITHUB_TOKEN permissions by default, so the pull-requests: write and SARIF security-events: write workflows will fail unless the repository explicitly allows write tokens for forks—a security-sensitive setting. Address this at:

  • README.md#L127-L159
  • docs/CI-SETUP.md#L127-L154
  • docs/CI-SETUP.md#L163-L200

Consider documenting the fork limitation or moving trusted PR-writing tasks to a separately secured design/workflow instead.

📍 Affects 2 files
  • README.md#L127-L159 (this comment)
  • docs/CI-SETUP.md#L127-L154
  • docs/CI-SETUP.md#L163-L200
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 127 - 159, Document the fork pull-request limitation
for the GitHub workflows: in README.md lines 127-159 and docs/CI-SETUP.md lines
127-154 and 163-200, explain that fork-triggered pull_request workflows receive
read-only GITHUB_TOKEN permissions by default, so pull-requests: write and
security-events: write actions fail unless write tokens for forks are explicitly
enabled, and note the associated security risk or recommend a separately secured
trusted workflow.


## Configuration

Settings are applied in priority order: **CLI flags > env vars > `.code-reviewer.yaml` > defaults**.
Expand All @@ -122,7 +167,7 @@ Settings are applied in priority order: **CLI flags > env vars > `.code-reviewer

| Flag | Description | Default |
|---|---|---|
| `--ci` | Run in GitLab CI mode | — |
| `--ci` | Run in CI mode (auto-detects GitHub/GitLab) | — |
| `--diff [ref]` | Review local git diff | `origin/HEAD` |
| `--files f1,f2` | Review specific files | — |
| `--model` | Vertex AI model ID | `gemini-2.5-flash` |
Expand Down Expand Up @@ -150,6 +195,8 @@ Settings are applied in priority order: **CLI flags > env vars > `.code-reviewer
| `--no-intent` | Disable intent-aware review (overrides CI default) | `false` |
| `--explain` | Explain the diff instead of reviewing it | `false` |
| `--fix` | Apply suggested fixes to the working tree | `false` |
| `--update-description` | Inject review summary into MR/PR description | `false` |
| `--cleanup-mode` | How to handle previous reviews: `delete` or `resolve` | `delete` |
| `--version` | Print version and exit | — |
| `hook install` | Install a pre-push git hook | — |
| `hook uninstall` | Remove the pre-push git hook | — |
Expand Down Expand Up @@ -177,6 +224,9 @@ Settings are applied in priority order: **CLI flags > env vars > `.code-reviewer
| `REVIEW_API_URL` | OpenAI-compatible API endpoint | — |
| `REVIEW_API_KEY` | API key for HTTP provider | — |
| `NO_COLOR` | Disable ANSI colors ([no-color.org](https://no-color.org)) | — |
| `GITHUB_TOKEN` | GitHub API token (auto-set in GitHub Actions) | Required for GitHub |
| `CODE_REVIEWER_UPDATE_DESCRIPTION` | Update MR/PR description with summary | `false` |
| `CODE_REVIEWER_CLEANUP_MODE` | Previous review cleanup mode | `delete` |

### Per-Repo Config

Expand All @@ -196,6 +246,8 @@ extra_rules: |
Check that zerolog is used instead of log/fmt.
max_tokens: 50000 # Optional: cap total tokens per review
api_url: http://localhost:11434/v1 # Optional: use a self-hosted model
update_description: false # Inject summary into MR/PR description
cleanup_mode: delete # delete or resolve
```

See [`.code-reviewer.example.yaml`](.code-reviewer.example.yaml) for all options.
Expand Down Expand Up @@ -295,7 +347,7 @@ Also works with the [pre-commit](https://pre-commit.com) framework:
```yaml
# .pre-commit-config.yaml
- repo: https://github.com/OpticDiff/code-reviewer
rev: v0.5.1
rev: v0.6.0
hooks:
- id: code-review
stages: [pre-push]
Expand Down Expand Up @@ -378,6 +430,13 @@ gcloud auth application-default login
| `CI_JOB_TOKEN` | Notes API (simple comments) | Automatic, zero config |
| Project Access Token | Notes + Discussions API (inline diff) | Settings → Access Tokens, `api` scope |

### GitHub API

| Token Type | Capabilities | Setup |
|---|---|---|
| `GITHUB_TOKEN` (Actions) | PR review comments, suggestions | Automatic in GitHub Actions |
| Personal Access Token | PR reviews outside CI | `repo` scope required |

## Context Window Handling

Large MRs may exceed the model's context window. The `--chunk-strategy` flag controls behavior:
Expand Down Expand Up @@ -419,8 +478,8 @@ CI runs **build**, **test**, and **lint** as 3 parallel jobs. [CodeRabbit](https
Releases are automated via [GoReleaser](https://goreleaser.com). Tag a version to publish binaries to GitHub Releases:

```bash
git tag -a v0.5.1 -m "v0.5.1"
git push origin v0.5.1
git tag -a v0.6.0 -m "v0.6.0"
git push origin v0.6.0
# → GitHub Actions: test → build 6 binaries → publish to Releases
```

Expand Down
86 changes: 57 additions & 29 deletions docs/CI-SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,49 @@ GitLab CI automatically sets these variables in MR pipelines:

## GitHub Actions

While code-reviewer's VCS integration targets GitLab, the `--diff` mode works anywhere. Use it in GitHub Actions to get review output as a PR comment:
code-reviewer has native integration with GitHub Pull Requests. It automatically detects the GitHub Actions environment, uses the provided `GITHUB_TOKEN` to authenticate, and posts findings as inline comments and PR summaries.

### Standard Setup

```yaml
name: Code Review
on:
pull_request:
types: [opened, synchronize]

jobs:
review:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
pull-requests: write # Required to post PR comments
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
service_account: ${{ secrets.WIF_SA }}

- name: Install code-reviewer
run: go install github.com/OpticDiff/code-reviewer/cmd/code-reviewer@v0.6.0

- name: Review PR
env:
GOOGLE_CLOUD_PROJECT: ${{ secrets.GCP_PROJECT }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: code-reviewer --ci
```

### GitHub Code Scanning (SARIF)

If you want findings to show up in the GitHub Security tab (Code Scanning alerts) in addition to PR comments, generate a SARIF file and upload it:

```yaml
name: Security Review
on:
pull_request:
types: [opened, synchronize]
Expand All @@ -131,47 +169,37 @@ jobs:
review:
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: read
id-token: write
pull-requests: write # For PR comments
security-events: write # For SARIF upload
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history for accurate diffs
fetch-depth: 0

- uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ secrets.WIF_PROVIDER }}
service_account: ${{ secrets.WIF_SA }}

- name: Install code-reviewer
run: go install github.com/OpticDiff/code-reviewer/cmd/code-reviewer@latest # Pin to a specific version in production
run: go install github.com/OpticDiff/code-reviewer/cmd/code-reviewer@v0.6.0

- name: Run review
- name: Review PR
env:
GOOGLE_CLOUD_PROJECT: ${{ secrets.GCP_PROJECT }}
run: |
code-reviewer --diff origin/${{ github.base_ref }} --json > review.json
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: code-reviewer --ci --sarif results.sarif --focus security
continue-on-error: true

- name: Post results
if: always()
uses: actions/github-script@v7
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
script: |
const fs = require('fs');
const review = JSON.parse(fs.readFileSync('review.json', 'utf8'));
if (review.findings.length === 0) return;
let body = `## 🔍 Code Review — ${review.findings.length} finding(s)\n\n`;
body += `${review.summary}\n\n`;
for (const f of review.findings) {
body += `### ${f.severity} — ${f.title}\n`;
body += `📁 \`${f.file}:${f.line}\` | Category: ${f.category}\n\n`;
body += `${f.body}\n\n`;
if (f.suggestion) body += `\`\`\`suggestion\n${f.suggestion}\n\`\`\`\n\n`;
}
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: body.slice(0, 65536)
});
sarif_file: results.sarif
```

> **Note:** This uses `--diff` mode (not `--ci`), which doesn't require GitLab-specific environment variables. The `--json` flag produces machine-parseable output for scripting.
> **Note:** The `GITHUB_TOKEN` needs `pull-requests: write` to post reviews and `security-events: write` to upload SARIF results.

## Authentication

Expand Down
Loading