package recoveryconformance import ( "bytes" "crypto/sha256" "encoding/hex" "encoding/json" "errors" "fmt" "io" "regexp" "slices" "strings" "time" ) const ( CaptureSchema = "production-recovery-capture-v1" ReportSchema = "production-recovery-conformance-report-v1" ) var digestPattern = regexp.MustCompile(`^sha256:[0-9a-f]{64}$`) var RequiredDrillTypes = []string{"POSTGRES_RESTORE", "REDIS_REBUILD", "SERVICE_ROLLING_RESTART", "PROVIDER_OUTAGE_RECOVERY"} type Capture struct { SchemaVersion string `json:"schema_version"` EvidenceSource string `json:"evidence_source"` CandidateVersion string `json:"candidate_version"` BuildDigest string `json:"build_digest"` Environment string `json:"environment"` InfrastructureRef string `json:"infrastructure_ref"` FailureDomainRef string `json:"failure_domain_ref"` ChangeTicketRef string `json:"change_ticket_ref"` AttestedByRef string `json:"attested_by_ref"` AttestedAt time.Time `json:"attested_at"` CollectedAt time.Time `json:"collected_at"` Drills []DrillEvidence `json:"drills"` } type DrillEvidence struct { DrillType string `json:"drill_type"` ScenarioRef string `json:"scenario_ref"` StartedAt time.Time `json:"started_at"` CompletedAt time.Time `json:"completed_at"` ObservedRecoverySeconds int `json:"observed_recovery_seconds"` RecoveryVerified bool `json:"recovery_verified"` DataIntegrityVerified bool `json:"data_integrity_verified"` BusinessContinuityVerified bool `json:"business_continuity_verified"` NoDuplicateEffects bool `json:"no_duplicate_effects"` CleanupVerified bool `json:"cleanup_verified"` BeforeStateDigest string `json:"before_state_digest"` AfterStateDigest string `json:"after_state_digest"` ExecutionRef string `json:"execution_ref"` ValidationRef string `json:"validation_ref"` AuditRef string `json:"audit_ref"` } type Check struct { Code string `json:"code"` Status string `json:"status"` Detail string `json:"detail"` } type Report struct { SchemaVersion string `json:"schema_version"` Result string `json:"result"` GeneratedAt time.Time `json:"generated_at"` CandidateVersion string `json:"candidate_version"` BuildDigest string `json:"build_digest"` EvidenceScope string `json:"evidence_scope"` ExternalValidationRequired bool `json:"external_validation_required"` Environment string `json:"environment"` InfrastructureRef string `json:"infrastructure_ref"` DrillCount int `json:"drill_count"` CompletedDrillTypes []string `json:"completed_drill_types"` ObservedRecoverySeconds map[string]int `json:"observed_recovery_seconds"` InputSHA256 map[string]string `json:"input_sha256"` Checks []Check `json:"checks"` Disclaimer string `json:"disclaimer"` } func ParseCapture(content []byte) (Capture, error) { var capture Capture if err := decodeStrict(content, &capture); err != nil { return Capture{}, fmt.Errorf("decode production recovery capture: %w", err) } return capture, nil } func ParseReport(content []byte) (Report, error) { var report Report if err := decodeStrict(content, &report); err != nil { return Report{}, fmt.Errorf("decode production recovery report: %w", err) } return report, nil } func Evaluate(capture Capture, candidateVersion, buildDigest string, generatedAt time.Time) Report { candidateVersion = strings.TrimSpace(candidateVersion) buildDigest = strings.ToLower(strings.TrimSpace(buildDigest)) report := Report{ SchemaVersion: ReportSchema, Result: "PASS", GeneratedAt: generatedAt.UTC(), CandidateVersion: candidateVersion, BuildDigest: buildDigest, EvidenceScope: "LOCAL_RECOVERY", ExternalValidationRequired: true, Environment: capture.Environment, InfrastructureRef: capture.InfrastructureRef, DrillCount: len(capture.Drills), CompletedDrillTypes: []string{}, ObservedRecoverySeconds: map[string]int{}, InputSHA256: map[string]string{}, Checks: []Check{}, Disclaimer: "恢复一致性报告只证明所提供候选、故障注入、恢复结果、数据完整性、连续性和审计引用相互一致;本地演练不替代生产等价基础设施和发布审批。", } if capture.EvidenceSource == "PRODUCTION_EQUIVALENT" { report.EvidenceScope = "PRODUCTION_EQUIVALENT" } add := func(code string, ok bool, detail string) { status := "PASS" if !ok { status, report.Result = "FAIL", "FAIL" } report.Checks = append(report.Checks, Check{Code: code, Status: status, Detail: detail}) } add("CAPTURE_SCHEMA", capture.SchemaVersion == CaptureSchema, "恢复证据必须使用"+CaptureSchema) add("EVIDENCE_SOURCE", capture.EvidenceSource == "LOCAL" || capture.EvidenceSource == "PRODUCTION_EQUIVALENT", "证据来源必须明确为LOCAL或PRODUCTION_EQUIVALENT") add("CANDIDATE_IDENTITY", candidateVersion != "" && digestPattern.MatchString(buildDigest), "候选版本和sha256构建摘要必须完整") add("CAPTURE_CANDIDATE_BINDING", capture.CandidateVersion == candidateVersion && strings.ToLower(capture.BuildDigest) == buildDigest, "恢复采集必须绑定同一候选版本和构建摘要") real := capture.EvidenceSource == "PRODUCTION_EQUIVALENT" environmentOK := capture.InfrastructureRef != "" && capture.AttestedByRef != "" && !capture.AttestedAt.IsZero() && !capture.CollectedAt.IsZero() && !capture.AttestedAt.After(capture.CollectedAt) if real { environmentOK = environmentOK && (capture.Environment == "STAGING" || capture.Environment == "PRODUCTION") && capture.FailureDomainRef != "" && capture.ChangeTicketRef != "" } else { environmentOK = environmentOK && capture.Environment == "LOCAL" } add("ENVIRONMENT_IDENTITY", environmentOK, "生产等价证据必须绑定环境、故障域、变更工单和复核人") drillsOK, timeOK, recoveryOK, integrityOK, continuityOK, refsOK := len(capture.Drills) > 0, true, true, true, true, true seen := map[string]bool{} for _, drill := range capture.Drills { if !slices.Contains(RequiredDrillTypes, drill.DrillType) || seen[drill.DrillType] || drill.ScenarioRef == "" { drillsOK = false } seen[drill.DrillType] = true timeOK = timeOK && !drill.StartedAt.IsZero() && !drill.CompletedAt.IsZero() && !drill.CompletedAt.Before(drill.StartedAt) && !drill.CompletedAt.After(capture.CollectedAt) && drill.ObservedRecoverySeconds >= 0 recoveryOK = recoveryOK && drill.RecoveryVerified && drill.CleanupVerified integrityOK = integrityOK && drill.DataIntegrityVerified && drill.BeforeStateDigest != "" && drill.BeforeStateDigest == drill.AfterStateDigest continuityOK = continuityOK && drill.BusinessContinuityVerified && drill.NoDuplicateEffects refsOK = refsOK && drill.ExecutionRef != "" && drill.ValidationRef != "" && drill.AuditRef != "" report.ObservedRecoverySeconds[drill.DrillType] = drill.ObservedRecoverySeconds } for drillType := range seen { report.CompletedDrillTypes = append(report.CompletedDrillTypes, drillType) } slices.Sort(report.CompletedDrillTypes) if real { for _, drillType := range RequiredDrillTypes { drillsOK = drillsOK && seen[drillType] } } add("DRILL_COVERAGE", drillsOK, "生产等价恢复必须覆盖PostgreSQL、Redis、三个服务滚动重启和供应商停机恢复") add("TIMELINE_INTEGRITY", timeOK, "演练时间线和观测恢复用时必须有效") add("RECOVERY_OUTCOME", recoveryOK, "每项故障注入必须恢复成功并完成夹具清理") add("DATA_INTEGRITY", integrityOK, "恢复前后权威状态摘要必须一致") add("BUSINESS_CONTINUITY", continuityOK, "降级/恢复期间业务连续性必须通过且不得产生重复效果") add("AUDIT_REFERENCES", refsOK, "每项演练必须保存执行、验证和审计引用") if real && environmentOK && drillsOK && timeOK && recoveryOK && integrityOK && continuityOK && refsOK && report.Result == "PASS" { report.ExternalValidationRequired = false } return report } func SHA256(content []byte) string { digest := sha256.Sum256(content) return hex.EncodeToString(digest[:]) } func decodeStrict(content []byte, target any) error { decoder := json.NewDecoder(bytes.NewReader(content)) decoder.DisallowUnknownFields() if err := decoder.Decode(target); err != nil { return err } var trailing any if err := decoder.Decode(&trailing); !errors.Is(err, io.EOF) { return errors.New("trailing JSON data") } return nil }