First Commit
ci / go (push) Waiting to run
ci / go-db (agent) (push) Waiting to run
ci / go-db (config) (push) Waiting to run
ci / go-db (db) (push) Waiting to run
ci / go-db (evidence) (push) Waiting to run
ci / go-db (llmrec) (push) Waiting to run
ci / go-db (server) (push) Waiting to run
web / web (push) Waiting to run
docs / links (push) Canceled after 0s
detections / detections (push) Canceled after 0s

This commit is contained in:
dela
2026-10-09 08:38:16 +08:00
commit 0335d572de
756 changed files with 201663 additions and 0 deletions
+129
View File
@@ -0,0 +1,129 @@
package db
import "testing"
func rule(kind, pattern string, enabled bool) AssetInterceptRule {
return AssetInterceptRule{Kind: kind, Pattern: pattern, Enabled: enabled}
}
func TestMatchAssetInterceptRules(t *testing.T) {
cases := []struct {
name string
rules []AssetInterceptRule
domains []string
ips []string
urls []string
want bool
wantVal string
}{
{"内置模糊政府域名命中", []AssetInterceptRule{rule("fuzzy_domain", ".gov.cn", true)},
[]string{"www.beijing.gov.cn"}, nil, nil, true, "www.beijing.gov.cn"},
{"模糊教育域名命中", []AssetInterceptRule{rule("fuzzy_domain", ".edu", true)},
[]string{"mit.edu"}, nil, nil, true, "mit.edu"},
{"全等域名命中大小写不敏感", []AssetInterceptRule{rule("exact_domain", "Example.com", true)},
[]string{"example.com"}, nil, nil, true, "example.com"},
{"全等域名不命中子域", []AssetInterceptRule{rule("exact_domain", "example.com", true)},
[]string{"a.example.com"}, nil, nil, false, ""},
{"全等IP命中", []AssetInterceptRule{rule("exact_ip", "203.0.113.5", true)},
nil, []string{"203.0.113.5"}, nil, true, "203.0.113.5"},
{"模糊IP前缀命中", []AssetInterceptRule{rule("fuzzy_ip", "203.0.113.", true)},
nil, []string{"203.0.113.99"}, nil, true, "203.0.113.99"},
{"CIDR 命中", []AssetInterceptRule{rule("cidr", "192.168.0.0/16", true)},
nil, []string{"192.168.5.20"}, nil, true, "192.168.5.20"},
{"CIDR 不命中", []AssetInterceptRule{rule("cidr", "192.168.0.0/16", true)},
nil, []string{"10.0.0.1"}, nil, false, ""},
{"全等URL命中", []AssetInterceptRule{rule("exact_url", "https://a.gov.cn/login", true)},
nil, nil, []string{"https://a.gov.cn/login"}, true, "https://a.gov.cn/login"},
{"模糊URL命中路径", []AssetInterceptRule{rule("fuzzy_url", "/admin", true)},
nil, nil, []string{"https://x.com/admin/panel"}, true, "https://x.com/admin/panel"},
{"禁用规则不命中", []AssetInterceptRule{rule("fuzzy_domain", ".gov.cn", false)},
[]string{"www.gov.cn"}, nil, nil, false, ""},
{"无规则不命中", nil, []string{"www.gov.cn"}, nil, nil, false, ""},
{"空pattern不命中", []AssetInterceptRule{rule("fuzzy_domain", " ", true)},
[]string{"www.gov.cn"}, nil, nil, false, ""},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
r, val, ok := MatchAssetInterceptRules(c.rules, c.domains, c.ips, c.urls)
if ok != c.want {
t.Fatalf("命中 = %v, 期望 %v (rule=%+v)", ok, c.want, r)
}
if ok && val != c.wantVal {
t.Fatalf("命中值 = %q, 期望 %q", val, c.wantVal)
}
})
}
}
func TestEvaluateAssetGate(t *testing.T) {
block := []AssetInterceptRule{rule("fuzzy_domain", ".gov.cn", true)}
allow := []AssetInterceptRule{rule("fuzzy_domain", "example.com", true)}
// 1. 命中拦截规则 → 拒绝(拦截原因优先)。
if d := EvaluateAssetGate(block, allow, []string{"www.gov.cn"}, nil, nil); d.Allowed {
t.Fatal("命中拦截规则应被拒绝")
}
// 2. 未命中拦截、有允许规则但不命中 → 拒绝(不允许)。
d := EvaluateAssetGate(block, allow, []string{"foo.other.com"}, nil, nil)
if d.Allowed {
t.Fatal("有白名单且不命中应被拒绝")
}
if d.Reason == "" {
t.Fatal("拒绝应带原因")
}
// 3. 未命中拦截、命中允许规则 → 放行。
if d := EvaluateAssetGate(block, allow, []string{"api.example.com"}, nil, nil); !d.Allowed {
t.Fatal("命中白名单应放行")
}
// 4. 无允许规则(白名单未启用)→ 未命中拦截即放行。
if d := EvaluateAssetGate(block, nil, []string{"foo.other.com"}, nil, nil); !d.Allowed {
t.Fatal("无白名单时未命中拦截应放行")
}
// 5. 允许规则全部禁用 → 视为白名单未启用,放行。
disabledAllow := []AssetInterceptRule{rule("fuzzy_domain", "example.com", false)}
if d := EvaluateAssetGate(nil, disabledAllow, []string{"foo.other.com"}, nil, nil); !d.Allowed {
t.Fatal("白名单全禁用时应放行")
}
// 6. 拦截优先于允许:同一目标既命中拦截又命中允许 → 拒绝。
if d := EvaluateAssetGate(
[]AssetInterceptRule{rule("fuzzy_domain", ".gov.cn", true)},
[]AssetInterceptRule{rule("fuzzy_domain", ".gov.cn", true)},
[]string{"www.gov.cn"}, nil, nil,
); d.Allowed {
t.Fatal("拦截应优先于允许")
}
}
func TestAssetInterceptCandidates(t *testing.T) {
// 只带 URL 的服务资产:host 应被拆出并归入域名候选,从而被 fuzzy_domain 命中。
a := &Asset{Type: "service", URL: "https://portal.beijing.gov.cn:8443/app"}
domains, _, urls := a.interceptCandidates()
if len(urls) != 1 || urls[0] != a.URL {
t.Fatalf("urls = %v", urls)
}
found := false
for _, d := range domains {
if d == "portal.beijing.gov.cn" {
found = true
}
}
if !found {
t.Fatalf("URL host 未拆入域名候选: %v", domains)
}
r, _, ok := MatchAssetInterceptRules([]AssetInterceptRule{rule("fuzzy_domain", ".gov.cn", true)}, domains, nil, urls)
if !ok {
t.Fatalf("仅带 URL 的政府服务资产应被 fuzzy_domain 命中, rule=%+v", r)
}
// URL host 是 IP 时应归入 IP 候选,可被 CIDR 命中。
b := &Asset{Type: "service", URL: "http://10.1.2.3/x"}
_, ips, _ := b.interceptCandidates()
if r, _, ok := MatchAssetInterceptRules([]AssetInterceptRule{rule("cidr", "10.0.0.0/8", true)}, nil, ips, nil); !ok {
t.Fatalf("URL 中的 IP 应被 CIDR 命中, ips=%v rule=%+v", ips, r)
}
}