enrichWithPolicyRules enriches audit log entries with policy rule attribution.
(entries []AuditLogEntry, manifest *PolicyManifest)
| 315 | |
| 316 | // enrichWithPolicyRules enriches audit log entries with policy rule attribution. |
| 317 | func enrichWithPolicyRules(entries []AuditLogEntry, manifest *PolicyManifest) *PolicyAnalysis { |
| 318 | firewallPolicyLog.Printf("Enriching %d entries with %d policy rules", len(entries), len(manifest.Rules)) |
| 319 | |
| 320 | ruleHitMap := make(map[string]int) |
| 321 | var deniedRequests []EnrichedRequest |
| 322 | uniqueDomains := make(map[string]struct { |
| 323 | }) |
| 324 | allowedCount := 0 |
| 325 | deniedCount := 0 |
| 326 | |
| 327 | for _, entry := range entries { |
| 328 | host := entry.Host |
| 329 | if host == "" || host == "-" { |
| 330 | continue |
| 331 | } |
| 332 | |
| 333 | // Skip benign Squid operational entries (matches TS computeRuleStats filter) |
| 334 | if entry.URL == "error:transaction-end-before-headers" { |
| 335 | continue |
| 336 | } |
| 337 | |
| 338 | // Strip port for domain tracking and normalize case |
| 339 | domain := host |
| 340 | if idx := strings.LastIndex(host, ":"); idx != -1 { |
| 341 | domain = host[:idx] |
| 342 | } |
| 343 | uniqueDomains[strings.ToLower(domain)] = struct { |
| 344 | }{} |
| 345 | |
| 346 | rule := findMatchingRule(entry, manifest.Rules) |
| 347 | |
| 348 | var enriched EnrichedRequest |
| 349 | enriched.Timestamp = entry.Timestamp |
| 350 | enriched.Host = host |
| 351 | enriched.Status = entry.Status |
| 352 | |
| 353 | if rule != nil { |
| 354 | enriched.RuleID = rule.ID |
| 355 | enriched.Action = rule.Action |
| 356 | ruleHitMap[rule.ID]++ |
| 357 | |
| 358 | if rule.Action == "deny" { |
| 359 | enriched.Reason = rule.Description |
| 360 | deniedRequests = append(deniedRequests, enriched) |
| 361 | deniedCount++ |
| 362 | } else { |
| 363 | allowedCount++ |
| 364 | } |
| 365 | } else { |
| 366 | // No matching rule — derive outcome from observed entry decision |
| 367 | if isEntryAllowed(entry) { |
| 368 | enriched.RuleID = "(unattributed-allow)" |
| 369 | enriched.Action = "allow" |
| 370 | enriched.Reason = "Allowed (rule not identified)" |
| 371 | allowedCount++ |
| 372 | } else { |
| 373 | enriched.RuleID = "(implicit-deny)" |
| 374 | enriched.Action = "deny" |