Files
lijiaoqiao/gateway/internal/compliance/rules/loader_test.go
Your Name 89104bd0db feat(P1/P2): 完成TDD开发及P1/P2设计文档
## 设计文档
- multi_role_permission_design: 多角色权限设计 (CONDITIONAL GO)
- audit_log_enhancement_design: 审计日志增强 (CONDITIONAL GO)
- routing_strategy_template_design: 路由策略模板 (CONDITIONAL GO)
- sso_saml_technical_research: SSO/SAML调研 (CONDITIONAL GO)
- compliance_capability_package_design: 合规能力包设计 (CONDITIONAL GO)

## TDD开发成果
- IAM模块: supply-api/internal/iam/ (111个测试)
- 审计日志模块: supply-api/internal/audit/ (40+测试)
- 路由策略模块: gateway/internal/router/ (33+测试)
- 合规能力包: gateway/internal/compliance/ + scripts/ci/compliance/

## 规范文档
- parallel_agent_output_quality_standards: 并行Agent产出质量规范
- project_experience_summary: 项目经验总结 (v2)
- 2026-04-02-p1-p2-tdd-execution-plan: TDD执行计划

## 评审报告
- 5个CONDITIONAL GO设计文档评审报告
- fix_verification_report: 修复验证报告
- full_verification_report: 全面质量验证报告
- tdd_module_quality_verification: TDD模块质量验证
- tdd_execution_summary: TDD执行总结

依据: Superpowers执行框架 + TDD规范
2026-04-02 23:35:53 +08:00

165 lines
4.0 KiB
Go

package rules
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// TestRuleLoader_ValidYaml 测试加载有效YAML
func TestRuleLoader_ValidYaml(t *testing.T) {
// 创建临时有效YAML文件
tmpfile, err := os.CreateTemp("", "valid_rule_*.yaml")
require.NoError(t, err)
defer os.Remove(tmpfile.Name())
validYAML := `
rules:
- id: "CRED-EXPOSE-RESPONSE"
name: "响应体凭证泄露检测"
description: "检测 API 响应中是否包含可复用的供应商凭证片段"
severity: "P0"
matchers:
- type: "regex_match"
pattern: "(sk-|ak-|api_key|secret|token).*[a-zA-Z0-9]{20,}"
target: "response_body"
scope: "all"
action:
primary: "block"
secondary: "alert"
audit:
event_name: "CRED-EXPOSE-RESPONSE"
event_category: "CRED"
event_sub_category: "EXPOSE"
`
_, err = tmpfile.WriteString(validYAML)
require.NoError(t, err)
tmpfile.Close()
// 测试加载
loader := NewRuleLoader()
rules, err := loader.LoadFromFile(tmpfile.Name())
assert.NoError(t, err)
assert.NotNil(t, rules)
assert.Len(t, rules, 1)
rule := rules[0]
assert.Equal(t, "CRED-EXPOSE-RESPONSE", rule.ID)
assert.Equal(t, "P0", rule.Severity)
assert.Equal(t, "block", rule.Action.Primary)
}
// TestRuleLoader_InvalidYaml 测试加载无效YAML
func TestRuleLoader_InvalidYaml(t *testing.T) {
// 创建临时无效YAML文件
tmpfile, err := os.CreateTemp("", "invalid_rule_*.yaml")
require.NoError(t, err)
defer os.Remove(tmpfile.Name())
invalidYAML := `
rules:
- id: "CRED-EXPOSE-RESPONSE"
name: "响应体凭证泄露检测"
severity: "P0"
# 缺少必需的matchers字段
action:
primary: "block"
`
_, err = tmpfile.WriteString(invalidYAML)
require.NoError(t, err)
tmpfile.Close()
// 测试加载
loader := NewRuleLoader()
rules, err := loader.LoadFromFile(tmpfile.Name())
assert.Error(t, err)
assert.Nil(t, rules)
}
// TestRuleLoader_MissingFields 测试缺少必需字段
func TestRuleLoader_MissingFields(t *testing.T) {
// 创建缺少必需字段的YAML
tmpfile, err := os.CreateTemp("", "missing_fields_*.yaml")
require.NoError(t, err)
defer os.Remove(tmpfile.Name())
// 缺少 id 字段
missingIDYAML := `
rules:
- name: "响应体凭证泄露检测"
severity: "P0"
matchers:
- type: "regex_match"
action:
primary: "block"
`
_, err = tmpfile.WriteString(missingIDYAML)
require.NoError(t, err)
tmpfile.Close()
loader := NewRuleLoader()
rules, err := loader.LoadFromFile(tmpfile.Name())
assert.Error(t, err)
assert.Nil(t, rules)
assert.Contains(t, err.Error(), "missing required field: id")
}
// TestRuleLoader_FileNotFound 测试文件不存在
func TestRuleLoader_FileNotFound(t *testing.T) {
loader := NewRuleLoader()
rules, err := loader.LoadFromFile("/nonexistent/path/rules.yaml")
assert.Error(t, err)
assert.Nil(t, rules)
}
// TestRuleLoader_ValidateRuleFormat 测试规则格式验证
func TestRuleLoader_ValidateRuleFormat(t *testing.T) {
tests := []struct {
name string
ruleID string
valid bool
}{
{"标准格式", "CRED-EXPOSE-RESPONSE", true},
{"带Detail格式", "CRED-EXPOSE-RESPONSE-DETAIL", true},
{"双连字符", "CRED--EXPOSE-RESPONSE", false},
{"小写字母", "cred-expose-response", false},
{"单字符Category", "C-EXPOSE-RESPONSE", false},
}
loader := NewRuleLoader()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
valid := loader.ValidateRuleID(tt.ruleID)
assert.Equal(t, tt.valid, valid)
})
}
}
// TestRuleLoader_EmptyRules 测试空规则列表
func TestRuleLoader_EmptyRules(t *testing.T) {
tmpfile, err := os.CreateTemp("", "empty_rules_*.yaml")
require.NoError(t, err)
defer os.Remove(tmpfile.Name())
emptyYAML := `
rules: []
`
_, err = tmpfile.WriteString(emptyYAML)
require.NoError(t, err)
tmpfile.Close()
loader := NewRuleLoader()
rules, err := loader.LoadFromFile(tmpfile.Name())
assert.NoError(t, err)
assert.NotNil(t, rules)
assert.Len(t, rules, 0)
}