固化七月迭代审计治理进展以隔离线上热修
Constraint: 切换 main 前必须保存当前七月分支全部项目进展,套餐生效提案仅属于 Iteration/7-11。 Rejected: 将七月套餐修复直接移植到 main | 两个分支的可靠投递架构不同。 Confidence: medium Scope-risk: broad Directive: 不得将本提交整体 cherry-pick 到 main;main 套餐热修必须基于其纯 Asynq 代码独立实施。 Tested: git diff --check;openspec validate fix-package-activation-starvation --strict。 Not-tested: 按用户要求未运行自动化测试;go build ./... 因当前审计改造中的 Enterprise 模型字面量和 role.recordFailure 参数类型错误未通过。
This commit is contained in:
@@ -38,14 +38,44 @@ type AccessTokenProvider interface {
|
||||
Invalidate(ctx context.Context, applicationID uint)
|
||||
}
|
||||
|
||||
// SensitiveReadAuditWriter 定义明文连接凭据读取的失败关闭审计边界。
|
||||
type SensitiveReadAuditWriter interface {
|
||||
WriteSensitiveRead(ctx context.Context, tx *gorm.DB, audit SensitiveReadAudit) error
|
||||
}
|
||||
|
||||
// SensitiveReadAudit 是一次企业微信应用明文凭据读取事实。
|
||||
type SensitiveReadAudit struct {
|
||||
OperatorID uint
|
||||
Applications []SensitiveReadResource
|
||||
FieldClasses []string
|
||||
RequestID string
|
||||
CorrelationID string
|
||||
}
|
||||
|
||||
// SensitiveReadResource 是不含任何明文凭据的读取目标快照。
|
||||
type SensitiveReadResource struct {
|
||||
ID uint
|
||||
CorpID string
|
||||
AgentID int64
|
||||
Name string
|
||||
Status int
|
||||
CredentialsConfigured bool
|
||||
}
|
||||
|
||||
// ConnectionService 保存应用配置并测试企业微信连接。
|
||||
type ConnectionService struct {
|
||||
db *gorm.DB
|
||||
repo ApplicationRepository
|
||||
tokens AccessTokenProvider
|
||||
audit systemconfigapp.AuditWriter
|
||||
members DefaultCreatorMemberFinder
|
||||
now func() time.Time
|
||||
db *gorm.DB
|
||||
repo ApplicationRepository
|
||||
tokens AccessTokenProvider
|
||||
audit systemconfigapp.AuditWriter
|
||||
readAudit SensitiveReadAuditWriter
|
||||
members DefaultCreatorMemberFinder
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
// SetSensitiveReadAuditWriter 注入明文凭据读取的失败关闭审计 Writer。
|
||||
func (s *ConnectionService) SetSensitiveReadAuditWriter(writer SensitiveReadAuditWriter) {
|
||||
s.readAudit = writer
|
||||
}
|
||||
|
||||
// SetDefaultCreatorMemberFinder 注入默认审批发起人的可见成员查询边界。
|
||||
@@ -156,6 +186,33 @@ func (s *ConnectionService) List(ctx context.Context, request dto.WeComApplicati
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(applications) > 0 {
|
||||
if s.db == nil || s.readAudit == nil {
|
||||
return nil, errors.New(errors.CodeServiceUnavailable, "敏感读取审计能力未配置")
|
||||
}
|
||||
requestID := ""
|
||||
if value := middleware.GetRequestIDFromContext(ctx); value != nil {
|
||||
requestID = *value
|
||||
}
|
||||
resources := make([]SensitiveReadResource, 0, len(applications))
|
||||
for _, application := range applications {
|
||||
resources = append(resources, SensitiveReadResource{
|
||||
ID: application.ID, CorpID: application.CorpID, AgentID: application.AgentID,
|
||||
Name: application.Name, Status: application.Status,
|
||||
CredentialsConfigured: application.Secret != "" && application.CallbackToken != "" && application.EncodingAESKey != "",
|
||||
})
|
||||
}
|
||||
readAudit := SensitiveReadAudit{
|
||||
OperatorID: middleware.GetUserIDFromContext(ctx), Applications: resources,
|
||||
FieldClasses: []string{"secret", "callback_token", "encoding_aes_key"},
|
||||
RequestID: requestID, CorrelationID: requestID,
|
||||
}
|
||||
if err := s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
|
||||
return s.readAudit.WriteSensitiveRead(ctx, tx, readAudit)
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
result := make([]dto.WeComApplicationResponse, 0, len(applications))
|
||||
for _, application := range applications {
|
||||
result = append(result, toApplicationResponse(application))
|
||||
|
||||
Reference in New Issue
Block a user