package security import ( "encoding/json" "fmt" "os/exec" "strings" ) // analyzeWithCLI sends findings to Claude via the claude command-line tool func analyzeWithCLI(a *Audit, findings []Finding) error { fmt.Println(" Using Claude Code CLI for analysis...") for _, finding := range findings { // Build prompt for Claude prompt := buildClaudePrompt(finding) // Call claude command cmd := exec.Command("claude", "ask", prompt) output, err := cmd.Output() if err != nil { fmt.Printf(" ⚠️ Error analyzing %s %s: %v\n", finding.PackageName, finding.CVE, err) continue } // Parse Claude's response mitigation := Mitigation{ Finding: finding, Rationale: string(output), Recommendation: inferRecommendation(string(output)), NextSteps: inferNextSteps(string(output)), } a.Mitigations = append(a.Mitigations, mitigation) } return nil } // analyzeWithSDK sends findings to Claude via Anthropic SDK // This requires ANTHROPIC_API_KEY environment variable func analyzeWithSDK(a *Audit, findings []Finding) error { fmt.Println(" Using Anthropic SDK for analysis...") // This is a placeholder - full SDK integration would go here // For now, fallback to CLI mode return analyzeWithCLI(a, findings) } // buildClaudePrompt constructs a prompt for Claude analysis func buildClaudePrompt(f Finding) string { return fmt.Sprintf(`You are a security expert. Analyze this vulnerability and provide a clear mitigation strategy. Package: %s (version %s) CVE: %s CVSS Score: %.1f Severity: %s Summary: %s For this vulnerability, provide a concise mitigation strategy. Consider these options: 1. UPDATE - update to a patched version 2. REPLACE - replace with an alternative package 3. PROTECT - add extra protections without updating 4. MONITOR - monitor and plan update Respond with: - Recommended action (UPDATE/REPLACE/PROTECT/MONITOR) - Why you recommend this action - Specific steps to take Be concise and practical.`, f.PackageName, f.PackageVersion, f.CVE, f.CVSS, f.Severity, f.Summary) } // inferRecommendation extracts the recommendation from Claude's response func inferRecommendation(response string) string { response = strings.ToUpper(response) if strings.Contains(response, "UPDATE") { return "update" } if strings.Contains(response, "REPLACE") { return "replace" } if strings.Contains(response, "PROTECT") { return "protect" } if strings.Contains(response, "MONITOR") { return "monitor" } return "unknown" } // inferNextSteps extracts action items from Claude's response func inferNextSteps(response string) string { // Extract the "steps" section if present lines := strings.Split(response, "\n") var steps []string foundSteps := false for _, line := range lines { trimmed := strings.TrimSpace(line) if strings.Contains(strings.ToLower(line), "step") { foundSteps = true } if foundSteps && strings.HasPrefix(trimmed, "-") || strings.HasPrefix(trimmed, "•") || strings.HasPrefix(trimmed, "1") { steps = append(steps, trimmed) } } if len(steps) > 0 { return strings.Join(steps, "\n") } return response } // MarshalJSON converts Mitigation to JSON, handling the Finding struct func (m Mitigation) MarshalJSON() ([]byte, error) { type Alias Mitigation return json.Marshal(&struct { *Alias }{ Alias: (*Alias)(&m), }) }