From 3493756b0405245a20c8141c25988fe7b83f0f27 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Jul 2026 04:02:59 +0000 Subject: [PATCH 1/2] Initial plan From b05f8940afbde7e230fd5a2d99ba495445cfcbdf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 21 Jul 2026 04:24:36 +0000 Subject: [PATCH 2/2] Rename firewall PolicyRule type Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/cli/README.md | 2 +- pkg/cli/firewall_policy.go | 34 ++++++++++++------------- pkg/cli/firewall_policy_test.go | 44 ++++++++++++++++----------------- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/pkg/cli/README.md b/pkg/cli/README.md index 2eadaa0d9c1..045cb7f57cf 100644 --- a/pkg/cli/README.md +++ b/pkg/cli/README.md @@ -356,7 +356,7 @@ The `cli` package exports many types used across its command implementations. Th | `PerformanceMetrics` | struct | Performance counters for a workflow run | | `PolicyAnalysis` | struct | Analysis of guard-policy evaluation results | | `PolicyManifest` | struct | A manifest of guard policies applied during a run | -| `PolicyRule` | struct | A single firewall policy rule from the policy manifest | +| `FirewallPolicyRule` | struct | A single firewall policy rule from the policy manifest | | `PolicySummaryDisplay` | struct | Display-friendly summary of policy evaluation results | | `PollResult` | int alias | Result code returned by `PollWithSignalHandling` | | `ProcessedRun` | struct | A fully-processed workflow run with parsed artifacts | diff --git a/pkg/cli/firewall_policy.go b/pkg/cli/firewall_policy.go index 9b8eaa2f525..7a9c58fc528 100644 --- a/pkg/cli/firewall_policy.go +++ b/pkg/cli/firewall_policy.go @@ -21,19 +21,19 @@ var firewallPolicyLog = logger.New("cli:firewall_policy") // PolicyManifest represents the policy-manifest.json file generated by AWF. // It describes the firewall policy rules and configuration used during a workflow run. type PolicyManifest struct { - Version int `json:"version"` - GeneratedAt string `json:"generatedAt"` - Rules []PolicyRule `json:"rules"` - DangerousPorts []int `json:"dangerousPorts,omitempty"` - DNSServers []string `json:"dnsServers,omitempty"` - SSLBumpEnabled bool `json:"sslBumpEnabled"` - DLPEnabled bool `json:"dlpEnabled"` - HostAccessEnabled bool `json:"hostAccessEnabled"` - AllowHostPorts *string `json:"allowHostPorts"` // nullable → pointer + Version int `json:"version"` + GeneratedAt string `json:"generatedAt"` + Rules []FirewallPolicyRule `json:"rules"` + DangerousPorts []int `json:"dangerousPorts,omitempty"` + DNSServers []string `json:"dnsServers,omitempty"` + SSLBumpEnabled bool `json:"sslBumpEnabled"` + DLPEnabled bool `json:"dlpEnabled"` + HostAccessEnabled bool `json:"hostAccessEnabled"` + AllowHostPorts *string `json:"allowHostPorts"` // nullable → pointer } -// PolicyRule represents a single firewall policy rule from the manifest. -type PolicyRule struct { +// FirewallPolicyRule represents a single firewall policy rule from the manifest. +type FirewallPolicyRule struct { ID string `json:"id"` Order int `json:"order"` Action string `json:"action"` // "allow" or "deny" @@ -71,8 +71,8 @@ type EnrichedRequest struct { // RuleHitStats tracks hit counts per policy rule. type RuleHitStats struct { - Rule PolicyRule `json:"rule"` - Hits int `json:"hits"` + Rule FirewallPolicyRule `json:"rule"` + Hits int `json:"hits"` } // PolicyAnalysis contains the enriched policy analysis results. @@ -101,7 +101,7 @@ func loadPolicyManifest(manifestPath string) (*PolicyManifest, error) { } // Sort rules by order for deterministic matching - slices.SortFunc(manifest.Rules, func(a, b PolicyRule) int { + slices.SortFunc(manifest.Rules, func(a, b FirewallPolicyRule) int { if a.Order < b.Order { return -1 } @@ -162,7 +162,7 @@ func parseAuditJSONL(jsonlPath string) ([]AuditLogEntry, error) { // - "github.com" matches only exactly "github.com" // - Regex patterns (detected via aclName containing "regex" or regex metacharacters) are // compiled and matched against the domain. -func domainMatchesRule(host string, rule PolicyRule) bool { +func domainMatchesRule(host string, rule FirewallPolicyRule) bool { // Strip port from host if present domain := host if idx := strings.LastIndex(host, ":"); idx != -1 { @@ -256,7 +256,7 @@ func isEntryAllowed(entry AuditLogEntry) bool { // protocolMatches checks if a rule's protocol constraint matches the request. // "both" matches everything; "https" matches only HTTPS; "http" matches only HTTP. -func protocolMatches(rule PolicyRule, isHTTPS bool) bool { +func protocolMatches(rule FirewallPolicyRule, isHTTPS bool) bool { switch strings.ToLower(rule.Protocol) { case "https": return isHTTPS @@ -276,7 +276,7 @@ func protocolMatches(rule PolicyRule, isHTTPS bool) bool { // 2. Protocol matching: HTTPS-only rules won't match HTTP requests, and vice versa // 3. Observed-decision validation: a rule only "matches" if its action matches the // observed outcome (allow rule only credited for allowed traffic, deny for denied) -func findMatchingRule(entry AuditLogEntry, rules []PolicyRule) *PolicyRule { +func findMatchingRule(entry AuditLogEntry, rules []FirewallPolicyRule) *FirewallPolicyRule { isHTTPS := isEntryHTTPS(entry) expectedAction := "deny" if isEntryAllowed(entry) { diff --git a/pkg/cli/firewall_policy_test.go b/pkg/cli/firewall_policy_test.go index d13874ab25e..a160ade94c7 100644 --- a/pkg/cli/firewall_policy_test.go +++ b/pkg/cli/firewall_policy_test.go @@ -16,13 +16,13 @@ func TestDomainMatchesRule(t *testing.T) { tests := []struct { name string host string - rule PolicyRule + rule FirewallPolicyRule expected bool }{ { name: "exact match without port", host: "github.com", - rule: PolicyRule{ + rule: FirewallPolicyRule{ Domains: []string{"github.com"}, }, expected: true, @@ -30,7 +30,7 @@ func TestDomainMatchesRule(t *testing.T) { { name: "exact match with port", host: "github.com:443", - rule: PolicyRule{ + rule: FirewallPolicyRule{ Domains: []string{"github.com"}, }, expected: true, @@ -38,7 +38,7 @@ func TestDomainMatchesRule(t *testing.T) { { name: "wildcard match - subdomain", host: "api.github.com:443", - rule: PolicyRule{ + rule: FirewallPolicyRule{ Domains: []string{".github.com"}, }, expected: true, @@ -46,7 +46,7 @@ func TestDomainMatchesRule(t *testing.T) { { name: "wildcard match - base domain", host: "github.com:443", - rule: PolicyRule{ + rule: FirewallPolicyRule{ Domains: []string{".github.com"}, }, expected: true, @@ -54,7 +54,7 @@ func TestDomainMatchesRule(t *testing.T) { { name: "wildcard match - deep subdomain", host: "api.v2.github.com:443", - rule: PolicyRule{ + rule: FirewallPolicyRule{ Domains: []string{".github.com"}, }, expected: true, @@ -62,7 +62,7 @@ func TestDomainMatchesRule(t *testing.T) { { name: "no match - different domain", host: "evil.com:443", - rule: PolicyRule{ + rule: FirewallPolicyRule{ Domains: []string{".github.com"}, }, expected: false, @@ -70,7 +70,7 @@ func TestDomainMatchesRule(t *testing.T) { { name: "no match - suffix collision", host: "notgithub.com:443", - rule: PolicyRule{ + rule: FirewallPolicyRule{ Domains: []string{".github.com"}, }, expected: false, @@ -78,7 +78,7 @@ func TestDomainMatchesRule(t *testing.T) { { name: "case insensitive match", host: "API.GitHub.COM:443", - rule: PolicyRule{ + rule: FirewallPolicyRule{ Domains: []string{".github.com"}, }, expected: true, @@ -86,7 +86,7 @@ func TestDomainMatchesRule(t *testing.T) { { name: "multiple domains in rule", host: "npmjs.org:443", - rule: PolicyRule{ + rule: FirewallPolicyRule{ Domains: []string{".github.com", "npmjs.org"}, }, expected: true, @@ -94,7 +94,7 @@ func TestDomainMatchesRule(t *testing.T) { { name: "no match - empty domains", host: "example.com", - rule: PolicyRule{ + rule: FirewallPolicyRule{ Domains: []string{}, }, expected: false, @@ -102,7 +102,7 @@ func TestDomainMatchesRule(t *testing.T) { { name: "regex match - IP pattern", host: "192.168.1.1", - rule: PolicyRule{ + rule: FirewallPolicyRule{ ACLName: "dst_ipv4_regex", Domains: []string{`^192\.168\.`}, }, @@ -111,7 +111,7 @@ func TestDomainMatchesRule(t *testing.T) { { name: "regex match - metachar detection", host: "test.example.com", - rule: PolicyRule{ + rule: FirewallPolicyRule{ ACLName: "some_acl", Domains: []string{`^.*\.example\.com$`}, }, @@ -120,7 +120,7 @@ func TestDomainMatchesRule(t *testing.T) { { name: "regex no match", host: "other.com", - rule: PolicyRule{ + rule: FirewallPolicyRule{ ACLName: "dst_ipv4_regex", Domains: []string{`^192\.168\.`}, }, @@ -137,7 +137,7 @@ func TestDomainMatchesRule(t *testing.T) { } func TestFindMatchingRule(t *testing.T) { - rules := []PolicyRule{ + rules := []FirewallPolicyRule{ { ID: "allow-github", Order: 1, @@ -211,7 +211,7 @@ func TestFindMatchingRule(t *testing.T) { } func TestProtocolMatching(t *testing.T) { - rules := []PolicyRule{ + rules := []FirewallPolicyRule{ { ID: "allow-https-only", Order: 1, @@ -291,7 +291,7 @@ func TestLoadPolicyManifest(t *testing.T) { manifest := PolicyManifest{ Version: 1, GeneratedAt: "2026-01-01T00:00:00Z", - Rules: []PolicyRule{ + Rules: []FirewallPolicyRule{ {ID: "rule-b", Order: 2, Action: "deny", Domains: []string{".evil.com"}, Description: "Block evil"}, {ID: "rule-a", Order: 1, Action: "allow", Domains: []string{".github.com"}, Description: "Allow GitHub"}, }, @@ -321,7 +321,7 @@ func TestLoadPolicyManifest(t *testing.T) { ports := "8080,9090" manifest := PolicyManifest{ Version: 1, - Rules: []PolicyRule{}, + Rules: []FirewallPolicyRule{}, HostAccessEnabled: true, AllowHostPorts: &ports, } @@ -417,7 +417,7 @@ func TestEnrichWithPolicyRules(t *testing.T) { manifest := &PolicyManifest{ Version: 1, GeneratedAt: "2026-01-01T00:00:00Z", - Rules: []PolicyRule{ + Rules: []FirewallPolicyRule{ { ID: "allow-github", Order: 1, @@ -518,7 +518,7 @@ func TestEnrichWithPolicyRules(t *testing.T) { // any allow rule should be classified as (unattributed-allow), not (implicit-deny) limitedManifest := &PolicyManifest{ Version: 1, - Rules: []PolicyRule{ + Rules: []FirewallPolicyRule{ {ID: "allow-github", Order: 1, Action: "allow", ACLName: "allowed_domains", Protocol: "both", Domains: []string{".github.com"}, Description: "Allow GitHub"}, }, } @@ -699,7 +699,7 @@ func TestAnalyzeFirewallPolicy(t *testing.T) { manifest := PolicyManifest{ Version: 1, GeneratedAt: "2026-01-01T00:00:00Z", - Rules: []PolicyRule{ + Rules: []FirewallPolicyRule{ {ID: "allow-github", Order: 1, Action: "allow", ACLName: "allowed_domains", Protocol: "both", Domains: []string{".github.com"}, Description: "Allow GitHub"}, {ID: "deny-all", Order: 2, Action: "deny", ACLName: "all", Protocol: "both", Domains: []string{}, Description: "Block all other traffic"}, }, @@ -732,7 +732,7 @@ func TestAnalyzeFirewallPolicy(t *testing.T) { manifest := PolicyManifest{ Version: 1, - Rules: []PolicyRule{{ID: "r1", Order: 1, Action: "allow", Domains: []string{".example.com"}}}, + Rules: []FirewallPolicyRule{{ID: "r1", Order: 1, Action: "allow", Domains: []string{".example.com"}}}, SSLBumpEnabled: true, } manifestData, err := json.Marshal(manifest)