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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ concurrency:
cancel-in-progress: true

env:
GO_VERSION: "1.26.5"
GO_VERSION: "1.26.6"
GOPROXY: "https://proxy.golang.org,direct"
GOPRIVATE: "github.com/GrayCodeAI/*"
GONOSUMDB: "github.com/GrayCodeAI/*"
Expand Down
34 changes: 34 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,40 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

---

## [Unreleased]

### Changed
- Extracted the out-of-range confidence fallback in `toPublicFindings`
into a documented package constant, `defaultConfidence` (0.6). No
behavior change.

### Fixed
- **Configured fail thresholds now survive contract conversion.**
`ToContractResult` copied `FailOn` by field assignment, leaving the
contract's `FailOnSet` false so its `Failed()` ignored a
user-configured below-critical threshold (e.g. `WithFailOn(High)`
from the `CI` preset). Conversion now records the threshold via
`SetFailOn`, so the contract `Result.Failed()` honors it.
- **Provider failures are now visible in `Stats`.** A review in which
every LLM call failed previously succeeded silently — errors only
appeared in the human-readable `Report`. `Stats.LLMErrors` now
records one entry per failed call (concern calls and the
self-reflection pass), and `ToContractResult` carries them into the
shared `reviewcontracts.Stats.LLMErrors` field so hawk can surface
partial results.

### Removed
- **Dead audit/graph API surface** (breaking, pre-1.0). The
`WithGraph`, `WithAuditMode`, and `WithAuditTargets` options and the
`AuditMode`, `AuditTarget`, `AuditTargetType`, `AuditOption`, and
`ParseAuditMode` types configured `Reviewer` fields that were never
read, and the `internal/graph` and `internal/audit` packages had no
callers. Removed the options, types, packages, the unused `Reviewer`
fields, and the `graph`/`audit` `.sight.toml` keys (the keys were
silently ignored in effect; they now remain unparsed, which is the
same behavior). Consumers should use `qualitygraph` for graph
projection and `inspect` for deployed-surface auditing.

## [0.1.2] - 2026-07-04

### Changed
Expand Down
13 changes: 0 additions & 13 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ type FileConfig struct {
Reflection *bool `json:"reflection"`
Parallel *bool `json:"parallel"`
Prompts map[string]string `json:"prompts"`
Graph *bool `json:"graph"`
Audit *string `json:"audit"` // "none", "hooks", "mcp", "full"
}

// LoadConfigFile reads .sight.toml from the given directory (or parents).
Expand Down Expand Up @@ -80,12 +78,6 @@ func ApplyFileConfig(fc *FileConfig) []Option {
if len(fc.Exclude) > 0 {
opts = append(opts, WithExclude(fc.Exclude...))
}
if fc.Graph != nil {
opts = append(opts, WithGraph(*fc.Graph))
}
if fc.Audit != nil {
opts = append(opts, WithAuditMode(ParseAuditMode(*fc.Audit)))
}

return opts
}
Expand Down Expand Up @@ -160,11 +152,6 @@ func parseTOMLConfig(content string) (*FileConfig, error) {
case "parallel":
b := value == "true"
cfg.Parallel = &b
case "graph":
b := value == "true"
cfg.Graph = &b
case "audit":
cfg.Audit = &value
}
}

Expand Down
9 changes: 7 additions & 2 deletions contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ func toContractStats(s Stats) reviewcontracts.Stats {
AverageConfidence: s.AverageConfidence,
HighConfidenceCount: s.HighConfidenceCount,
LowConfidenceCount: s.LowConfidenceCount,
LLMErrors: s.LLMErrors,
}
}

Expand All @@ -113,13 +114,17 @@ func ToContractResult(r *Result) *reviewcontracts.Result {
if r == nil {
return nil
}
return &reviewcontracts.Result{
res := &reviewcontracts.Result{
Findings: ToContractFindings(r.Findings),
Comments: ToContractInlineComments(r.Comments),
Stats: toContractStats(r.Stats),
Report: r.Report,
FailOn: r.FailOn,
SASTFusion: toContractSASTFusion(r.SASTFusion),
ConfidenceBreakdown: toContractConfidenceBreakdown(r.ConfidenceBreakdown),
}
// Set the threshold through SetFailOn so FailOnSet is recorded: the
// contract's Failed() ignores a directly-assigned FailOn below
// critical, which would drop a user-configured threshold.
res.SetFailOn(r.FailOn)
return res
}
67 changes: 66 additions & 1 deletion contracts_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package sight

import "testing"
import (
"context"
"testing"
)

func TestToContractResult(t *testing.T) {
t.Parallel()
Expand Down Expand Up @@ -49,3 +52,65 @@ func TestToContractResult(t *testing.T) {
t.Fatal("expected confidence breakdown to convert")
}
}

func TestToContractResult_FailOnThresholdTakesEffect(t *testing.T) {
t.Parallel()

// A below-critical threshold configured on the sight Result must
// survive conversion: the contract's Failed() honors it only when
// FailOnSet is true, which ToContractResult must arrange via SetFailOn.
result := &Result{
FailOn: SeverityHigh,
Findings: []Finding{
{Severity: SeverityInfo, Message: "note", Confidence: 0.5},
},
}

contract := ToContractResult(result)
if !contract.FailOnSet {
t.Fatal("FailOnSet = false, want true after conversion")
}
if contract.FailOn != SeverityHigh {
t.Fatalf("FailOn = %v, want high", contract.FailOn)
}
if contract.Failed() {
t.Error("info finding must not fail a review with a high threshold")
}

result.Findings = append(result.Findings, Finding{
Severity: SeverityHigh, Message: "real problem", Confidence: 0.5,
})
contract = ToContractResult(result)
if !contract.Failed() {
t.Error("high finding must fail a review with a high threshold")
}
}

func TestToContractResult_FailOnConfiguredViaOptions(t *testing.T) {
t.Parallel()

reviewWith := func(response string) *Result {
t.Helper()
r := NewReviewer(
WithProvider(&fixMockProvider{response: response}),
WithFailOn(SeverityHigh),
WithConcerns("security"),
WithParallel(false),
)
result, err := r.Review(context.Background(), sampleDiff)
if err != nil {
t.Fatalf("Review failed: %v", err)
}
return result
}

infoOnly := reviewWith(`[{"file": "handler.go", "line": 13, "severity": "info", "message": "style nit", "fix": "n/a"}]`)
if got := ToContractResult(infoOnly).Failed(); got {
t.Error("Failed() = true for info-only findings with failOn=high, want false")
}

highFinding := reviewWith(`[{"file": "handler.go", "line": 13, "severity": "high", "message": "SQL injection", "fix": "use params"}]`)
if got := ToContractResult(highFinding).Failed(); !got {
t.Error("Failed() = false for a high finding with failOn=high, want true")
}
}
57 changes: 0 additions & 57 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,63 +134,6 @@ srv.ServeHTTP("127.0.0.1:8080") // 🌐 streamable HTTP transport, served at /mc

---

## 🔗 Structural Dependency Graph

The `internal/graph` package provides **optional structural dependency analysis** for code reviews:

**Key capabilities:**
- Parse Go AST to build structural dependency graph
- Blast-radius analysis: identify all files affected by changes
- Transitive dependency tracking
- Impact scoring based on depth and number of dependents
- SQLite persistence for incremental updates

**Usage:**
```go
// Enable graph-backed review
g := graph.New()
// ... build graph or load from SQLite ...

// Run blast radius analysis
result := g.GetBlastRadius([]string{"file.go"})
fmt.Printf("Direct: %d, Transitive: %d\n", result.Direct, result.Transitive)
```

**Tools exposed via MCP:** `sight_graph_blastRadius`, `sight_graph_query`, `sight_graph_stats`

---

## 🔒 Security Auditing

The `internal/audit` package provides **agent surface security auditing**:

**Key capabilities:**
- Concurrent security scanning of multiple targets
- Filter findings by severity (critical, high, medium, low) or category
- Integration with MCP hooks, permissions, and endpoints
- Webhook validation and test requests
- JSON-serializable audit findings

**Usage:**
```go
// Create audit scope
auditScope := &audit.AuditScope{
Targets: []audit.AuditTarget{
{Type: audit.AuditTargetHooks, Path: "/hooks/webhook"},
{Type: audit.AuditTargetEndpoints, Path: "/api/endpoint"},
},
Rules: []string{"detect_unauthenticated_endpoints", "detect_hardcoded_secrets"},
}

// Run audit
report, err := audit.Audit(ctx, auditScope)
if report.Count() > 0 {
fmt.Printf("Found %d security issues\n", report.Count())
}
```

---

## 🌐 Browser Automation Tools

The `internal/tool` package provides **HTTP-based browser automation** capabilities:
Expand Down
4 changes: 2 additions & 2 deletions go.mod

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading