Files
lijiaoqiao/supply-api/internal/audit/model/audit_metrics_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

459 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package model
import (
"testing"
"github.com/stretchr/testify/assert"
)
// ==================== M-013 凭证暴露事件详情 ====================
func TestCredentialExposureDetail_New(t *testing.T) {
// M-013: 凭证暴露事件专用
detail := NewCredentialExposureDetail(
"exposed_in_response",
"response_body",
"sk-[a-zA-Z0-9]{20,}",
"sk-xxxxxx****xxxx",
"SCAN-001",
)
assert.Equal(t, "exposed_in_response", detail.ExposureType)
assert.Equal(t, "response_body", detail.ExposureLocation)
assert.Equal(t, "sk-[a-zA-Z0-9]{20,}", detail.ExposurePattern)
assert.Equal(t, "sk-xxxxxx****xxxx", detail.ExposedFragment)
assert.Equal(t, "SCAN-001", detail.ScanRuleID)
assert.False(t, detail.Resolved)
assert.Nil(t, detail.ResolvedAt)
assert.Nil(t, detail.ResolvedBy)
assert.Empty(t, detail.ResolutionNotes)
}
func TestCredentialExposureDetail_Resolve(t *testing.T) {
detail := NewCredentialExposureDetail(
"exposed_in_response",
"response_body",
"sk-[a-zA-Z0-9]{20,}",
"sk-xxxxxx****xxxx",
"SCAN-001",
)
detail.Resolve(1001, "Fixed by adding masking")
assert.True(t, detail.Resolved)
assert.NotNil(t, detail.ResolvedAt)
assert.Equal(t, int64(1001), *detail.ResolvedBy)
assert.Equal(t, "Fixed by adding masking", detail.ResolutionNotes)
}
func TestCredentialExposureDetail_ExposureTypes(t *testing.T) {
// 验证暴露类型常量
validTypes := []string{
"exposed_in_response",
"exposed_in_log",
"exposed_in_export",
}
for _, exposureType := range validTypes {
detail := NewCredentialExposureDetail(
exposureType,
"response_body",
"pattern",
"fragment",
"SCAN-001",
)
assert.Equal(t, exposureType, detail.ExposureType)
}
}
func TestCredentialExposureDetail_ExposureLocations(t *testing.T) {
// 验证暴露位置常量
validLocations := []string{
"response_body",
"response_header",
"log_file",
"export_file",
}
for _, location := range validLocations {
detail := NewCredentialExposureDetail(
"exposed_in_response",
location,
"pattern",
"fragment",
"SCAN-001",
)
assert.Equal(t, location, detail.ExposureLocation)
}
}
// ==================== M-014 凭证入站事件详情 ====================
func TestCredentialIngressDetail_New(t *testing.T) {
// M-014: 凭证入站类型专用
detail := NewCredentialIngressDetail(
"platform_token",
"platform_token",
true,
true,
false,
)
assert.Equal(t, "platform_token", detail.RequestCredentialType)
assert.Equal(t, "platform_token", detail.ExpectedCredentialType)
assert.True(t, detail.CoverageCompliant)
assert.True(t, detail.PlatformTokenPresent)
assert.False(t, detail.UpstreamKeyPresent)
assert.False(t, detail.Reviewed)
assert.Nil(t, detail.ReviewedAt)
assert.Nil(t, detail.ReviewedBy)
}
func TestCredentialIngressDetail_NonCompliant(t *testing.T) {
// M-014 非合规场景:使用 query_key 而不是 platform_token
detail := NewCredentialIngressDetail(
"query_key",
"platform_token",
false,
false,
true,
)
assert.Equal(t, "query_key", detail.RequestCredentialType)
assert.Equal(t, "platform_token", detail.ExpectedCredentialType)
assert.False(t, detail.CoverageCompliant)
assert.False(t, detail.PlatformTokenPresent)
assert.True(t, detail.UpstreamKeyPresent)
}
func TestCredentialIngressDetail_Review(t *testing.T) {
detail := NewCredentialIngressDetail(
"platform_token",
"platform_token",
true,
true,
false,
)
detail.Review(1001)
assert.True(t, detail.Reviewed)
assert.NotNil(t, detail.ReviewedAt)
assert.Equal(t, int64(1001), *detail.ReviewedBy)
}
func TestCredentialIngressDetail_CredentialTypes(t *testing.T) {
// 验证凭证类型
testCases := []struct {
credType string
platformToken bool
upstreamKey bool
compliant bool
}{
{"platform_token", true, false, true},
{"query_key", false, false, false},
{"upstream_api_key", false, true, false},
{"none", false, false, false},
}
for _, tc := range testCases {
detail := NewCredentialIngressDetail(
tc.credType,
"platform_token",
tc.compliant,
tc.platformToken,
tc.upstreamKey,
)
assert.Equal(t, tc.compliant, detail.CoverageCompliant, "Compliance mismatch for %s", tc.credType)
}
}
// ==================== M-015 直连绕过事件详情 ====================
func TestDirectCallDetail_New(t *testing.T) {
// M-015: 直连绕过专用
detail := NewDirectCallDetail(
1001, // consumerID
2001, // supplierID
"https://supplier.example.com/v1/chat/completions",
false, // viaPlatform
"ip_bypass",
"upstream_api_pattern_match",
)
assert.Equal(t, int64(1001), detail.ConsumerID)
assert.Equal(t, int64(2001), detail.SupplierID)
assert.Equal(t, "https://supplier.example.com/v1/chat/completions", detail.DirectEndpoint)
assert.False(t, detail.ViaPlatform)
assert.Equal(t, "ip_bypass", detail.BypassType)
assert.Equal(t, "upstream_api_pattern_match", detail.DetectionMethod)
assert.False(t, detail.Blocked)
assert.Nil(t, detail.BlockedAt)
assert.Empty(t, detail.BlockReason)
}
func TestDirectCallDetail_Block(t *testing.T) {
detail := NewDirectCallDetail(
1001,
2001,
"https://supplier.example.com/v1/chat/completions",
false,
"ip_bypass",
"upstream_api_pattern_match",
)
detail.Block("P0 event - immediate block")
assert.True(t, detail.Blocked)
assert.NotNil(t, detail.BlockedAt)
assert.Equal(t, "P0 event - immediate block", detail.BlockReason)
}
func TestDirectCallDetail_BypassTypes(t *testing.T) {
// 验证绕过类型常量
validBypassTypes := []string{
"ip_bypass",
"proxy_bypass",
"config_bypass",
"dns_bypass",
}
for _, bypassType := range validBypassTypes {
detail := NewDirectCallDetail(
1001,
2001,
"https://example.com",
false,
bypassType,
"detection_method",
)
assert.Equal(t, bypassType, detail.BypassType)
}
}
func TestDirectCallDetail_DetectionMethods(t *testing.T) {
// 验证检测方法常量
validMethods := []string{
"upstream_api_pattern_match",
"dns_resolution_check",
"connection_source_check",
"ip_whitelist_check",
}
for _, method := range validMethods {
detail := NewDirectCallDetail(
1001,
2001,
"https://example.com",
false,
"ip_bypass",
method,
)
assert.Equal(t, method, detail.DetectionMethod)
}
}
func TestDirectCallDetail_ViaPlatform(t *testing.T) {
// 通过平台的调用不应该标记为直连
detail := NewDirectCallDetail(
1001,
2001,
"https://platform.example.com/v1/chat/completions",
true, // viaPlatform = true
"",
"platform_proxy",
)
assert.True(t, detail.ViaPlatform)
assert.False(t, detail.Blocked)
}
// ==================== M-016 Query Key 拒绝事件详情 ====================
func TestQueryKeyRejectDetail_New(t *testing.T) {
// M-016: query key 拒绝专用
detail := NewQueryKeyRejectDetail(
"qk-12345",
"/v1/chat/completions",
"not_allowed",
"QUERY_KEY_NOT_ALLOWED",
)
assert.Equal(t, "qk-12345", detail.QueryKeyID)
assert.Equal(t, "/v1/chat/completions", detail.RequestedEndpoint)
assert.Equal(t, "not_allowed", detail.RejectReason)
assert.Equal(t, "QUERY_KEY_NOT_ALLOWED", detail.RejectCode)
assert.True(t, detail.FirstOccurrence)
assert.Equal(t, 1, detail.OccurrenceCount)
}
func TestQueryKeyRejectDetail_RecordOccurrence(t *testing.T) {
detail := NewQueryKeyRejectDetail(
"qk-12345",
"/v1/chat/completions",
"not_allowed",
"QUERY_KEY_NOT_ALLOWED",
)
// 第二次发生
detail.RecordOccurrence(false)
assert.Equal(t, 2, detail.OccurrenceCount)
assert.False(t, detail.FirstOccurrence)
// 第三次发生
detail.RecordOccurrence(false)
assert.Equal(t, 3, detail.OccurrenceCount)
}
func TestQueryKeyRejectDetail_RejectReasons(t *testing.T) {
// 验证拒绝原因常量
validReasons := []string{
"not_allowed",
"expired",
"malformed",
"revoked",
"rate_limited",
}
for _, reason := range validReasons {
detail := NewQueryKeyRejectDetail(
"qk-12345",
"/v1/chat/completions",
reason,
"QUERY_KEY_REJECT",
)
assert.Equal(t, reason, detail.RejectReason)
}
}
func TestQueryKeyRejectDetail_RejectCodes(t *testing.T) {
// 验证拒绝码常量
validCodes := []string{
"QUERY_KEY_NOT_ALLOWED",
"QUERY_KEY_EXPIRED",
"QUERY_KEY_MALFORMED",
"QUERY_KEY_REVOKED",
"QUERY_KEY_RATE_LIMITED",
}
for _, code := range validCodes {
detail := NewQueryKeyRejectDetail(
"qk-12345",
"/v1/chat/completions",
"not_allowed",
code,
)
assert.Equal(t, code, detail.RejectCode)
}
}
// ==================== 指标计算辅助函数 ====================
func TestCalculateM013(t *testing.T) {
// M-013: 凭证泄露事件数 = 0
events := []struct {
eventName string
resolved bool
}{
{"CRED-EXPOSE-RESPONSE", true},
{"CRED-EXPOSE-RESPONSE", true},
{"CRED-EXPOSE-LOG", false},
{"AUTH-TOKEN-OK", true},
}
var unresolvedCount int
for _, e := range events {
if IsM013Event(e.eventName) && !e.resolved {
unresolvedCount++
}
}
assert.Equal(t, 1, unresolvedCount, "M-013 should have 1 unresolved event")
}
func TestCalculateM014(t *testing.T) {
// M-014: 平台凭证入站覆盖率 = 100%
events := []struct {
credentialType string
compliant bool
}{
{"platform_token", true},
{"platform_token", true},
{"query_key", false},
{"upstream_api_key", false},
{"platform_token", true},
}
var platformCount, totalCount int
for _, e := range events {
if IsM014Compliant(e.credentialType) {
platformCount++
}
totalCount++
}
coverage := float64(platformCount) / float64(totalCount) * 100
assert.Equal(t, 60.0, coverage, "M-014 coverage should be 60%%")
assert.Equal(t, 3, platformCount)
assert.Equal(t, 5, totalCount)
}
func TestCalculateM015(t *testing.T) {
// M-015: 直连事件数 = 0
events := []struct {
targetDirect bool
blocked bool
}{
{targetDirect: true, blocked: false},
{targetDirect: true, blocked: true},
{targetDirect: false, blocked: false},
{targetDirect: true, blocked: false},
}
var directCallCount, blockedCount int
for _, e := range events {
if e.targetDirect {
directCallCount++
if e.blocked {
blockedCount++
}
}
}
assert.Equal(t, 3, directCallCount, "M-015 should have 3 direct call events")
assert.Equal(t, 1, blockedCount, "M-015 should have 1 blocked event")
}
func TestCalculateM016(t *testing.T) {
// M-016: query key 拒绝率 = 100%
// 分母所有query key请求不含被拒绝的无效请求
events := []struct {
eventName string
}{
{"AUTH-QUERY-KEY"},
{"AUTH-QUERY-REJECT"},
{"AUTH-QUERY-KEY"},
{"AUTH-QUERY-REJECT"},
{"AUTH-TOKEN-OK"},
}
var totalQueryKey, rejectedCount int
for _, e := range events {
if IsM016Event(e.eventName) {
totalQueryKey++
if e.eventName == "AUTH-QUERY-REJECT" {
rejectedCount++
}
}
}
rejectRate := float64(rejectedCount) / float64(totalQueryKey) * 100
assert.Equal(t, 4, totalQueryKey, "M-016 should have 4 query key events")
assert.Equal(t, 2, rejectedCount, "M-016 should have 2 rejected events")
assert.Equal(t, 50.0, rejectRate, "M-016 reject rate should be 50%%")
}
// IsM014Compliant 检查凭证类型是否为M-014合规
func IsM014Compliant(credentialType string) bool {
return credentialType == CredentialTypePlatformToken
}