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:
220
supply-api/internal/audit/model/audit_metrics.go
Normal file
220
supply-api/internal/audit/model/audit_metrics.go
Normal file
@@ -0,0 +1,220 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// ==================== M-013: 凭证暴露事件详情 ====================
|
||||
|
||||
// CredentialExposureDetail M-013: 凭证暴露事件专用
|
||||
type CredentialExposureDetail struct {
|
||||
EventID string `json:"event_id"` // 事件ID(关联audit_events)
|
||||
ExposureType string `json:"exposure_type"` // exposed_in_response/exposed_in_log/exposed_in_export
|
||||
ExposureLocation string `json:"exposure_location"` // response_body/response_header/log_file/export_file
|
||||
ExposurePattern string `json:"exposure_pattern"` // 匹配到的正则模式
|
||||
ExposedFragment string `json:"exposed_fragment"` // 暴露的片段(已脱敏)
|
||||
ScanRuleID string `json:"scan_rule_id"` // 触发扫描规则ID
|
||||
Resolved bool `json:"resolved"` // 是否已解决
|
||||
ResolvedAt *time.Time `json:"resolved_at"` // 解决时间
|
||||
ResolvedBy *int64 `json:"resolved_by"` // 解决人
|
||||
ResolutionNotes string `json:"resolution_notes"` // 解决备注
|
||||
}
|
||||
|
||||
// NewCredentialExposureDetail 创建凭证暴露详情
|
||||
func NewCredentialExposureDetail(
|
||||
exposureType string,
|
||||
exposureLocation string,
|
||||
exposurePattern string,
|
||||
exposedFragment string,
|
||||
scanRuleID string,
|
||||
) *CredentialExposureDetail {
|
||||
return &CredentialExposureDetail{
|
||||
ExposureType: exposureType,
|
||||
ExposureLocation: exposureLocation,
|
||||
ExposurePattern: exposurePattern,
|
||||
ExposedFragment: exposedFragment,
|
||||
ScanRuleID: scanRuleID,
|
||||
Resolved: false,
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve 标记为已解决
|
||||
func (d *CredentialExposureDetail) Resolve(resolvedBy int64, notes string) {
|
||||
now := time.Now()
|
||||
d.Resolved = true
|
||||
d.ResolvedAt = &now
|
||||
d.ResolvedBy = &resolvedBy
|
||||
d.ResolutionNotes = notes
|
||||
}
|
||||
|
||||
// ==================== M-014: 凭证入站事件详情 ====================
|
||||
|
||||
// CredentialIngressDetail M-014: 凭证入站类型专用
|
||||
type CredentialIngressDetail struct {
|
||||
EventID string `json:"event_id"` // 事件ID
|
||||
RequestCredentialType string `json:"request_credential_type"` // 请求中的凭证类型
|
||||
ExpectedCredentialType string `json:"expected_credential_type"` // 期望的凭证类型
|
||||
CoverageCompliant bool `json:"coverage_compliant"` // 是否合规
|
||||
PlatformTokenPresent bool `json:"platform_token_present"` // 平台Token是否存在
|
||||
UpstreamKeyPresent bool `json:"upstream_key_present"` // 上游Key是否存在
|
||||
Reviewed bool `json:"reviewed"` // 是否已审核
|
||||
ReviewedAt *time.Time `json:"reviewed_at"` // 审核时间
|
||||
ReviewedBy *int64 `json:"reviewed_by"` // 审核人
|
||||
}
|
||||
|
||||
// NewCredentialIngressDetail 创建凭证入站详情
|
||||
func NewCredentialIngressDetail(
|
||||
requestCredentialType string,
|
||||
expectedCredentialType string,
|
||||
coverageCompliant bool,
|
||||
platformTokenPresent bool,
|
||||
upstreamKeyPresent bool,
|
||||
) *CredentialIngressDetail {
|
||||
return &CredentialIngressDetail{
|
||||
RequestCredentialType: requestCredentialType,
|
||||
ExpectedCredentialType: expectedCredentialType,
|
||||
CoverageCompliant: coverageCompliant,
|
||||
PlatformTokenPresent: platformTokenPresent,
|
||||
UpstreamKeyPresent: upstreamKeyPresent,
|
||||
Reviewed: false,
|
||||
}
|
||||
}
|
||||
|
||||
// Review 标记为已审核
|
||||
func (d *CredentialIngressDetail) Review(reviewedBy int64) {
|
||||
now := time.Now()
|
||||
d.Reviewed = true
|
||||
d.ReviewedAt = &now
|
||||
d.ReviewedBy = &reviewedBy
|
||||
}
|
||||
|
||||
// ==================== M-015: 直连绕过事件详情 ====================
|
||||
|
||||
// DirectCallDetail M-015: 直连绕过专用
|
||||
type DirectCallDetail struct {
|
||||
EventID string `json:"event_id"` // 事件ID
|
||||
ConsumerID int64 `json:"consumer_id"` // 消费者ID
|
||||
SupplierID int64 `json:"supplier_id"` // 供应商ID
|
||||
DirectEndpoint string `json:"direct_endpoint"` // 直连端点
|
||||
ViaPlatform bool `json:"via_platform"` // 是否通过平台
|
||||
BypassType string `json:"bypass_type"` // ip_bypass/proxy_bypass/config_bypass/dns_bypass
|
||||
DetectionMethod string `json:"detection_method"` // 检测方法
|
||||
Blocked bool `json:"blocked"` // 是否被阻断
|
||||
BlockedAt *time.Time `json:"blocked_at"` // 阻断时间
|
||||
BlockReason string `json:"block_reason"` // 阻断原因
|
||||
}
|
||||
|
||||
// NewDirectCallDetail 创建直连详情
|
||||
func NewDirectCallDetail(
|
||||
consumerID int64,
|
||||
supplierID int64,
|
||||
directEndpoint string,
|
||||
viaPlatform bool,
|
||||
bypassType string,
|
||||
detectionMethod string,
|
||||
) *DirectCallDetail {
|
||||
return &DirectCallDetail{
|
||||
ConsumerID: consumerID,
|
||||
SupplierID: supplierID,
|
||||
DirectEndpoint: directEndpoint,
|
||||
ViaPlatform: viaPlatform,
|
||||
BypassType: bypassType,
|
||||
DetectionMethod: detectionMethod,
|
||||
Blocked: false,
|
||||
}
|
||||
}
|
||||
|
||||
// Block 标记为已阻断
|
||||
func (d *DirectCallDetail) Block(reason string) {
|
||||
now := time.Now()
|
||||
d.Blocked = true
|
||||
d.BlockedAt = &now
|
||||
d.BlockReason = reason
|
||||
}
|
||||
|
||||
// ==================== M-016: Query Key 拒绝事件详情 ====================
|
||||
|
||||
// QueryKeyRejectDetail M-016: query key 拒绝专用
|
||||
type QueryKeyRejectDetail struct {
|
||||
EventID string `json:"event_id"` // 事件ID
|
||||
QueryKeyID string `json:"query_key_id"` // Query Key ID
|
||||
RequestedEndpoint string `json:"requested_endpoint"` // 请求端点
|
||||
RejectReason string `json:"reject_reason"` // not_allowed/expired/malformed/revoked/rate_limited
|
||||
RejectCode string `json:"reject_code"` // 拒绝码
|
||||
FirstOccurrence bool `json:"first_occurrence"` // 是否首次发生
|
||||
OccurrenceCount int `json:"occurrence_count"` // 发生次数
|
||||
}
|
||||
|
||||
// NewQueryKeyRejectDetail 创建Query Key拒绝详情
|
||||
func NewQueryKeyRejectDetail(
|
||||
queryKeyID string,
|
||||
requestedEndpoint string,
|
||||
rejectReason string,
|
||||
rejectCode string,
|
||||
) *QueryKeyRejectDetail {
|
||||
return &QueryKeyRejectDetail{
|
||||
QueryKeyID: queryKeyID,
|
||||
RequestedEndpoint: requestedEndpoint,
|
||||
RejectReason: rejectReason,
|
||||
RejectCode: rejectCode,
|
||||
FirstOccurrence: true,
|
||||
OccurrenceCount: 1,
|
||||
}
|
||||
}
|
||||
|
||||
// RecordOccurrence 记录再次发生
|
||||
func (d *QueryKeyRejectDetail) RecordOccurrence(firstOccurrence bool) {
|
||||
d.FirstOccurrence = firstOccurrence
|
||||
d.OccurrenceCount++
|
||||
}
|
||||
|
||||
// ==================== 指标常量 ====================
|
||||
|
||||
// M-013 暴露类型常量
|
||||
const (
|
||||
ExposureTypeResponse = "exposed_in_response"
|
||||
ExposureTypeLog = "exposed_in_log"
|
||||
ExposureTypeExport = "exposed_in_export"
|
||||
)
|
||||
|
||||
// M-013 暴露位置常量
|
||||
const (
|
||||
ExposureLocationResponseBody = "response_body"
|
||||
ExposureLocationResponseHeader = "response_header"
|
||||
ExposureLocationLogFile = "log_file"
|
||||
ExposureLocationExportFile = "export_file"
|
||||
)
|
||||
|
||||
// M-015 绕过类型常量
|
||||
const (
|
||||
BypassTypeIPBypass = "ip_bypass"
|
||||
BypassTypeProxyBypass = "proxy_bypass"
|
||||
BypassTypeConfigBypass = "config_bypass"
|
||||
BypassTypeDNSBypass = "dns_bypass"
|
||||
)
|
||||
|
||||
// M-015 检测方法常量
|
||||
const (
|
||||
DetectionMethodUpstreamAPIPattern = "upstream_api_pattern_match"
|
||||
DetectionMethodDNSResolution = "dns_resolution_check"
|
||||
DetectionMethodConnectionSource = "connection_source_check"
|
||||
DetectionMethodIPWhitelist = "ip_whitelist_check"
|
||||
)
|
||||
|
||||
// M-016 拒绝原因常量
|
||||
const (
|
||||
RejectReasonNotAllowed = "not_allowed"
|
||||
RejectReasonExpired = "expired"
|
||||
RejectReasonMalformed = "malformed"
|
||||
RejectReasonRevoked = "revoked"
|
||||
RejectReasonRateLimited = "rate_limited"
|
||||
)
|
||||
|
||||
// M-016 拒绝码常量
|
||||
const (
|
||||
RejectCodeNotAllowed = "QUERY_KEY_NOT_ALLOWED"
|
||||
RejectCodeExpired = "QUERY_KEY_EXPIRED"
|
||||
RejectCodeMalformed = "QUERY_KEY_MALFORMED"
|
||||
RejectCodeRevoked = "QUERY_KEY_REVOKED"
|
||||
RejectCodeRateLimited = "QUERY_KEY_RATE_LIMITED"
|
||||
)
|
||||
Reference in New Issue
Block a user