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
14 changes: 14 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.git
.github
.gitignore
*.md
.env
.env.*
Dockerfile
.dockerignore
coverage.out
docs/
deploy/
api/
go.work
go.work.sum
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# sight environment variables — copy to .env and fill in
# LLM API key for code review (consumers provide their own via the Provider interface)
# sight itself doesn't read this — configure your LLM client before passing it to sight.NewReviewer()
SIGHT_PROVIDER=
SIGHT_API_KEY=
63 changes: 63 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Docker

on:
push:
branches: [main]
tags: ["v*"]
pull_request:
branches: [main]
paths:
- "Dockerfile"
- "**.go"
- "go.mod"
- "go.sum"

permissions:
contents: read
packages: write

env:
REGISTRY: ghcr.io
IMAGE_NAME: graycodeai/sight

jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha,prefix=sha-

- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
VERSION=${{ github.ref_name }}
COMMIT=${{ github.sha }}
BUILD_DATE=${{ github.event.head_commit.timestamp }}
29 changes: 29 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
FROM golang:1.26.3-alpine AS builder

RUN apk add --no-cache git ca-certificates tzdata

WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download && go mod verify

COPY . .
ARG VERSION=dev
ARG COMMIT=none
ARG BUILD_DATE=unknown
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath \
-ldflags="-s -w \
-X main.Version=${VERSION} \
-X main.Commit=${COMMIT} \
-X main.BuildDate=${BUILD_DATE}" \
-o sight ./cmd/sight

FROM alpine:3.21
RUN apk add --no-cache ca-certificates tini && \
adduser -D -u 1000 sight

COPY --from=builder /build/sight /usr/local/bin/sight
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo

USER sight
ENTRYPOINT ["tini", "--", "sight"]
CMD ["mcp"]
95 changes: 95 additions & 0 deletions api/openapi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
openapi: "3.1.0"
info:
title: sight — Code Review Tool Reference
description: |
sight is an AI-powered code review library for diffs.
It parses unified diffs, enriches with code context and git history,
and runs parallel multi-concern reviews through an LLM provider.

sight operates as a Go library and MCP server (stdio or HTTP).
This document describes the MCP tool surface as a machine-readable reference.
version: "0.1.0"
license:
name: MIT
url: https://github.com/GrayCodeAI/sight/blob/main/LICENSE
contact:
url: https://github.com/GrayCodeAI/sight

# No HTTP server by default — MCP uses stdio transport.
# HTTP transport is available via: sight mcp --transport http --addr 127.0.0.1:8080

tags:
- name: review
description: Code review tools
- name: taint
description: Security taint analysis

x-mcp-server:
transport: stdio
binary: sight
start_command: ["sight", "mcp"]
http_transport_command: ["sight", "mcp", "--transport", "http", "--addr", "127.0.0.1:8080"]

x-mcp-tools:
sight_review:
description: AI code review on a unified diff — security, correctness, style, performance
inputSchema:
type: object
required: [diff]
properties:
diff:
type: string
description: Unified diff text (output of `git diff`)
preset:
type: string
enum: [Quick, Standard, Thorough, SecurityFocus, CI]
default: Standard
description: Review thoroughness preset
exclude_files:
type: array
items:
type: string
description: File patterns to exclude from review (glob)
max_tokens:
type: integer
description: Maximum tokens for the LLM review

sight_describe:
description: Generate a pull request description from a unified diff
inputSchema:
type: object
required: [diff]
properties:
diff:
type: string
description: Unified diff text

sight_improve:
description: Suggest specific code improvements for a diff
inputSchema:
type: object
required: [diff]
properties:
diff:
type: string
focus:
type: string
description: Focus area for improvements (e.g. "performance", "readability")

sight_taint:
description: SSA-based cross-function taint analysis for security vulnerabilities
inputSchema:
type: object
required: [path]
properties:
path:
type: string
description: Absolute path to the Go package or module root
patterns:
type: string
default: "./..."
description: Go package patterns to analyze
json:
type: boolean
default: false
description: Output results as JSON
12 changes: 12 additions & 0 deletions deploy/docker/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: sight

services:
sight:
build:
context: ../../
dockerfile: Dockerfile
image: ghcr.io/graycodeai/sight:dev
env_file:
- path: ../../.env.example
required: false
command: ["mcp"]
124 changes: 124 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<div align="center">

# 👁️ sight Architecture

**AI-Powered Code Review on Diffs**

[![Go](https://img.shields.io/badge/Go-1.26+-00ADD8?logo=go)](https://go.dev/)
[![Protocol](https://img.shields.io/badge/Protocol-MCP-purple)]()

</div>

---

## 🎯 Overview

sight is an AI-powered code review library for Go. It parses unified diffs, enriches with **code context** and **git history**, and runs **parallel multi-concern reviews** through an LLM provider.

> 💡 No LLM client bundled — consumers inject their own via the `Provider` interface.

---

## 🧱 Components

```
sight/
├── api/openapi.yaml 📜 MCP tool surface reference
├── cmd/sight/main.go 🖥️ CLI entry (mcp, taint subcommands)
├── sight.go 📤 Public API: Review(), Finding, Result, Stats
├── reviewer.go 🔄 Reviewer: parallel concern orchestration
├── options.go ⚙️ config, With* functions, presets
├── provider.go 🔌 Provider interface (consumers implement)
├── severity.go 📊 Re-exports from hawk/shared/types
├── static_rules.go 🛡️ 30+ static analysis rules
├── taint_analysis.go 🔗 SSA-based taint tracking
├── sast_integration.go 🔒 SAST-LLM fusion
├── autofix.go 🔧 Fix suggestion pipeline
├── eval.go 📊 Evaluation harness
├── mcp/ 🔌 MCP server (stdio + HTTP)
└── internal/
├── diff/ 📄 Unified diff parser
├── review/ 🧠 Concerns, prompts, response parsing
├── comment/ 💬 Inline comment formatting
├── context/ 📖 Code context + git blame
└── output/ 📊 SARIF and terminal formatters
```

---

## 📤 Public API

```go
// 🚀 One-shot review
result, err := sight.Review(ctx, diffText,
sight.WithProvider(myLLMProvider),
sight.Thorough,
)

// 🔄 Reusable reviewer
reviewer := sight.NewReviewer(sight.WithProvider(myLLMProvider))
result, err := reviewer.Review(ctx, diffText)

// ❌ Check if any findings are above threshold
if result.Failed() {
fmt.Printf("Review failed: %d findings\n", len(result.Findings))
}
```

---

## 🔌 Provider Interface

```go
type Provider interface {
Chat(ctx context.Context, messages []Message, opts ChatOpts) (*Response, error)
}
```

> Consumers implement this with their LLM client (e.g., using eyrie). hawk wires eyrie as the provider via `internal/bridge/sight/bridge.go`.

---

## ⚡ Presets

| Preset | Concerns | Speed |
|--------|----------|:-----:|
| 🏃 `Quick` | security, correctness | Fast |
| 📊 `Standard` | security, correctness, style, docs | Medium |
| 🔬 `Thorough` | all concerns | Slow |
| 🔒 `SecurityFocus` | security, taint only | Fast |
| 🤖 `CI` | Standard, fail on High+ | Medium |

---

## 🔌 MCP Server

```bash
sight mcp # 📡 stdio transport
sight mcp --transport http --addr :8080 # 🌐 HTTP transport
```

**Tools:** `sight_review` · `sight_describe` · `sight_improve` · `sight_taint`

---

## 🔎 Findings

| Field | Description |
|-------|-------------|
| `Concern` | Review category (security, style, etc.) |
| `Severity` | 🟢 Info · 🟡 Low · 🟠 Medium · 🔴 High · 🟥 Critical |
| `File` / `Line` | Location in the diff |
| `Message` | What was found and why |
| `Fix` | Suggested fix |
| `CWE` | CWE reference (security findings) |
| `Confidence` | 0.0–1.0 score |
| `InlineComment` | PR-ready inline comment |

---

## 🛡️ Static Rules + Taint Analysis

**30+ built-in rules** run without LLM overhead — hardcoded secret patterns, SQL injection sinks, unsafe deserialization, etc. Fused with LLM results.

**Taint analysis** (`sight taint --path .`) uses SSA-based cross-function tracking to detect source→sink data flows. Sources, sinks, and sanitizers are configurable.
47 changes: 47 additions & 0 deletions examples/basic/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package main

import (
"context"
"fmt"
"log"

"github.com/GrayCodeAI/sight"
)

type mockProvider struct{}

func (m *mockProvider) Complete(ctx context.Context, messages []sight.Message) (string, error) {
return "Code looks good. Consider adding error handling for edge cases.", nil
}

func main() {
diff := `diff --git a/main.go b/main.go
--- a/main.go
+++ b/main.go
@@ -10,6 +10,10 @@ func main() {
if err != nil {
log.Fatal(err)
}
+
+ // Process the data
+ processData(result)
+
fmt.Println("Done")
}
`

reviewer := sight.NewReviewer(
sight.WithProvider(&mockProvider{}),

Check failure on line 34 in examples/basic/main.go

View workflow job for this annotation

GitHub Actions / security

cannot use &mockProvider{} (value of type *mockProvider) as sight.Provider value in argument to sight.WithProvider: *mockProvider does not implement sight.Provider (missing method Chat)

Check failure on line 34 in examples/basic/main.go

View workflow job for this annotation

GitHub Actions / lint

cannot use &mockProvider{} (value of type *mockProvider) as sight.Provider value in argument to sight.WithProvider: *mockProvider does not implement sight.Provider (missing method Chat) (typecheck)

Check failure on line 34 in examples/basic/main.go

View workflow job for this annotation

GitHub Actions / test (race + cover)

cannot use &mockProvider{} (value of type *mockProvider) as sight.Provider value in argument to sight.WithProvider: *mockProvider does not implement sight.Provider (missing method Chat)

Check failure on line 34 in examples/basic/main.go

View workflow job for this annotation

GitHub Actions / deadcode

cannot use &mockProvider{} (value of type *mockProvider) as sight.Provider value in argument to sight.WithProvider: *mockProvider does not implement sight.Provider (missing method Chat)
sight.Thorough,
)

result, err := reviewer.Review(context.Background(), diff)
if err != nil {
log.Fatal(err)
}

fmt.Printf("Found %d findings:\n", len(result.Findings))
for _, f := range result.Findings {
fmt.Printf("[%s] %s:%d - %s\n", f.Severity, f.File, f.Line, f.Message)
}
}
Loading