Files
lijiaoqiao/supply-api/internal/audit/model/audit_metrics.go
Your Name 89104bd0db 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规范
2026-04-02 23:35:53 +08:00

220 lines
7.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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"
)