feat: require production infrastructure evidence

This commit is contained in:
Codex Local
2026-08-26 22:56:19 +08:00
parent 3786db0de8
commit feb99de192
19 changed files with 237 additions and 61 deletions
+84 -25
View File
@@ -82,6 +82,15 @@ type AcceptancePlatformHealthState struct {
GateSatisfied bool `json:"gate_satisfied"`
}
type AcceptanceProductionInfrastructureState struct {
Applicable bool `json:"applicable"`
DeploymentProfile string `json:"deployment_profile"`
OffsiteBackupReady bool `json:"offsite_backup_ready"`
ExternalAlertReceiverReady bool `json:"external_alert_receiver_ready"`
MockServicesDisabled bool `json:"mock_services_disabled"`
GateSatisfied bool `json:"gate_satisfied"`
}
type AcceptanceBlockingAlert struct {
ID string `json:"id"`
RuleCode string `json:"rule_code"`
@@ -101,25 +110,26 @@ type AcceptanceGate struct {
}
type AcceptanceSnapshot struct {
ID string `json:"id"`
GeneratedAt time.Time `json:"generated_at"`
TenantID string `json:"tenant_id"`
CandidateVersion string `json:"candidate_version"`
BuildDigest string `json:"build_digest"`
Environment string `json:"environment"`
RunType string `json:"run_type"`
Scope string `json:"scope"`
RedactionPolicy string `json:"redaction_policy"`
RuntimeBuild buildinfo.Info `json:"runtime_build"`
Database AcceptanceDatabaseState `json:"database"`
IntegrationIssues IntegrationIssueSummary `json:"integration_issues"`
ExternalDependencies []AcceptanceDependencyState `json:"external_dependencies"`
Outbox AcceptanceOutboxState `json:"outbox"`
Alerts AcceptanceAlertState `json:"alerts"`
PlatformHealth AcceptancePlatformHealthState `json:"platform_health"`
Gates []AcceptanceGate `json:"gates"`
OverallGateSatisfied bool `json:"overall_gate_satisfied"`
Disclaimer string `json:"disclaimer"`
ID string `json:"id"`
GeneratedAt time.Time `json:"generated_at"`
TenantID string `json:"tenant_id"`
CandidateVersion string `json:"candidate_version"`
BuildDigest string `json:"build_digest"`
Environment string `json:"environment"`
RunType string `json:"run_type"`
Scope string `json:"scope"`
RedactionPolicy string `json:"redaction_policy"`
RuntimeBuild buildinfo.Info `json:"runtime_build"`
Database AcceptanceDatabaseState `json:"database"`
IntegrationIssues IntegrationIssueSummary `json:"integration_issues"`
ExternalDependencies []AcceptanceDependencyState `json:"external_dependencies"`
Outbox AcceptanceOutboxState `json:"outbox"`
Alerts AcceptanceAlertState `json:"alerts"`
PlatformHealth AcceptancePlatformHealthState `json:"platform_health"`
ProductionInfrastructure AcceptanceProductionInfrastructureState `json:"production_infrastructure"`
Gates []AcceptanceGate `json:"gates"`
OverallGateSatisfied bool `json:"overall_gate_satisfied"`
Disclaimer string `json:"disclaimer"`
}
func (s *Service) ExportAcceptanceSnapshot(ctx context.Context, principal identity.Principal, tenantPublicID, key, requestID string, input AcceptanceSnapshotInput) (AcceptanceSnapshot, bool, error) {
@@ -289,11 +299,12 @@ func buildAcceptanceSnapshot(ctx context.Context, tx pgx.Tx, tenantPublicID, ten
); err != nil {
return AcceptanceSnapshot{}, err
}
platformHealth, err := loadAcceptancePlatformHealth(ctx, tx, now)
platformHealth, productionInfrastructure, err := loadAcceptancePlatformHealth(ctx, tx, now, input.Environment)
if err != nil {
return AcceptanceSnapshot{}, err
}
snapshot.PlatformHealth = platformHealth
snapshot.ProductionInfrastructure = productionInfrastructure
runtimeSatisfied := input.Environment == "LAB" || (snapshot.RuntimeBuild.Version == input.CandidateVersion && snapshot.RuntimeBuild.Commit != "unknown" && snapshot.RuntimeBuild.BuildTime != "unknown")
dependenciesSatisfied := true
@@ -310,6 +321,7 @@ func buildAcceptanceSnapshot(ctx context.Context, tx pgx.Tx, tenantPublicID, ten
{Code: "outbox_clear", Satisfied: outboxSatisfied, Summary: "租户及平台级待处理、处理中和死信任务必须清零"},
{Code: "critical_alerts_clear", Satisfied: alertsSatisfied, Summary: "不得存在未解决的高或严重级告警"},
{Code: "platform_health_current", Satisfied: snapshot.PlatformHealth.GateSatisfied, Summary: acceptancePlatformHealthSummary(snapshot.PlatformHealth)},
{Code: "production_infrastructure_ready", Satisfied: snapshot.ProductionInfrastructure.GateSatisfied, Summary: acceptanceProductionInfrastructureSummary(snapshot.ProductionInfrastructure)},
}
snapshot.OverallGateSatisfied = true
for _, gate := range snapshot.Gates {
@@ -318,7 +330,7 @@ func buildAcceptanceSnapshot(ctx context.Context, tx pgx.Tx, tenantPublicID, ten
return snapshot, nil
}
func loadAcceptancePlatformHealth(ctx context.Context, tx pgx.Tx, now time.Time) (AcceptancePlatformHealthState, error) {
func loadAcceptancePlatformHealth(ctx context.Context, tx pgx.Tx, now time.Time, environment string) (AcceptancePlatformHealthState, AcceptanceProductionInfrastructureState, error) {
state := AcceptancePlatformHealthState{State: "MISSING"}
var observedAt, receivedAt time.Time
var checksJSON []byte
@@ -328,16 +340,16 @@ func loadAcceptancePlatformHealth(ctx context.Context, tx pgx.Tx, now time.Time)
&state.Status, &observedAt, &receivedAt, &checksJSON,
)
if errors.Is(err, pgx.ErrNoRows) {
return state, nil
return state, evaluateAcceptanceProductionInfrastructure(environment, nil), nil
}
if err != nil {
return AcceptancePlatformHealthState{}, err
return AcceptancePlatformHealthState{}, AcceptanceProductionInfrastructureState{}, err
}
var checks []PlatformHealthCheck
if err = json.Unmarshal(checksJSON, &checks); err != nil {
return AcceptancePlatformHealthState{}, err
return AcceptancePlatformHealthState{}, AcceptanceProductionInfrastructureState{}, err
}
return evaluateAcceptancePlatformHealth(state.Status, observedAt, receivedAt, checks, now), nil
return evaluateAcceptancePlatformHealth(state.Status, observedAt, receivedAt, checks, now), evaluateAcceptanceProductionInfrastructure(environment, checks), nil
}
func evaluateAcceptancePlatformHealth(status string, observedAt, receivedAt time.Time, checks []PlatformHealthCheck, now time.Time) AcceptancePlatformHealthState {
@@ -372,6 +384,53 @@ func acceptancePlatformHealthSummary(state AcceptancePlatformHealthState) string
return fmt.Sprintf("云端主机健康快照当前有效,共%d项检查", state.CheckCount)
}
func evaluateAcceptanceProductionInfrastructure(environment string, checks []PlatformHealthCheck) AcceptanceProductionInfrastructureState {
state := AcceptanceProductionInfrastructureState{Applicable: environment == "PRODUCTION", DeploymentProfile: "MISSING"}
if !state.Applicable {
state.GateSatisfied = true
return state
}
profileReady := false
for _, check := range checks {
switch check.Name {
case "deployment_profile":
state.DeploymentProfile = check.Value
profileReady = check.Status == "healthy" && check.Value == "production"
case "offsite_backup":
state.OffsiteBackupReady = check.Status == "healthy" && strings.HasPrefix(check.Value, "age_seconds=")
case "external_alert_receiver":
state.ExternalAlertReceiverReady = check.Status == "healthy" && check.Value == "configured"
case "mock_services":
state.MockServicesDisabled = check.Status == "healthy" && check.Value == "disabled"
}
}
state.GateSatisfied = profileReady && state.OffsiteBackupReady && state.ExternalAlertReceiverReady && state.MockServicesDisabled
return state
}
func acceptanceProductionInfrastructureSummary(state AcceptanceProductionInfrastructureState) string {
if !state.Applicable {
return "非生产候选不适用生产基础设施强制门禁"
}
missing := make([]string, 0, 4)
if state.DeploymentProfile != "production" {
missing = append(missing, "生产部署模式")
}
if !state.OffsiteBackupReady {
missing = append(missing, "已验证异地备份")
}
if !state.ExternalAlertReceiverReady {
missing = append(missing, "真实外部告警接收器")
}
if !state.MockServicesDisabled {
missing = append(missing, "关闭模拟服务")
}
if len(missing) > 0 {
return "生产基础设施尚缺:" + strings.Join(missing, "、")
}
return "生产部署模式、异地备份、外部告警和模拟服务退出均已确认"
}
func acceptanceRuntimeSummary(environment string) string {
if environment == "LAB" {
return "实验室环境允许开发构建,但候选版本与镜像摘要必须明确"