Parent issue: #22736
Prerequisite: #22733 (merged) — policy-manifest.json is now included in firewall-audit-logs artifacts
Summary
Enhance gh aw audit <run-id> to automatically include firewall policy rule attribution when firewall artifacts are present. No new flags — just richer output when policy-manifest.json and audit.jsonl are available in the downloaded artifacts.
What Changes
When gh aw audit detects firewall artifacts in the downloaded run directory, the audit report should include:
- Policy rule attribution — for each domain, show which rule caused the allow/deny decision
- Rule hit table — show all policy rules with action, description, and hit count
- Denied request details — timestamp, domain, rule ID, and reason for each denial
- Summary statistics — total requests, allowed, denied, unique domains
When policy-manifest.json is absent (older runs), fall back to current behavior (domain counts only).
Example Output
### Firewall Policy Analysis
**Policy**: 12 rules, SSL Bump disabled, DLP disabled
| Rule | Action | Description | Hits |
|------|--------|-------------|------|
| allow-both-plain | allow | Allow HTTP/HTTPS to whitelisted domains | 47 |
| deny-blocked-plain | deny | Deny all other HTTP/HTTPS traffic | 3 |
**Denied Requests (3)**
| Time | Domain | Rule | Reason |
|------|--------|------|--------|
| 14:23:01 | evil.com:443 | deny-blocked-plain | Domain not in allowlist |
| 14:23:05 | tracker.io:443 | deny-blocked-plain | Domain not in allowlist |
Implementation
Approach: Go reimplementation (not AWF subprocess)
Port the enrichment logic from gh-aw-firewall's TypeScript to Go. The AWF CLI requires Docker/sudo so invoking it as a subprocess is not viable.
Key files to port from (gh-aw-firewall)
src/logs/audit-enricher.ts — enrichWithPolicyRules(), domainMatchesRule(), computeRuleStats()
src/types.ts — PolicyManifest, PolicyRule types
Key files to modify (gh-aw)
pkg/cli/firewall_log.go — Add JSONL parser, policy manifest loader, rule enrichment
pkg/cli/audit.go (or related audit report generation) — Integrate enriched output into markdown report
Data formats
audit.jsonl (one JSON object per line):
{"ts":1761074374.646,"client":"172.30.0.20","host":"api.github.com:443","dest":"140.82.114.22:443","method":"CONNECT","status":200,"decision":"TCP_TUNNEL","url":"api.github.com:443"}
policy-manifest.json:
{
"version": 1,
"generatedAt": "...",
"rules": [
{"id": "allow-both-plain", "order": 1, "action": "allow", "aclName": "allowed_domains", "protocol": "both", "domains": ["github.com", ".github.com"], "description": "Allow github.com and subdomains"}
],
"dangerousPorts": [22, 25],
"dnsServers": ["8.8.8.8"],
"sslBumpEnabled": false,
"dlpEnabled": false
}
Rule matching: Rules evaluated top-to-bottom by order; first matching rule wins. Domain matching: .github.com matches both github.com and *.github.com.
Tasks
Parent issue: #22736
Prerequisite: #22733 (merged) —
policy-manifest.jsonis now included infirewall-audit-logsartifactsSummary
Enhance
gh aw audit <run-id>to automatically include firewall policy rule attribution when firewall artifacts are present. No new flags — just richer output whenpolicy-manifest.jsonandaudit.jsonlare available in the downloaded artifacts.What Changes
When
gh aw auditdetects firewall artifacts in the downloaded run directory, the audit report should include:When
policy-manifest.jsonis absent (older runs), fall back to current behavior (domain counts only).Example Output
Implementation
Approach: Go reimplementation (not AWF subprocess)
Port the enrichment logic from gh-aw-firewall's TypeScript to Go. The AWF CLI requires Docker/sudo so invoking it as a subprocess is not viable.
Key files to port from (gh-aw-firewall)
src/logs/audit-enricher.ts—enrichWithPolicyRules(),domainMatchesRule(),computeRuleStats()src/types.ts—PolicyManifest,PolicyRuletypesKey files to modify (gh-aw)
pkg/cli/firewall_log.go— Add JSONL parser, policy manifest loader, rule enrichmentpkg/cli/audit.go(or related audit report generation) — Integrate enriched output into markdown reportData formats
audit.jsonl (one JSON object per line):
{"ts":1761074374.646,"client":"172.30.0.20","host":"api.github.com:443","dest":"140.82.114.22:443","method":"CONNECT","status":200,"decision":"TCP_TUNNEL","url":"api.github.com:443"}policy-manifest.json:
{ "version": 1, "generatedAt": "...", "rules": [ {"id": "allow-both-plain", "order": 1, "action": "allow", "aclName": "allowed_domains", "protocol": "both", "domains": ["github.com", ".github.com"], "description": "Allow github.com and subdomains"} ], "dangerousPorts": [22, 25], "dnsServers": ["8.8.8.8"], "sslBumpEnabled": false, "dlpEnabled": false }Rule matching: Rules evaluated top-to-bottom by
order; first matching rule wins. Domain matching:.github.commatches bothgithub.comand*.github.com.Tasks
PolicyManifest,PolicyRuleGo structsaudit.jsonlJSONL parser (complement existingaccess.logparser infirewall_log.go)enrichWithPolicyRules()/domainMatchesRule()to Go--jsonsupport for enriched firewall dataaudit.jsonl+policy-manifest.json)