Files
lijiaoqiao/gateway/internal/compliance/rules/loader_test.go

165 lines
4.0 KiB
Go
Raw Normal View History

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)
}