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规范
This commit is contained in:
Your Name
2026-04-02 23:35:53 +08:00
parent ed0961d486
commit 89104bd0db
94 changed files with 24738 additions and 5 deletions

View File

@@ -0,0 +1,186 @@
package events
import (
"strings"
)
// CRED事件类别常量
const (
CategoryCRED = "CRED"
SubCategoryEXPOSE = "EXPOSE"
SubCategoryINGRESS = "INGRESS"
SubCategoryROTATE = "ROTATE"
SubCategoryREVOKE = "REVOKE"
SubCategoryVALIDATE = "VALIDATE"
SubCategoryDIRECT = "DIRECT"
)
// CRED事件列表
var credEvents = []string{
// 凭证暴露事件 (CRED-EXPOSE)
"CRED-EXPOSE-RESPONSE", // 响应中暴露凭证
"CRED-EXPOSE-LOG", // 日志中暴露凭证
"CRED-EXPOSE-EXPORT", // 导出文件中暴露凭证
// 凭证入站事件 (CRED-INGRESS)
"CRED-INGRESS-PLATFORM", // 平台凭证入站
"CRED-INGRESS-SUPPLIER", // 供应商凭证入站
// 凭证轮换事件 (CRED-ROTATE)
"CRED-ROTATE",
// 凭证吊销事件 (CRED-REVOKE)
"CRED-REVOKE",
// 凭证验证事件 (CRED-VALIDATE)
"CRED-VALIDATE",
// 直连绕过事件 (CRED-DIRECT)
"CRED-DIRECT-SUPPLIER", // 直连供应商
"CRED-DIRECT-BYPASS", // 绕过直连
}
// CRED事件结果码映射
var credResultCodes = map[string]string{
"CRED-EXPOSE-RESPONSE": "SEC_CRED_EXPOSED",
"CRED-EXPOSE-LOG": "SEC_CRED_EXPOSED",
"CRED-EXPOSE-EXPORT": "SEC_CRED_EXPOSED",
"CRED-INGRESS-PLATFORM": "CRED_INGRESS_OK",
"CRED-INGRESS-SUPPLIER": "CRED_INGRESS_OK",
"CRED-DIRECT-SUPPLIER": "SEC_DIRECT_BYPASS",
"CRED-DIRECT-BYPASS": "SEC_DIRECT_BYPASS",
"CRED-ROTATE": "CRED_ROTATE_OK",
"CRED-REVOKE": "CRED_REVOKE_OK",
"CRED-VALIDATE": "CRED_VALIDATE_OK",
}
// CRED指标名称映射
var credMetricNames = map[string]string{
"CRED-EXPOSE-RESPONSE": "supplier_credential_exposure_events",
"CRED-EXPOSE-LOG": "supplier_credential_exposure_events",
"CRED-EXPOSE-EXPORT": "supplier_credential_exposure_events",
"CRED-INGRESS-PLATFORM": "platform_credential_ingress_coverage_pct",
"CRED-INGRESS-SUPPLIER": "platform_credential_ingress_coverage_pct",
"CRED-DIRECT-SUPPLIER": "direct_supplier_call_by_consumer_events",
"CRED-DIRECT-BYPASS": "direct_supplier_call_by_consumer_events",
}
// GetCREDEvents 返回所有CRED事件
func GetCREDEvents() []string {
return credEvents
}
// GetCREDExposeEvents 返回所有凭证暴露事件
func GetCREDExposeEvents() []string {
return []string{
"CRED-EXPOSE-RESPONSE",
"CRED-EXPOSE-LOG",
"CRED-EXPOSE-EXPORT",
}
}
// GetCREDFngressEvents 返回所有凭证入站事件
func GetCREDFngressEvents() []string {
return []string{
"CRED-INGRESS-PLATFORM",
"CRED-INGRESS-SUPPLIER",
}
}
// GetCREDDnirectEvents 返回所有直连绕过事件
func GetCREDDnirectEvents() []string {
return []string{
"CRED-DIRECT-SUPPLIER",
"CRED-DIRECT-BYPASS",
}
}
// GetCREDEventCategory 返回CRED事件的类别
func GetCREDEventCategory(eventName string) string {
if strings.HasPrefix(eventName, "CRED-") {
return CategoryCRED
}
if eventName == "CRED-ROTATE" || eventName == "CRED-REVOKE" || eventName == "CRED-VALIDATE" {
return CategoryCRED
}
return ""
}
// GetCREDEventSubCategory 返回CRED事件的子类别
func GetCREDEventSubCategory(eventName string) string {
if strings.HasPrefix(eventName, "CRED-EXPOSE") {
return SubCategoryEXPOSE
}
if strings.HasPrefix(eventName, "CRED-INGRESS") {
return SubCategoryINGRESS
}
if strings.HasPrefix(eventName, "CRED-DIRECT") {
return SubCategoryDIRECT
}
if strings.HasPrefix(eventName, "CRED-ROTATE") {
return SubCategoryROTATE
}
if strings.HasPrefix(eventName, "CRED-REVOKE") {
return SubCategoryREVOKE
}
if strings.HasPrefix(eventName, "CRED-VALIDATE") {
return SubCategoryVALIDATE
}
return ""
}
// IsValidCREDEvent 检查事件名称是否为有效的CRED事件
func IsValidCREDEvent(eventName string) bool {
for _, e := range credEvents {
if e == eventName {
return true
}
}
return false
}
// IsCREDExposeEvent 检查是否为凭证暴露事件M-013相关
func IsCREDExposeEvent(eventName string) bool {
return strings.HasPrefix(eventName, "CRED-EXPOSE")
}
// IsCREDFngressEvent 检查是否为凭证入站事件M-014相关
func IsCREDFngressEvent(eventName string) bool {
return strings.HasPrefix(eventName, "CRED-INGRESS")
}
// IsCREDDnirectEvent 检查是否为直连绕过事件M-015相关
func IsCREDDnirectEvent(eventName string) bool {
return strings.HasPrefix(eventName, "CRED-DIRECT")
}
// GetCREDMetricName 获取CRED事件对应的指标名称
func GetCREDMetricName(eventName string) string {
if metric, ok := credMetricNames[eventName]; ok {
return metric
}
return ""
}
// GetCREDEventResultCode 获取CRED事件对应的结果码
func GetCREDEventResultCode(eventName string) string {
if code, ok := credResultCodes[eventName]; ok {
return code
}
return ""
}
// IsCREDExposeEvent 检查是否为M-013事件凭证暴露
func IsM013RelatedEvent(eventName string) bool {
return IsCREDExposeEvent(eventName)
}
// IsCREDFngressEvent 检查是否为M-014事件凭证入站
func IsM014RelatedEvent(eventName string) bool {
return IsCREDFngressEvent(eventName)
}
// IsCREDDnirectEvent 检查是否为M-015事件直连绕过
func IsM015RelatedEvent(eventName string) bool {
return IsCREDDnirectEvent(eventName)
}

View File

@@ -0,0 +1,145 @@
package events
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCREDEvents_Categories(t *testing.T) {
// 测试 CRED 事件类别
events := GetCREDEvents()
// CRED-EXPOSE-RESPONSE: 响应中暴露凭证
assert.Contains(t, events, "CRED-EXPOSE-RESPONSE", "Should contain CRED-EXPOSE-RESPONSE")
// CRED-INGRESS-PLATFORM: 平台凭证入站
assert.Contains(t, events, "CRED-INGRESS-PLATFORM", "Should contain CRED-INGRESS-PLATFORM")
// CRED-DIRECT-SUPPLIER: 直连供应商
assert.Contains(t, events, "CRED-DIRECT-SUPPLIER", "Should contain CRED-DIRECT-SUPPLIER")
}
func TestCREDEvents_ExposeEvents(t *testing.T) {
// 测试 CRED-EXPOSE 事件
events := GetCREDExposeEvents()
assert.Contains(t, events, "CRED-EXPOSE-RESPONSE")
assert.Contains(t, events, "CRED-EXPOSE-LOG")
assert.Contains(t, events, "CRED-EXPOSE-EXPORT")
}
func TestCREDEvents_IngressEvents(t *testing.T) {
// 测试 CRED-INGRESS 事件
events := GetCREDFngressEvents()
assert.Contains(t, events, "CRED-INGRESS-PLATFORM")
assert.Contains(t, events, "CRED-INGRESS-SUPPLIER")
}
func TestCREDEvents_DirectEvents(t *testing.T) {
// 测试 CRED-DIRECT 事件
events := GetCREDDnirectEvents()
assert.Contains(t, events, "CRED-DIRECT-SUPPLIER")
assert.Contains(t, events, "CRED-DIRECT-BYPASS")
}
func TestCREDEvents_GetEventCategory(t *testing.T) {
// 所有CRED事件的类别应该是CRED
events := GetCREDEvents()
for _, eventName := range events {
category := GetCREDEventCategory(eventName)
assert.Equal(t, "CRED", category, "Event %s should have category CRED", eventName)
}
}
func TestCREDEvents_GetEventSubCategory(t *testing.T) {
// 测试CRED事件的子类别
testCases := []struct {
eventName string
expectedSubCategory string
}{
{"CRED-EXPOSE-RESPONSE", "EXPOSE"},
{"CRED-INGRESS-PLATFORM", "INGRESS"},
{"CRED-DIRECT-SUPPLIER", "DIRECT"},
{"CRED-ROTATE", "ROTATE"},
{"CRED-REVOKE", "REVOKE"},
}
for _, tc := range testCases {
t.Run(tc.eventName, func(t *testing.T) {
subCategory := GetCREDEventSubCategory(tc.eventName)
assert.Equal(t, tc.expectedSubCategory, subCategory)
})
}
}
func TestCREDEvents_IsValidEvent(t *testing.T) {
// 测试有效事件验证
assert.True(t, IsValidCREDEvent("CRED-EXPOSE-RESPONSE"))
assert.True(t, IsValidCREDEvent("CRED-INGRESS-PLATFORM"))
assert.True(t, IsValidCREDEvent("CRED-DIRECT-SUPPLIER"))
assert.False(t, IsValidCREDEvent("INVALID-EVENT"))
assert.False(t, IsValidCREDEvent("AUTH-TOKEN-OK"))
}
func TestCREDEvents_IsM013Event(t *testing.T) {
// 测试M-013相关事件
assert.True(t, IsCREDExposeEvent("CRED-EXPOSE-RESPONSE"))
assert.True(t, IsCREDExposeEvent("CRED-EXPOSE-LOG"))
assert.False(t, IsCREDExposeEvent("CRED-INGRESS-PLATFORM"))
}
func TestCREDEvents_IsM014Event(t *testing.T) {
// 测试M-014相关事件
assert.True(t, IsCREDFngressEvent("CRED-INGRESS-PLATFORM"))
assert.True(t, IsCREDFngressEvent("CRED-INGRESS-SUPPLIER"))
assert.False(t, IsCREDFngressEvent("CRED-EXPOSE-RESPONSE"))
}
func TestCREDEvents_IsM015Event(t *testing.T) {
// 测试M-015相关事件
assert.True(t, IsCREDDnirectEvent("CRED-DIRECT-SUPPLIER"))
assert.True(t, IsCREDDnirectEvent("CRED-DIRECT-BYPASS"))
assert.False(t, IsCREDDnirectEvent("CRED-INGRESS-PLATFORM"))
}
func TestCREDEvents_GetMetricName(t *testing.T) {
// 测试指标名称映射
testCases := []struct {
eventName string
expectedMetric string
}{
{"CRED-EXPOSE-RESPONSE", "supplier_credential_exposure_events"},
{"CRED-EXPOSE-LOG", "supplier_credential_exposure_events"},
{"CRED-INGRESS-PLATFORM", "platform_credential_ingress_coverage_pct"},
{"CRED-DIRECT-SUPPLIER", "direct_supplier_call_by_consumer_events"},
}
for _, tc := range testCases {
t.Run(tc.eventName, func(t *testing.T) {
metric := GetCREDMetricName(tc.eventName)
assert.Equal(t, tc.expectedMetric, metric)
})
}
}
func TestCREDEvents_GetResultCode(t *testing.T) {
// 测试CRED事件结果码
testCases := []struct {
eventName string
expectedCode string
}{
{"CRED-EXPOSE-RESPONSE", "SEC_CRED_EXPOSED"},
{"CRED-INGRESS-PLATFORM", "CRED_INGRESS_OK"},
{"CRED-DIRECT-SUPPLIER", "SEC_DIRECT_BYPASS"},
}
for _, tc := range testCases {
t.Run(tc.eventName, func(t *testing.T) {
code := GetCREDEventResultCode(tc.eventName)
assert.Equal(t, tc.expectedCode, code)
})
}
}

View File

@@ -0,0 +1,195 @@
package events
import (
"fmt"
)
// SECURITY事件类别常量
const (
CategorySECURITY = "SECURITY"
SubCategoryVIOLATION = "VIOLATION"
SubCategoryALERT = "ALERT"
SubCategoryBREACH = "BREACH"
)
// SECURITY事件列表
var securityEvents = []string{
// 不变量违反事件 (INVARIANT-VIOLATION)
"INV-PKG-001", // 供应方资质过期
"INV-PKG-002", // 供应方余额为负
"INV-PKG-003", // 售价不得低于保护价
"INV-SET-001", // processing/completed 不可撤销
"INV-SET-002", // 提现金额不得超过可提现余额
"INV-SET-003", // 结算单金额与余额流水必须平衡
// 安全突破事件 (SECURITY-BREACH)
"SEC-BREACH-001", // 凭证泄露突破
"SEC-BREACH-002", // 权限绕过突破
// 安全告警事件 (SECURITY-ALERT)
"SEC-ALERT-001", // 可疑访问告警
"SEC-ALERT-002", // 异常行为告警
}
// 不变量违反事件到结果码的映射
var invariantResultCodes = map[string]string{
"INV-PKG-001": "SEC_INV_PKG_001",
"INV-PKG-002": "SEC_INV_PKG_002",
"INV-PKG-003": "SEC_INV_PKG_003",
"INV-SET-001": "SEC_INV_SET_001",
"INV-SET-002": "SEC_INV_SET_002",
"INV-SET-003": "SEC_INV_SET_003",
}
// 事件描述映射
var securityEventDescriptions = map[string]string{
"INV-PKG-001": "供应方资质过期,资质验证失败",
"INV-PKG-002": "供应方余额为负,余额检查失败",
"INV-PKG-003": "售价不得低于保护价,价格校验失败",
"INV-SET-001": "结算单状态为processing/completed不可撤销",
"INV-SET-002": "提现金额不得超过可提现余额",
"INV-SET-003": "结算单金额与余额流水不平衡",
"SEC-BREACH-001": "检测到凭证泄露安全突破",
"SEC-BREACH-002": "检测到权限绕过安全突破",
"SEC-ALERT-001": "检测到可疑访问行为",
"SEC-ALERT-002": "检测到异常行为",
}
// GetSECURITYEvents 返回所有SECURITY事件
func GetSECURITYEvents() []string {
return securityEvents
}
// GetInvariantViolationEvents 返回所有不变量违反事件
func GetInvariantViolationEvents() []string {
return []string{
"INV-PKG-001",
"INV-PKG-002",
"INV-PKG-003",
"INV-SET-001",
"INV-SET-002",
"INV-SET-003",
}
}
// GetSecurityAlertEvents 返回所有安全告警事件
func GetSecurityAlertEvents() []string {
return []string{
"SEC-ALERT-001",
"SEC-ALERT-002",
}
}
// GetSecurityBreachEvents 返回所有安全突破事件
func GetSecurityBreachEvents() []string {
return []string{
"SEC-BREACH-001",
"SEC-BREACH-002",
}
}
// GetEventCategory 返回事件的类别
func GetEventCategory(eventName string) string {
if isInvariantViolation(eventName) || isSecurityBreach(eventName) || isSecurityAlert(eventName) {
return CategorySECURITY
}
return ""
}
// GetEventSubCategory 返回事件的子类别
func GetEventSubCategory(eventName string) string {
if isInvariantViolation(eventName) {
return SubCategoryVIOLATION
}
if isSecurityBreach(eventName) {
return SubCategoryBREACH
}
if isSecurityAlert(eventName) {
return SubCategoryALERT
}
return ""
}
// GetResultCode 返回事件对应的结果码
func GetResultCode(eventName string) string {
if code, ok := invariantResultCodes[eventName]; ok {
return code
}
return ""
}
// GetEventDescription 返回事件的描述
func GetEventDescription(eventName string) string {
if desc, ok := securityEventDescriptions[eventName]; ok {
return desc
}
return ""
}
// IsValidEvent 检查事件名称是否有效
func IsValidEvent(eventName string) bool {
for _, e := range securityEvents {
if e == eventName {
return true
}
}
return false
}
// isInvariantViolation 检查是否为不变量违反事件
func isInvariantViolation(eventName string) bool {
for _, e := range getInvariantViolationEvents() {
if e == eventName {
return true
}
}
return false
}
// getInvariantViolationEvents 返回不变量违反事件列表(内部使用)
func getInvariantViolationEvents() []string {
return []string{
"INV-PKG-001",
"INV-PKG-002",
"INV-PKG-003",
"INV-SET-001",
"INV-SET-002",
"INV-SET-003",
}
}
// isSecurityBreach 检查是否为安全突破事件
func isSecurityBreach(eventName string) bool {
prefixes := []string{"SEC-BREACH"}
for _, prefix := range prefixes {
if len(eventName) >= len(prefix) && eventName[:len(prefix)] == prefix {
return true
}
}
return false
}
// isSecurityAlert 检查是否为安全告警事件
func isSecurityAlert(eventName string) bool {
prefixes := []string{"SEC-ALERT"}
for _, prefix := range prefixes {
if len(eventName) >= len(prefix) && eventName[:len(prefix)] == prefix {
return true
}
}
return false
}
// FormatSECURITYEvent 格式化SECURITY事件
func FormatSECURITYEvent(eventName string, params map[string]string) string {
desc := GetEventDescription(eventName)
if desc == "" {
return fmt.Sprintf("SECURITY event: %s", eventName)
}
// 如果有额外参数,追加到描述中
if len(params) > 0 {
return fmt.Sprintf("%s - %v", desc, params)
}
return desc
}

View File

@@ -0,0 +1,131 @@
package events
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestSECURITYEvents_InvariantViolation(t *testing.T) {
// 测试 invariant_violation 事件
events := GetSECURITYEvents()
// INV-PKG-001: 供应方资质过期
assert.Contains(t, events, "INV-PKG-001", "Should contain INV-PKG-001")
// INV-SET-001: processing/completed 不可撤销
assert.Contains(t, events, "INV-SET-001", "Should contain INV-SET-001")
}
func TestSECURITYEvents_AllEvents(t *testing.T) {
// 测试所有SECURITY事件
events := GetSECURITYEvents()
// 验证不变量违反事件
invariantEvents := GetInvariantViolationEvents()
for _, event := range invariantEvents {
assert.Contains(t, events, event, "SECURITY events should contain %s", event)
}
}
func TestSECURITYEvents_GetInvariantViolationEvents(t *testing.T) {
events := GetInvariantViolationEvents()
// INV-PKG-001: 供应方资质过期
assert.Contains(t, events, "INV-PKG-001")
// INV-PKG-002: 供应方余额为负
assert.Contains(t, events, "INV-PKG-002")
// INV-PKG-003: 售价不得低于保护价
assert.Contains(t, events, "INV-PKG-003")
// INV-SET-001: processing/completed 不可撤销
assert.Contains(t, events, "INV-SET-001")
// INV-SET-002: 提现金额不得超过可提现余额
assert.Contains(t, events, "INV-SET-002")
// INV-SET-003: 结算单金额与余额流水必须平衡
assert.Contains(t, events, "INV-SET-003")
}
func TestSECURITYEvents_GetSecurityAlertEvents(t *testing.T) {
events := GetSecurityAlertEvents()
// 安全告警事件应该存在
assert.NotEmpty(t, events)
}
func TestSECURITYEvents_GetSecurityBreachEvents(t *testing.T) {
events := GetSecurityBreachEvents()
// 安全突破事件应该存在
assert.NotEmpty(t, events)
}
func TestSECURITYEvents_GetEventCategory(t *testing.T) {
// 所有SECURITY事件的类别应该是SECURITY
events := GetSECURITYEvents()
for _, eventName := range events {
category := GetEventCategory(eventName)
assert.Equal(t, "SECURITY", category, "Event %s should have category SECURITY", eventName)
}
}
func TestSECURITYEvents_GetResultCode(t *testing.T) {
// 测试不变量违反事件的结果码映射
testCases := []struct {
eventName string
expectedCode string
}{
{"INV-PKG-001", "SEC_INV_PKG_001"},
{"INV-PKG-002", "SEC_INV_PKG_002"},
{"INV-PKG-003", "SEC_INV_PKG_003"},
{"INV-SET-001", "SEC_INV_SET_001"},
{"INV-SET-002", "SEC_INV_SET_002"},
{"INV-SET-003", "SEC_INV_SET_003"},
}
for _, tc := range testCases {
t.Run(tc.eventName, func(t *testing.T) {
code := GetResultCode(tc.eventName)
assert.Equal(t, tc.expectedCode, code, "Result code mismatch for %s", tc.eventName)
})
}
}
func TestSECURITYEvents_GetEventDescription(t *testing.T) {
// 测试事件描述
desc := GetEventDescription("INV-PKG-001")
assert.NotEmpty(t, desc)
assert.Contains(t, desc, "供应方资质", "Description should contain 供应方资质")
}
func TestSECURITYEvents_IsValidEvent(t *testing.T) {
// 测试有效事件验证
assert.True(t, IsValidEvent("INV-PKG-001"))
assert.True(t, IsValidEvent("INV-SET-001"))
assert.False(t, IsValidEvent("INVALID-EVENT"))
assert.False(t, IsValidEvent(""))
}
func TestSECURITYEvents_GetEventSubCategory(t *testing.T) {
// SECURITY事件的子类别应该是VIOLATION/ALERT/BREACH
testCases := []struct {
eventName string
expectedSubCategory string
}{
{"INV-PKG-001", "VIOLATION"},
{"INV-SET-001", "VIOLATION"},
{"SEC-BREACH-001", "BREACH"},
{"SEC-ALERT-001", "ALERT"},
}
for _, tc := range testCases {
t.Run(tc.eventName, func(t *testing.T) {
subCategory := GetEventSubCategory(tc.eventName)
assert.Equal(t, tc.expectedSubCategory, subCategory)
})
}
}