## 设计文档 - 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规范
357 lines
10 KiB
Go
357 lines
10 KiB
Go
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")
|
||
} |