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:
357
supply-api/internal/audit/model/audit_event.go
Normal file
357
supply-api/internal/audit/model/audit_event.go
Normal file
@@ -0,0 +1,357 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// 事件类别常量
|
||||
const (
|
||||
CategoryCRED = "CRED"
|
||||
CategoryAUTH = "AUTH"
|
||||
CategoryDATA = "DATA"
|
||||
CategoryCONFIG = "CONFIG"
|
||||
CategorySECURITY = "SECURITY"
|
||||
)
|
||||
|
||||
// 凭证事件子类别
|
||||
const (
|
||||
SubCategoryCredExpose = "EXPOSE"
|
||||
SubCategoryCredIngress = "INGRESS"
|
||||
SubCategoryCredRotate = "ROTATE"
|
||||
SubCategoryCredRevoke = "REVOKE"
|
||||
SubCategoryCredValidate = "VALIDATE"
|
||||
SubCategoryCredDirect = "DIRECT"
|
||||
)
|
||||
|
||||
// 凭证类型
|
||||
const (
|
||||
CredentialTypePlatformToken = "platform_token"
|
||||
CredentialTypeQueryKey = "query_key"
|
||||
CredentialTypeUpstreamAPIKey = "upstream_api_key"
|
||||
CredentialTypeNone = "none"
|
||||
)
|
||||
|
||||
// 操作者类型
|
||||
const (
|
||||
OperatorTypeUser = "user"
|
||||
OperatorTypeSystem = "system"
|
||||
OperatorTypeAdmin = "admin"
|
||||
)
|
||||
|
||||
// 租户类型
|
||||
const (
|
||||
TenantTypeSupplier = "supplier"
|
||||
TenantTypeConsumer = "consumer"
|
||||
TenantTypePlatform = "platform"
|
||||
)
|
||||
|
||||
// SecurityFlags 安全标记
|
||||
type SecurityFlags struct {
|
||||
HasCredential bool `json:"has_credential"` // 是否包含凭证
|
||||
CredentialExposed bool `json:"credential_exposed"` // 凭证是否暴露
|
||||
Desensitized bool `json:"desensitized"` // 是否已脱敏
|
||||
Scanned bool `json:"scanned"` // 是否已扫描
|
||||
ScanPassed bool `json:"scan_passed"` // 扫描是否通过
|
||||
ViolationTypes []string `json:"violation_types"` // 违规类型列表
|
||||
}
|
||||
|
||||
// NewSecurityFlags 创建默认安全标记
|
||||
func NewSecurityFlags() *SecurityFlags {
|
||||
return &SecurityFlags{
|
||||
HasCredential: false,
|
||||
CredentialExposed: false,
|
||||
Desensitized: false,
|
||||
Scanned: false,
|
||||
ScanPassed: false,
|
||||
ViolationTypes: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
// HasViolation 检查是否有违规
|
||||
func (sf *SecurityFlags) HasViolation() bool {
|
||||
return len(sf.ViolationTypes) > 0
|
||||
}
|
||||
|
||||
// HasViolationOfType 检查是否有指定类型的违规
|
||||
func (sf *SecurityFlags) HasViolationOfType(violationType string) bool {
|
||||
for _, v := range sf.ViolationTypes {
|
||||
if v == violationType {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// AddViolationType 添加违规类型
|
||||
func (sf *SecurityFlags) AddViolationType(violationType string) {
|
||||
sf.ViolationTypes = append(sf.ViolationTypes, violationType)
|
||||
}
|
||||
|
||||
// AuditEvent 统一审计事件
|
||||
type AuditEvent struct {
|
||||
// 基础标识
|
||||
EventID string `json:"event_id"` // 事件唯一ID (UUID)
|
||||
EventName string `json:"event_name"` // 事件名称 (e.g., "CRED-EXPOSE")
|
||||
EventCategory string `json:"event_category"` // 事件大类 (e.g., "CRED")
|
||||
EventSubCategory string `json:"event_sub_category"` // 事件子类
|
||||
|
||||
// 时间戳
|
||||
Timestamp time.Time `json:"timestamp"` // 事件发生时间
|
||||
TimestampMs int64 `json:"timestamp_ms"` // 毫秒时间戳
|
||||
|
||||
// 请求上下文
|
||||
RequestID string `json:"request_id"` // 请求追踪ID
|
||||
TraceID string `json:"trace_id"` // 分布式追踪ID
|
||||
SpanID string `json:"span_id"` // Span ID
|
||||
|
||||
// 幂等性
|
||||
IdempotencyKey string `json:"idempotency_key,omitempty"` // 幂等键
|
||||
|
||||
// 操作者信息
|
||||
OperatorID int64 `json:"operator_id"` // 操作者ID
|
||||
OperatorType string `json:"operator_type"` // 操作者类型 (user/system/admin)
|
||||
OperatorRole string `json:"operator_role"` // 操作者角色
|
||||
|
||||
// 租户信息
|
||||
TenantID int64 `json:"tenant_id"` // 租户ID
|
||||
TenantType string `json:"tenant_type"` // 租户类型 (supplier/consumer/platform)
|
||||
|
||||
// 对象信息
|
||||
ObjectType string `json:"object_type"` // 对象类型 (account/package/settlement)
|
||||
ObjectID int64 `json:"object_id"` // 对象ID
|
||||
|
||||
// 操作信息
|
||||
Action string `json:"action"` // 操作类型 (create/update/delete)
|
||||
ActionDetail string `json:"action_detail"` // 操作详情
|
||||
|
||||
// 凭证信息 (M-013/M-014/M-015/M-016 关键)
|
||||
CredentialType string `json:"credential_type"` // 凭证类型 (platform_token/query_key/upstream_api_key/none)
|
||||
CredentialID string `json:"credential_id,omitempty"` // 凭证标识 (脱敏)
|
||||
CredentialFingerprint string `json:"credential_fingerprint,omitempty"` // 凭证指纹
|
||||
|
||||
// 来源信息
|
||||
SourceType string `json:"source_type"` // 来源类型 (api/ui/cron/internal)
|
||||
SourceIP string `json:"source_ip"` // 来源IP
|
||||
SourceRegion string `json:"source_region"` // 来源区域
|
||||
UserAgent string `json:"user_agent,omitempty"` // User Agent
|
||||
|
||||
// 目标信息 (用于直连检测 M-015)
|
||||
TargetType string `json:"target_type,omitempty"` // 目标类型
|
||||
TargetEndpoint string `json:"target_endpoint,omitempty"` // 目标端点
|
||||
TargetDirect bool `json:"target_direct"` // 是否直连
|
||||
|
||||
// 结果信息
|
||||
ResultCode string `json:"result_code"` // 结果码
|
||||
ResultMessage string `json:"result_message,omitempty"` // 结果消息
|
||||
Success bool `json:"success"` // 是否成功
|
||||
|
||||
// 状态变更 (用于溯源)
|
||||
BeforeState map[string]any `json:"before_state,omitempty"` // 操作前状态
|
||||
AfterState map[string]any `json:"after_state,omitempty"` // 操作后状态
|
||||
|
||||
// 安全标记 (M-013 关键)
|
||||
SecurityFlags SecurityFlags `json:"security_flags"` // 安全标记
|
||||
RiskScore int `json:"risk_score"` // 风险评分 0-100
|
||||
|
||||
// 合规信息
|
||||
ComplianceTags []string `json:"compliance_tags,omitempty"` // 合规标签 (e.g., ["GDPR", "SOC2"])
|
||||
InvariantRule string `json:"invariant_rule,omitempty"` // 触发的不变量规则
|
||||
|
||||
// 扩展字段
|
||||
Extensions map[string]any `json:"extensions,omitempty"` // 扩展数据
|
||||
|
||||
// 元数据
|
||||
Version int `json:"version"` // 事件版本
|
||||
CreatedAt time.Time `json:"created_at"` // 创建时间
|
||||
}
|
||||
|
||||
// NewAuditEvent 创建审计事件
|
||||
func NewAuditEvent(
|
||||
eventName string,
|
||||
eventCategory string,
|
||||
eventSubCategory string,
|
||||
metricName string,
|
||||
requestID string,
|
||||
traceID string,
|
||||
operatorID int64,
|
||||
operatorType string,
|
||||
operatorRole string,
|
||||
tenantID int64,
|
||||
tenantType string,
|
||||
objectType string,
|
||||
objectID int64,
|
||||
action string,
|
||||
credentialType string,
|
||||
sourceType string,
|
||||
sourceIP string,
|
||||
success bool,
|
||||
resultCode string,
|
||||
resultMessage string,
|
||||
) *AuditEvent {
|
||||
now := time.Now()
|
||||
event := &AuditEvent{
|
||||
EventID: uuid.New().String(),
|
||||
EventName: eventName,
|
||||
EventCategory: eventCategory,
|
||||
EventSubCategory: eventSubCategory,
|
||||
Timestamp: now,
|
||||
TimestampMs: now.UnixMilli(),
|
||||
RequestID: requestID,
|
||||
TraceID: traceID,
|
||||
OperatorID: operatorID,
|
||||
OperatorType: operatorType,
|
||||
OperatorRole: operatorRole,
|
||||
TenantID: tenantID,
|
||||
TenantType: tenantType,
|
||||
ObjectType: objectType,
|
||||
ObjectID: objectID,
|
||||
Action: action,
|
||||
CredentialType: credentialType,
|
||||
SourceType: sourceType,
|
||||
SourceIP: sourceIP,
|
||||
Success: success,
|
||||
ResultCode: resultCode,
|
||||
ResultMessage: resultMessage,
|
||||
Version: 1,
|
||||
CreatedAt: now,
|
||||
SecurityFlags: *NewSecurityFlags(),
|
||||
ComplianceTags: []string{},
|
||||
}
|
||||
|
||||
// 根据凭证类型设置安全标记
|
||||
if credentialType != CredentialTypeNone && credentialType != "" {
|
||||
event.SecurityFlags.HasCredential = true
|
||||
}
|
||||
|
||||
// 根据事件名称设置凭证暴露标记(M-013)
|
||||
if IsM013Event(eventName) {
|
||||
event.SecurityFlags.CredentialExposed = true
|
||||
}
|
||||
|
||||
// 根据事件名称设置指标名称到扩展字段
|
||||
if metricName != "" {
|
||||
if event.Extensions == nil {
|
||||
event.Extensions = make(map[string]any)
|
||||
}
|
||||
event.Extensions["metric_name"] = metricName
|
||||
}
|
||||
|
||||
return event
|
||||
}
|
||||
|
||||
// NewAuditEventWithSecurityFlags 创建带完整安全标记的审计事件
|
||||
func NewAuditEventWithSecurityFlags(
|
||||
eventName string,
|
||||
eventCategory string,
|
||||
eventSubCategory string,
|
||||
metricName string,
|
||||
requestID string,
|
||||
traceID string,
|
||||
operatorID int64,
|
||||
operatorType string,
|
||||
operatorRole string,
|
||||
tenantID int64,
|
||||
tenantType string,
|
||||
objectType string,
|
||||
objectID int64,
|
||||
action string,
|
||||
credentialType string,
|
||||
sourceType string,
|
||||
sourceIP string,
|
||||
success bool,
|
||||
resultCode string,
|
||||
resultMessage string,
|
||||
securityFlags SecurityFlags,
|
||||
riskScore int,
|
||||
) *AuditEvent {
|
||||
event := NewAuditEvent(
|
||||
eventName,
|
||||
eventCategory,
|
||||
eventSubCategory,
|
||||
metricName,
|
||||
requestID,
|
||||
traceID,
|
||||
operatorID,
|
||||
operatorType,
|
||||
operatorRole,
|
||||
tenantID,
|
||||
tenantType,
|
||||
objectType,
|
||||
objectID,
|
||||
action,
|
||||
credentialType,
|
||||
sourceType,
|
||||
sourceIP,
|
||||
success,
|
||||
resultCode,
|
||||
resultMessage,
|
||||
)
|
||||
event.SecurityFlags = securityFlags
|
||||
event.RiskScore = riskScore
|
||||
return event
|
||||
}
|
||||
|
||||
// SetIdempotencyKey 设置幂等键
|
||||
func (e *AuditEvent) SetIdempotencyKey(key string) {
|
||||
e.IdempotencyKey = key
|
||||
}
|
||||
|
||||
// SetTarget 设置目标信息(用于M-015直连检测)
|
||||
func (e *AuditEvent) SetTarget(targetType, targetEndpoint string, targetDirect bool) {
|
||||
e.TargetType = targetType
|
||||
e.TargetEndpoint = targetEndpoint
|
||||
e.TargetDirect = targetDirect
|
||||
}
|
||||
|
||||
// SetInvariantRule 设置不变量规则(用于SECURITY事件)
|
||||
func (e *AuditEvent) SetInvariantRule(rule string) {
|
||||
e.InvariantRule = rule
|
||||
// 添加合规标签
|
||||
e.ComplianceTags = append(e.ComplianceTags, "XR-001")
|
||||
}
|
||||
|
||||
// GetMetricName 获取指标名称
|
||||
func (e *AuditEvent) GetMetricName() string {
|
||||
if e.Extensions != nil {
|
||||
if metricName, ok := e.Extensions["metric_name"].(string); ok {
|
||||
return metricName
|
||||
}
|
||||
}
|
||||
|
||||
// 根据事件名称推断指标
|
||||
switch e.EventName {
|
||||
case "CRED-EXPOSE-RESPONSE", "CRED-EXPOSE-LOG", "CRED-EXPOSE":
|
||||
return "supplier_credential_exposure_events"
|
||||
case "CRED-INGRESS-PLATFORM", "CRED-INGRESS":
|
||||
return "platform_credential_ingress_coverage_pct"
|
||||
case "CRED-DIRECT-SUPPLIER", "CRED-DIRECT":
|
||||
return "direct_supplier_call_by_consumer_events"
|
||||
case "AUTH-QUERY-KEY", "AUTH-QUERY-REJECT", "AUTH-QUERY":
|
||||
return "query_key_external_reject_rate_pct"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// IsM013Event 判断是否为M-013凭证暴露事件
|
||||
func IsM013Event(eventName string) bool {
|
||||
return strings.HasPrefix(eventName, "CRED-EXPOSE")
|
||||
}
|
||||
|
||||
// IsM014Event 判断是否为M-014凭证入站事件
|
||||
func IsM014Event(eventName string) bool {
|
||||
return strings.HasPrefix(eventName, "CRED-INGRESS")
|
||||
}
|
||||
|
||||
// IsM015Event 判断是否为M-015直连绕过事件
|
||||
func IsM015Event(eventName string) bool {
|
||||
return strings.HasPrefix(eventName, "CRED-DIRECT")
|
||||
}
|
||||
|
||||
// IsM016Event 判断是否为M-016 query key拒绝事件
|
||||
func IsM016Event(eventName string) bool {
|
||||
return strings.HasPrefix(eventName, "AUTH-QUERY")
|
||||
}
|
||||
Reference in New Issue
Block a user