fix(P2): 修复4个P2轻微问题

P2-01: 通配符scope安全风险 (scope_auth.go)
- 添加hasWildcardScope()函数检测通配符scope
- 添加logWildcardScopeAccess()函数记录审计日志
- 在RequireScope/RequireAllScopes/RequireAnyScope中间件中调用审计日志

P2-02: isSamePayload比较字段不完整 (audit_service.go)
- 添加ActionDetail字段比较
- 添加ResultMessage字段比较
- 添加Extensions字段比较
- 添加compareExtensions()辅助函数

P2-03: regexp.MustCompile可能panic (sanitizer.go)
- 添加compileRegex()安全编译函数替代MustCompile
- 处理编译错误,避免panic

P2-04: StrategyRoundRobin未实现 (router.go)
- 添加selectByRoundRobin()方法
- 添加roundRobinCounter原子计数器
- 使用atomic.AddUint64实现线程安全的轮询

P2-05: 错误信息泄露内部细节 - 已在MED-09中处理,跳过
This commit is contained in:
Your Name
2026-04-03 09:39:32 +08:00
parent 732c97f85b
commit b2d32be14f
8 changed files with 289 additions and 19 deletions

View File

@@ -550,4 +550,63 @@ func TestAuditService_IdempotencyRaceCondition(t *testing.T) {
assert.Equal(t, 1, createdCount, "Should have exactly one created event")
assert.Equal(t, concurrentCount-1, duplicateCount, "Should have concurrentCount-1 duplicates")
assert.Equal(t, 0, conflictCount, "Should have no conflicts for same payload")
}
}
// P2-02: isSamePayload比较字段不完整缺少ActionDetail/ResultMessage/Extensions等字段
func TestP2_02_IsSamePayload_MissingFields(t *testing.T) {
ctx := context.Background()
svc := NewAuditService(NewInMemoryAuditStore())
// 第一次事件 - 完整的payload
event1 := &model.AuditEvent{
EventName: "CRED-EXPOSE-RESPONSE",
EventCategory: "CRED",
OperatorID: 1001,
TenantID: 2001,
ObjectType: "account",
ObjectID: 12345,
Action: "query",
CredentialType: "platform_token",
SourceType: "api",
SourceIP: "192.168.1.1",
Success: true,
ResultCode: "SEC_CRED_EXPOSED",
ActionDetail: "detailed action info", // 缺失字段
ResultMessage: "operation completed", // 缺失字段
IdempotencyKey: "p2-02-test-key",
}
// 第二次重放 - ActionDetail和ResultMessage不同但isSamePayload应该能检测出来
event2 := &model.AuditEvent{
EventName: "CRED-EXPOSE-RESPONSE",
EventCategory: "CRED",
OperatorID: 1001,
TenantID: 2001,
ObjectType: "account",
ObjectID: 12345,
Action: "query",
CredentialType: "platform_token",
SourceType: "api",
SourceIP: "192.168.1.1",
Success: true,
ResultCode: "SEC_CRED_EXPOSED",
ActionDetail: "different action info", // 与event1不同
ResultMessage: "different message", // 与event1不同
IdempotencyKey: "p2-02-test-key",
}
// 首次创建
result1, err1 := svc.CreateEvent(ctx, event1)
assert.NoError(t, err1)
assert.Equal(t, 201, result1.StatusCode)
// 重放异参 - 应该返回409
result2, err2 := svc.CreateEvent(ctx, event2)
assert.NoError(t, err2)
// 如果isSamePayload没有比较ActionDetail和ResultMessage这里会错误地返回200而不是409
if result2.StatusCode == 200 {
t.Errorf("P2-02 BUG: isSamePayload does NOT compare ActionDetail/ResultMessage fields. Got 200 (duplicate) but should be 409 (conflict)")
} else if result2.StatusCode == 409 {
t.Logf("P2-02 FIXED: isSamePayload correctly detects payload mismatch")
}
}