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