Files
macos-package-review/cmd/audit/main.go
T
FloandClaude Opus 4.8 5a610ff5c4 feat(security): scan Homebrew pkgs via brew-vulns
Add Audit.ScanHomebrew, which shells out to "brew vulns --json" (the
homebrew/brew-vulns tap) to cover the Homebrew formulae that ScanOSV
skips. It resolves each formula's source repo and version tag and
queries OSV via the GIT ecosystem.

brew-vulns exits 1 when vulnerabilities are found, so success is
detected by parseable JSON on stdout rather than the exit code; if the
tool is not installed the scan is skipped with a notice instead of
failing the audit. Qualitative severities are mapped through the
existing severityLabelToScore/cvssToSeverity helpers for consistency.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GVbEgdgcC1w6qwSq3zC4kg
2026-06-23 23:58:42 +02:00

100 lines
2.9 KiB
Go

package main
import (
"flag"
"fmt"
"log"
"os"
"github.com/user/package-review/internal/inventory"
"github.com/user/package-review/internal/report"
"github.com/user/package-review/internal/security"
)
func main() {
var (
inventoryFile = flag.String("inventory", "inventory.json", "Path to inventory JSON file")
outputJSON = flag.String("json", "audit_report.json", "Output audit report as JSON")
outputHTML = flag.String("html", "audit_report.html", "Output audit report as HTML")
claudeMode = flag.String("claude", "claude", "Claude integration mode: 'claude' (CLI) or 'sdk' (Anthropic SDK)")
)
flag.Usage = func() {
fmt.Fprintf(os.Stderr, `Usage: audit [options]
Options:
`)
flag.PrintDefaults()
fmt.Fprintf(os.Stderr, `
Examples:
# Collect inventory and run audit
./scripts/collect-inventory.sh && go run ./cmd/audit
# Use existing inventory
go run ./cmd/audit -inventory=/path/to/inventory.json
# Specify output files
go run ./cmd/audit -json=report.json -html=report.html
# Use Anthropic SDK for Claude (requires ANTHROPIC_API_KEY)
go run ./cmd/audit -claude=sdk
`)
}
flag.Parse()
// Verify inventory file exists
if _, err := os.Stat(*inventoryFile); os.IsNotExist(err) {
log.Fatalf("❌ Inventory file not found: %s\nRun: ./scripts/collect-inventory.sh", *inventoryFile)
}
fmt.Println("🔍 Loading inventory...")
inv, err := inventory.LoadInventory(*inventoryFile)
if err != nil {
log.Fatalf("Error loading inventory: %v", err)
}
fmt.Printf("✓ Loaded %d packages from inventory\n\n", inv.CountPackages())
// Scan for vulnerabilities
fmt.Println("🔎 Scanning for vulnerabilities...")
audit := security.NewAudit(inv)
if err := audit.ScanOSV(); err != nil {
log.Fatalf("Error scanning OSV.dev: %v", err)
}
if err := audit.ScanHomebrew(); err != nil {
log.Fatalf("Error scanning Homebrew packages: %v", err)
}
// Get high-severity findings
highSev := audit.FilterByMinSeverity(7.0)
fmt.Printf("⚠️ Found %d high-severity vulnerabilities\n\n", len(highSev))
// Run Claude analysis on high-severity items
if len(highSev) > 0 {
fmt.Println("🤖 Analyzing with Claude...")
if err := audit.AnalyzeWithClaude(*claudeMode); err != nil {
log.Fatalf("Error running Claude analysis: %v", err)
}
}
// Generate reports
fmt.Println("\n📊 Generating reports...")
// JSON report
if err := report.WriteJSON(audit, *outputJSON); err != nil {
log.Fatalf("Error writing JSON report: %v", err)
}
fmt.Printf("✓ JSON report: %s\n", *outputJSON)
// HTML report (via Astro)
if err := report.GenerateAstroSite(audit, *outputHTML); err != nil {
log.Fatalf("Error generating HTML report: %v", err)
}
fmt.Printf("✓ HTML report: %s\n", *outputHTML)
fmt.Println("\n✅ Audit complete!")
fmt.Printf("📈 Summary: %d packages scanned, %d with CVEs, %d high-severity\n",
inv.CountPackages(), audit.CountVulnerable(), len(highSev))
}