Assessor_2.0/src/domain/gpo-analysis-persistence.ts

99 lines
4.5 KiB
TypeScript

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<string>();
const observations = new Set<string>();
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)];
}