import type { CanonicalAssessmentModel } from '../domain/canonical-model'; import { createReferenceRecognizer, type ReferenceCatalogSnapshot, type ReferenceRecognitionRun } from '../domain/reference-recognition'; import { canonicalJson } from '../shared/canonical-json'; import { RepositoryValidationError } from './repository-errors'; export function validateReferenceRun(run: ReferenceRecognitionRun, catalogs: ReferenceCatalogSnapshot[], model: CanonicalAssessmentModel | null): void { const hash = /^[a-f0-9]{64}$/; if (!model || model.project.id !== run.projectId || model.assessment.id !== run.assessmentId || !model.scanRuns.some(scan => scan.id === run.scanRunId) || run.schemaVersion !== 1 || !run.id || !run.recognizerVersion || !hash.test(run.inputSha256) || !Number.isFinite(Date.parse(run.createdAt)) || catalogs.length !== 2 || new Set(catalogs.map(catalog => catalog.framework)).size !== 2 || catalogs.some(catalog => !hash.test(catalog.sha256) || !catalog.entries.length || !catalog.license) || canonicalJson([...run.catalogHashes].sort()) !== canonicalJson(catalogs.map(catalog => catalog.sha256).sort())) { throw new RepositoryValidationError('Ungültiger Referenzlauf oder fremder Scan-/Katalogkontext.'); } const occurrences = model.findingOccurrences.filter(item => item.scanRunId === run.scanRunId); const results = new Map(run.results.map(result => [result.occurrenceId, result])); const recognize = createReferenceRecognizer(catalogs); if (results.size !== occurrences.length || results.size !== run.results.length) throw new RepositoryValidationError('Unvollständiger Referenzlauf.'); for (const occurrence of occurrences) { const result = results.get(occurrence.id); const file = model.importFiles.find(item => item.id === occurrence.importFileId); if (!result || result.importFileId !== occurrence.importFileId || result.sourceFileSha256 !== file?.sha256 || canonicalJson(result.sourcePosition) !== canonicalJson(occurrence.sourcePosition) || canonicalJson(result.references) !== canonicalJson(recognize(occurrence.originalFields))) { throw new RepositoryValidationError('Referenzherkunft stimmt nicht mit dem gespeicherten Original überein.'); } } }