"""TOM template generator V2 — SDM-structured TOM catalog. Replaces the flat 17-measure list with a hierarchical structure based on the 7 SDM Gewaehrleistungsziele (Standard-Datenschutzmodell V3.1a). """ # -- SDM-structured TOM catalog --------------------------------------------- SDM_TOM_CATALOG = { "verfuegbarkeit": { "label": "Verfuegbarkeit", "sdm_baustein": "SDM-B11 (Aufbewahren)", "measures": [ {"name": "Redundante Datenhaltung", "description": "RAID, Replikation, Geo-Redundanz", "type": "technical"}, {"name": "Backup-Strategie", "description": "Taeglich inkrementell, woechentlich voll, verschluesselt", "type": "technical"}, {"name": "Disaster-Recovery-Plan", "description": "Dokumentierte RTO/RPO-Werte, jaehrliche Tests", "type": "organizational"}, {"name": "USV / Notstromversorgung", "description": "Unterbrechungsfreie Stromversorgung fuer kritische Systeme", "type": "technical"}, ], }, "integritaet": { "label": "Integritaet", "sdm_baustein": "SDM-B61 (Berichtigen)", "measures": [ {"name": "Pruefsummen und Signaturen", "description": "Digitale Signaturen fuer Datenuebertragungen", "type": "technical"}, {"name": "Eingabevalidierung", "description": "Plausibilitaetspruefungen auf allen Eingabeschnittstellen", "type": "technical"}, {"name": "Change Management", "description": "Dokumentierte Aenderungsverfahren mit Freigabeprozess", "type": "organizational"}, {"name": "Versionierung", "description": "Versionierung von Datensaetzen und Konfigurationen", "type": "technical"}, ], }, "vertraulichkeit": { "label": "Vertraulichkeit", "sdm_baustein": "SDM-B51 (Zugriffe regeln)", "measures": [ {"name": "Verschluesselung im Transit", "description": "TLS 1.3 fuer alle Verbindungen", "type": "technical"}, {"name": "Verschluesselung at Rest", "description": "AES-256 fuer gespeicherte Daten", "type": "technical"}, {"name": "Zugriffskonzept (RBAC)", "description": "Rollenbasiert, Least-Privilege-Prinzip, regelmaessige Reviews", "type": "technical"}, {"name": "Multi-Faktor-Authentifizierung", "description": "MFA fuer alle administrativen Zugaenge", "type": "technical"}, {"name": "Physische Zutrittskontrolle", "description": "Schluessel, Kartenleser, Besucherprotokoll", "type": "technical"}, {"name": "Vertraulichkeitsverpflichtung", "description": "Schriftliche Verpflichtung aller Mitarbeitenden", "type": "organizational"}, ], }, "nichtverkettung": { "label": "Nichtverkettung", "sdm_baustein": "SDM-B50 (Trennen)", "measures": [ {"name": "Mandantentrennung", "description": "Logische Datentrennung nach Mandanten/Zweck", "type": "technical"}, {"name": "Pseudonymisierung", "description": "Wo fachlich moeglich, Einsatz von Pseudonymen", "type": "technical"}, {"name": "Zweckbindungspruefung", "description": "Pruefung bei jeder neuen Datennutzung", "type": "organizational"}, ], }, "transparenz": { "label": "Transparenz", "sdm_baustein": "SDM-B42 (Dokumentieren), SDM-B43 (Protokollieren)", "measures": [ {"name": "Verarbeitungsverzeichnis", "description": "Art. 30 DS-GVO konformes VVT", "type": "organizational"}, {"name": "Audit-Logging", "description": "Vollstaendige Protokollierung aller Datenzugriffe", "type": "technical"}, {"name": "Informationspflichten", "description": "Art. 13/14 DS-GVO Datenschutzerklaerung", "type": "organizational"}, {"name": "Datenpannen-Prozess", "description": "Dokumentierter Meldeprozess Art. 33/34 DS-GVO", "type": "organizational"}, ], }, "intervenierbarkeit": { "label": "Intervenierbarkeit", "sdm_baustein": "SDM-B60 (Loeschen), SDM-B61 (Berichtigen), SDM-B62 (Einschraenken)", "measures": [ {"name": "Betroffenenanfragen-Prozess", "description": "Auskunft, Loeschung, Berichtigung, Widerspruch", "type": "organizational"}, {"name": "Technische Loeschfaehigkeit", "description": "Loeschung mit Nachweis (Loeschprotokoll)", "type": "technical"}, {"name": "Datenportabilitaet", "description": "Export in maschinenlesbarem Format (Art. 20)", "type": "technical"}, {"name": "Sperrfunktion", "description": "Einschraenkung der Verarbeitung moeglich", "type": "technical"}, ], }, "datenminimierung": { "label": "Datenminimierung", "sdm_baustein": "SDM-B41 (Planen und Spezifizieren)", "measures": [ {"name": "Erforderlichkeitspruefung", "description": "Regelmaessige Pruefung der erhobenen Datenfelder", "type": "organizational"}, {"name": "Automatisierte Loeschung", "description": "Fristgerechte Loeschung nach Aufbewahrungsfrist", "type": "technical"}, {"name": "Anonymisierung", "description": "Anonymisierung/Aggregation fuer Statistik", "type": "technical"}, {"name": "Privacy by Design", "description": "Datenschutz ab Entwurfsphase neuer Verarbeitungen", "type": "organizational"}, ], }, } # -- Sector-specific extensions ---------------------------------------------- SECTOR_TOMS = { "it_saas": { "label": "IT / SaaS", "measures": [ {"name": "Container-Isolation", "description": "Workload-Isolation zwischen Mandanten (Kubernetes Namespaces)", "type": "technical", "sdm_goal": "nichtverkettung"}, {"name": "API-Security", "description": "Rate Limiting, OAuth 2.0, API-Key-Rotation", "type": "technical", "sdm_goal": "vertraulichkeit"}, {"name": "DevSecOps Pipeline", "description": "SAST/DAST in CI/CD, Dependency Scanning", "type": "technical", "sdm_goal": "integritaet"}, {"name": "Secrets Management", "description": "Vault/KMS fuer Credentials, keine Hardcoded Secrets", "type": "technical", "sdm_goal": "vertraulichkeit"}, ], }, "gesundheitswesen": { "label": "Gesundheitswesen", "measures": [ {"name": "Patientenakten-Verschluesselung", "description": "Ende-zu-Ende-Verschluesselung fuer Gesundheitsdaten (Art. 9)", "type": "technical", "sdm_goal": "vertraulichkeit"}, {"name": "Notfallzugriff", "description": "Break-the-Glass-Verfahren fuer medizinische Notfaelle", "type": "organizational", "sdm_goal": "verfuegbarkeit"}, {"name": "Forschungsdaten-Anonymisierung", "description": "Vollstaendige Anonymisierung vor Forschungsnutzung", "type": "technical", "sdm_goal": "datenminimierung"}, ], }, "finanzdienstleistungen": { "label": "Finanzdienstleistungen", "measures": [ {"name": "Transaktions-Monitoring", "description": "Echtzeit-Ueberwachung auf Unregelmaessigkeiten (GwG)", "type": "technical", "sdm_goal": "integritaet"}, {"name": "Aufbewahrungspflichten", "description": "10 Jahre Aufbewahrung gemaess AO/HGB, danach Loeschung", "type": "organizational", "sdm_goal": "datenminimierung"}, {"name": "PCI-DSS Compliance", "description": "Payment Card Industry Standards fuer Kartendaten", "type": "technical", "sdm_goal": "vertraulichkeit"}, ], }, "handel": { "label": "Handel / E-Commerce", "measures": [ {"name": "Cookie-Consent-Management", "description": "TDDDG-konformes Einwilligungsmanagement", "type": "technical", "sdm_goal": "transparenz"}, {"name": "Gastzugang-Option", "description": "Bestellung ohne Pflicht-Kundenkonto (Datenminimierung)", "type": "organizational", "sdm_goal": "datenminimierung"}, {"name": "Zahlungsdaten-Tokenisierung", "description": "Keine direkte Speicherung von Zahlungsdaten", "type": "technical", "sdm_goal": "vertraulichkeit"}, ], }, "handwerk": { "label": "Handwerk", "measures": [ {"name": "Mobile-Device-Management", "description": "Absicherung mobiler Endgeraete auf Baustellen", "type": "technical", "sdm_goal": "vertraulichkeit"}, {"name": "Papierakten-Sicherung", "description": "Verschlossene Schraenke fuer physische Kundenakten", "type": "technical", "sdm_goal": "vertraulichkeit"}, ], }, } # -- NIS2 / ISO 27001 / AI Act extensions ----------------------------------- NIS2_TOMS = [ {"name": "Incident-Response-Plan", "description": "NIS2-konformer Vorfallreaktionsplan (72h Meldepflicht an BSI)", "type": "organizational", "sdm_goal": "verfuegbarkeit"}, {"name": "Supply-Chain-Security", "description": "Bewertung der Lieferkettensicherheit (BSIG 2025)", "type": "organizational", "sdm_goal": "integritaet"}, {"name": "Vulnerability Management", "description": "Regelmaessige Schwachstellenscans, Patch-Management", "type": "technical", "sdm_goal": "integritaet"}, {"name": "Security Awareness", "description": "Pflicht-Schulungen Cybersicherheit fuer Geschaeftsleitung", "type": "organizational", "sdm_goal": "vertraulichkeit"}, ] ISO27001_TOMS = [ {"name": "ISMS Risikomanagement", "description": "ISO 27001 Anhang A — Informationssicherheits-Risikobewertung", "type": "organizational", "sdm_goal": "verfuegbarkeit"}, {"name": "Dokumentenlenkung", "description": "Versionierte Sicherheitsrichtlinien und -verfahren", "type": "organizational", "sdm_goal": "transparenz"}, {"name": "Management Review", "description": "Jaehrliche Ueberprufung des ISMS durch Geschaeftsleitung", "type": "organizational", "sdm_goal": "transparenz"}, ] AI_ACT_TOMS = [ {"name": "KI-Risikoklassifizierung", "description": "Bewertung aller KI-Systeme nach EU AI Act Risikokategorien", "type": "organizational", "sdm_goal": "transparenz"}, {"name": "Human Oversight", "description": "Menschliche Aufsicht fuer Hochrisiko-KI-Systeme (Art. 14 KI-VO)", "type": "organizational", "sdm_goal": "intervenierbarkeit"}, {"name": "KI-Transparenz", "description": "Transparenzpflichten bei KI-Einsatz gegenueber Betroffenen (Art. 13 KI-VO)", "type": "organizational", "sdm_goal": "transparenz"}, {"name": "KI-Bias-Monitoring", "description": "Ueberwachung auf diskriminierende Ergebnisse", "type": "technical", "sdm_goal": "integritaet"}, ] def generate_tom_drafts(ctx: dict) -> list[dict]: """Generate TOM measure drafts structured by SDM Gewaehrleistungsziele. Args: ctx: Flat dict from company-profile/template-context. Returns: List of TOM measure dicts with SDM goal assignment. """ measures = [] control_counter = 0 # Base SDM measures for goal_key, goal_data in SDM_TOM_CATALOG.items(): for m in goal_data["measures"]: control_counter += 1 measures.append(_build_measure( counter=control_counter, measure=m, sdm_goal=goal_key, sdm_baustein=goal_data["sdm_baustein"], category=goal_data["label"], ctx=ctx, )) # Regulatory extensions if ctx.get("subject_to_nis2"): for m in NIS2_TOMS: control_counter += 1 measures.append(_build_measure( counter=control_counter, measure=m, sdm_goal=m["sdm_goal"], sdm_baustein="NIS2 / BSIG 2025", category="Cybersicherheit (NIS2)", ctx=ctx, )) if ctx.get("subject_to_iso27001"): for m in ISO27001_TOMS: control_counter += 1 measures.append(_build_measure( counter=control_counter, measure=m, sdm_goal=m["sdm_goal"], sdm_baustein="ISO 27001 Anhang A", category="ISMS (ISO 27001)", ctx=ctx, )) if ctx.get("subject_to_ai_act") or ctx.get("has_ai_systems"): for m in AI_ACT_TOMS: control_counter += 1 measures.append(_build_measure( counter=control_counter, measure=m, sdm_goal=m["sdm_goal"], sdm_baustein="EU AI Act (2024/1689)", category="KI-Compliance", ctx=ctx, )) # Sector-specific extensions sector = _detect_sector(ctx) if sector and sector in SECTOR_TOMS: sector_data = SECTOR_TOMS[sector] for m in sector_data["measures"]: control_counter += 1 measures.append(_build_measure( counter=control_counter, measure=m, sdm_goal=m.get("sdm_goal", "vertraulichkeit"), sdm_baustein=f"Sektor: {sector_data['label']}", category=f"Sektor ({sector_data['label']})", ctx=ctx, )) return measures def sdm_coverage_summary(measures: list[dict]) -> dict: """Return coverage matrix: SDM goal -> measure count.""" summary = {} for goal_key in SDM_TOM_CATALOG: count = sum(1 for m in measures if m.get("sdm_goal") == goal_key) summary[goal_key] = { "label": SDM_TOM_CATALOG[goal_key]["label"], "count": count, } return summary # -- Internal helpers -------------------------------------------------------- def _build_measure(counter: int, measure: dict, sdm_goal: str, sdm_baustein: str, category: str, ctx: dict) -> dict: return { "control_id": f"TOM-SDM-{counter:03d}", "name": measure["name"], "description": measure["description"], "category": category, "type": measure.get("type", "organizational"), "sdm_goal": sdm_goal, "sdm_baustein_ref": sdm_baustein, "implementation_status": "not_implemented", "effectiveness_rating": "not_assessed", "responsible_department": "IT-Sicherheit", "priority": _assess_priority(measure, ctx), "review_frequency": f"{ctx.get('review_cycle_months', 12)} Monate", } def _assess_priority(measure: dict, ctx: dict) -> str: name_lower = measure.get("name", "").lower() if any(kw in name_lower for kw in ["verschluesselung", "mfa", "incident", "ki-risiko"]): return "high" if any(kw in name_lower for kw in ["backup", "zugriff", "logging", "loeschung"]): return "high" return "medium" def _detect_sector(ctx: dict) -> str | None: """Map company industry to sector key.""" industry = (ctx.get("industry") or "").lower() mapping = { "technologie": "it_saas", "it": "it_saas", "saas": "it_saas", "software": "it_saas", "gesundheit": "gesundheitswesen", "pharma": "gesundheitswesen", "medizin": "gesundheitswesen", "finanz": "finanzdienstleistungen", "bank": "finanzdienstleistungen", "versicherung": "finanzdienstleistungen", "handel": "handel", "e-commerce": "handel", "einzelhandel": "handel", "shop": "handel", "handwerk": "handwerk", "bau": "handwerk", "kfz": "handwerk", } for keyword, sector in mapping.items(): if keyword in industry: return sector return None