obligations-document, tom-document, loeschfristen-document, compliance-scope-triggers, sdk-flow/flow-data, processing-activities, loeschfristen-baseline-catalog, catalog-registry, dsfa mitigation-library + risk-catalog, vvt-baseline-catalog, vendor contract-review checklists + findings, demo-data, tom-compliance. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
178 lines
4.9 KiB
TypeScript
178 lines
4.9 KiB
TypeScript
// =============================================================================
|
|
// TOM Module - Compliance Check Engine
|
|
// Prueft Technische und Organisatorische Massnahmen auf Vollstaendigkeit,
|
|
// Konsistenz und DSGVO-Konformitaet (Art. 32 DSGVO)
|
|
//
|
|
// Check functions live in tom-compliance-checks.ts (barrel split).
|
|
// =============================================================================
|
|
|
|
import type { TOMGeneratorState } from './tom-generator/types'
|
|
|
|
import {
|
|
resetIssueCounter,
|
|
checkMissingResponsible,
|
|
checkOverdueReview,
|
|
checkMissingEvidence,
|
|
checkStaleNotImplemented,
|
|
checkIncompleteCategory,
|
|
checkNoEncryption,
|
|
checkNoPseudonymization,
|
|
checkMissingAvailability,
|
|
checkNoReviewProcess,
|
|
checkUncoveredSDMGoal,
|
|
checkHighRiskWithoutMeasures,
|
|
} from './tom-compliance-checks'
|
|
|
|
// =============================================================================
|
|
// TYPES
|
|
// =============================================================================
|
|
|
|
export type TOMComplianceIssueSeverity = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'
|
|
|
|
export type TOMComplianceIssueType =
|
|
| 'MISSING_RESPONSIBLE'
|
|
| 'OVERDUE_REVIEW'
|
|
| 'MISSING_EVIDENCE'
|
|
| 'INCOMPLETE_CATEGORY'
|
|
| 'NO_ENCRYPTION_MEASURES'
|
|
| 'NO_PSEUDONYMIZATION'
|
|
| 'MISSING_AVAILABILITY'
|
|
| 'NO_REVIEW_PROCESS'
|
|
| 'UNCOVERED_SDM_GOAL'
|
|
| 'HIGH_RISK_WITHOUT_MEASURES'
|
|
| 'STALE_NOT_IMPLEMENTED'
|
|
|
|
export interface TOMComplianceIssue {
|
|
id: string
|
|
controlId: string
|
|
controlName: string
|
|
type: TOMComplianceIssueType
|
|
severity: TOMComplianceIssueSeverity
|
|
title: string
|
|
description: string
|
|
recommendation: string
|
|
}
|
|
|
|
export interface TOMComplianceCheckResult {
|
|
issues: TOMComplianceIssue[]
|
|
score: number // 0-100
|
|
stats: {
|
|
total: number
|
|
passed: number
|
|
failed: number
|
|
bySeverity: Record<TOMComplianceIssueSeverity, number>
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// CONSTANTS
|
|
// =============================================================================
|
|
|
|
export const TOM_SEVERITY_LABELS_DE: Record<TOMComplianceIssueSeverity, string> = {
|
|
CRITICAL: 'Kritisch',
|
|
HIGH: 'Hoch',
|
|
MEDIUM: 'Mittel',
|
|
LOW: 'Niedrig',
|
|
}
|
|
|
|
export const TOM_SEVERITY_COLORS: Record<TOMComplianceIssueSeverity, string> = {
|
|
CRITICAL: '#dc2626',
|
|
HIGH: '#ea580c',
|
|
MEDIUM: '#d97706',
|
|
LOW: '#6b7280',
|
|
}
|
|
|
|
// =============================================================================
|
|
// MAIN COMPLIANCE CHECK
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Fuehrt einen vollstaendigen Compliance-Check ueber alle TOMs durch.
|
|
*
|
|
* @param state - Der vollstaendige TOMGeneratorState
|
|
* @returns TOMComplianceCheckResult mit Issues, Score und Statistiken
|
|
*/
|
|
export function runTOMComplianceCheck(state: TOMGeneratorState): TOMComplianceCheckResult {
|
|
// Reset counter for deterministic IDs within a single check run
|
|
resetIssueCounter()
|
|
|
|
const issues: TOMComplianceIssue[] = []
|
|
|
|
// Filter to applicable TOMs only (REQUIRED or RECOMMENDED, exclude NOT_APPLICABLE)
|
|
const applicableTOMs = state.derivedTOMs.filter(
|
|
(tom) => tom.applicability === 'REQUIRED' || tom.applicability === 'RECOMMENDED'
|
|
)
|
|
|
|
// Run per-TOM checks (1-3, 11) on each applicable TOM
|
|
for (const tom of applicableTOMs) {
|
|
const perTomChecks = [
|
|
checkMissingResponsible(tom),
|
|
checkOverdueReview(tom),
|
|
checkMissingEvidence(tom),
|
|
checkStaleNotImplemented(tom, state),
|
|
]
|
|
|
|
for (const issue of perTomChecks) {
|
|
if (issue !== null) {
|
|
issues.push(issue)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Run aggregate checks (4-10)
|
|
issues.push(...checkIncompleteCategory(applicableTOMs))
|
|
|
|
const aggregateChecks = [
|
|
checkNoEncryption(applicableTOMs),
|
|
checkNoPseudonymization(applicableTOMs, state.dataProfile),
|
|
checkMissingAvailability(applicableTOMs, state),
|
|
checkNoReviewProcess(applicableTOMs),
|
|
checkHighRiskWithoutMeasures(applicableTOMs, state.riskProfile),
|
|
]
|
|
|
|
for (const issue of aggregateChecks) {
|
|
if (issue !== null) {
|
|
issues.push(issue)
|
|
}
|
|
}
|
|
|
|
issues.push(...checkUncoveredSDMGoal(applicableTOMs))
|
|
|
|
// Calculate score
|
|
const bySeverity: Record<TOMComplianceIssueSeverity, number> = {
|
|
LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0,
|
|
}
|
|
|
|
for (const issue of issues) {
|
|
bySeverity[issue.severity]++
|
|
}
|
|
|
|
const rawScore =
|
|
100 -
|
|
(bySeverity.CRITICAL * 15 +
|
|
bySeverity.HIGH * 10 +
|
|
bySeverity.MEDIUM * 5 +
|
|
bySeverity.LOW * 2)
|
|
|
|
const score = Math.max(0, rawScore)
|
|
|
|
// Calculate pass/fail per TOM
|
|
const failedControlIds = new Set(
|
|
issues.filter((i) => !i.controlId.startsWith('SDM-') && i.controlId !== 'RISK-PROFILE').map((i) => i.controlId)
|
|
)
|
|
const totalTOMs = applicableTOMs.length
|
|
const failedCount = failedControlIds.size
|
|
const passedCount = Math.max(0, totalTOMs - failedCount)
|
|
|
|
return {
|
|
issues,
|
|
score,
|
|
stats: {
|
|
total: totalTOMs,
|
|
passed: passedCount,
|
|
failed: failedCount,
|
|
bySeverity,
|
|
},
|
|
}
|
|
}
|