import type { GpoBackupInstance } from './gpo-ingestion'; import { gpoBackupInstanceValidationErrors } from './gpo-ingestion'; import type { GpoPolicyIdentityResolution } from './gpo-policy-identity'; import { gpoTechnicalPolicyIdentityValidationErrors } from './gpo-policy-identity'; export interface StoredGpoBackupInstance { version: 1; id: string; projectId: string; artifactId: string; processingRunId: string; instance: GpoBackupInstance; createdAt: string; } export interface GpoPolicyIdentityAnalysisRun { version: 1; id: string; projectId: string; artifactId: string; sourceProcessingRunId: string; supersedesAnalysisRunId?: string; analyzer: { id: 'gpo-policy-identity-analysis'; version: string }; identityResolver: { id: string; version: string }; status: 'complete' | 'partial'; observationCount: number; resolvedCount: number; diagnosticCodes: string[]; startedAt: string; completedAt: string; } export interface StoredGpoPolicyIdentityResolution { version: 1; id: string; projectId: string; analysisRunId: string; sourceProcessingRunId: string; backupInstanceId: string; observationId: string; resolution: GpoPolicyIdentityResolution; } export interface StoredGpoPolicyAnalysis { run: GpoPolicyIdentityAnalysisRun; resolutions: StoredGpoPolicyIdentityResolution[]; } export function storedGpoBackupInstanceValidationErrors(record: StoredGpoBackupInstance): string[] { const errors = gpoBackupInstanceValidationErrors(record.instance); if (record.version !== 1) errors.push('Unbekannte persistierte GPO-Backupversion.'); if (!record.id.trim() || !record.projectId.trim() || !record.artifactId.trim() || !record.processingRunId.trim()) { errors.push('Persistierte GPO-Backup-, Projekt-, Artefakt- und Processing-Run-ID sind erforderlich.'); } if (record.instance.projectId !== record.projectId || record.instance.sourceArtifactId !== record.artifactId) { errors.push('GPO-Backupinstanz gehört nicht zum angegebenen Projekt oder Artefakt.'); } if (!Number.isFinite(Date.parse(record.createdAt))) errors.push('Der Persistenzzeitpunkt der GPO-Backupinstanz ist ungültig.'); return errors; } export function storedGpoPolicyAnalysisValidationErrors(analysis: StoredGpoPolicyAnalysis): string[] { const errors: string[] = []; const { run, resolutions } = analysis; if (run.version !== 1 || !run.id.trim() || !run.projectId.trim() || !run.artifactId.trim() || !run.sourceProcessingRunId.trim()) { errors.push('Der Policy-Identitätslauf benötigt gültige IDs.'); } if (run.supersedesAnalysisRunId === run.id) errors.push('Ein Policy-Identitätslauf darf sich nicht selbst ersetzen.'); if (run.analyzer.id !== 'gpo-policy-identity-analysis' || !run.analyzer.version.trim() || !run.identityResolver.id.trim() || !run.identityResolver.version.trim()) { errors.push('Der Policy-Identitätslauf benötigt versionierte Analyse- und Resolverprovenienz.'); } if (![run.observationCount, run.resolvedCount].every(value => Number.isSafeInteger(value) && value >= 0) || run.resolvedCount > run.observationCount || run.observationCount !== resolutions.length) { errors.push('Die Zählwerte des Policy-Identitätslaufs sind inkonsistent.'); } if (![run.startedAt, run.completedAt].every(value => Number.isFinite(Date.parse(value))) || Date.parse(run.completedAt) < Date.parse(run.startedAt)) { errors.push('Die Zeitspanne des Policy-Identitätslaufs ist ungültig.'); } const ids = new Set(); const observations = new Set(); for (const record of resolutions) { if (record.version !== 1 || !record.id.trim() || record.projectId !== run.projectId || record.analysisRunId !== run.id || record.sourceProcessingRunId !== run.sourceProcessingRunId || !record.backupInstanceId.trim() || !record.observationId.trim() || ids.has(record.id) || observations.has(record.observationId)) { errors.push('Eine persistierte Policy-Identitätsauflösung ist ungültig oder doppelt.'); } ids.add(record.id); observations.add(record.observationId); if (record.resolution.status === 'resolved') errors.push(...gpoTechnicalPolicyIdentityValidationErrors(record.resolution.identity)); else if (!record.resolution.reasonCode.trim()) errors.push('Eine unaufgelöste Policy-Identität benötigt einen Grundcode.'); } if (run.resolvedCount !== resolutions.filter(record => record.resolution.status === 'resolved').length) { errors.push('Die Zahl aufgelöster Policy-Identitäten ist inkonsistent.'); } return [...new Set(errors)]; }