analyzeFirewallPolicy loads policy manifest and audit JSONL, then enriches with rule attribution. Returns nil if no policy artifacts are found (graceful fallback to basic analysis).
(runDir string, verbose bool)
| 497 | // analyzeFirewallPolicy loads policy manifest and audit JSONL, then enriches with rule attribution. |
| 498 | // Returns nil if no policy artifacts are found (graceful fallback to basic analysis). |
| 499 | func analyzeFirewallPolicy(runDir string, verbose bool) (*PolicyAnalysis, error) { |
| 500 | manifestPath, auditJSONLPath, err := detectFirewallAuditArtifacts(runDir) |
| 501 | if err != nil { |
| 502 | return nil, fmt.Errorf("failed to detect firewall audit artifacts: %w", err) |
| 503 | } |
| 504 | |
| 505 | if manifestPath == "" { |
| 506 | firewallPolicyLog.Print("No policy manifest found, skipping policy analysis") |
| 507 | return nil, nil |
| 508 | } |
| 509 | |
| 510 | manifest, err := loadPolicyManifest(manifestPath) |
| 511 | if err != nil { |
| 512 | return nil, fmt.Errorf("failed to load policy manifest: %w", err) |
| 513 | } |
| 514 | |
| 515 | if auditJSONLPath == "" { |
| 516 | // We have a manifest but no audit log — return policy summary without request enrichment |
| 517 | firewallPolicyLog.Print("No audit JSONL found, returning manifest-only analysis") |
| 518 | sslBump := "disabled" |
| 519 | if manifest.SSLBumpEnabled { |
| 520 | sslBump = "enabled" |
| 521 | } |
| 522 | dlp := "disabled" |
| 523 | if manifest.DLPEnabled { |
| 524 | dlp = "enabled" |
| 525 | } |
| 526 | |
| 527 | return &PolicyAnalysis{ |
| 528 | PolicySummary: fmt.Sprintf("%d rules, SSL Bump %s, DLP %s", len(manifest.Rules), sslBump, dlp), |
| 529 | RuleHits: make([]RuleHitStats, 0), |
| 530 | }, nil |
| 531 | } |
| 532 | |
| 533 | entries, err := parseAuditJSONL(auditJSONLPath) |
| 534 | if err != nil { |
| 535 | return nil, fmt.Errorf("failed to parse audit JSONL: %w", err) |
| 536 | } |
| 537 | |
| 538 | return enrichWithPolicyRules(entries, manifest), nil |
| 539 | } |