feat: Add 76 Level-2 regex checks for document correctness verification

Split dsi_document_checker.py (466 LOC) into doc_checks/ package (9 files).
Two-pass L1→L2 logic: L1 checks "Is it mentioned?", L2 checks "Is it correct?"
(e.g. controller has full address, specific Art. 6 lit., concrete time periods).

138 total checks (62 L1 + 76 L2) across 7 doc types:
- DSE Art. 13: 31, Impressum §5 TMG: 16, Cookie §25 TDDDG: 15
- Widerruf §355: 15, AGB §305ff: 21, Social Media Art. 26: 20, DSFA Art. 35: 18

Frontend: hierarchical L1→L2 display with dual progress bars
(green=completeness, blue=correctness).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-07 12:37:03 +02:00
parent 3c12e06faf
commit b363c28539
12 changed files with 2083 additions and 496 deletions
@@ -0,0 +1,230 @@
"""
DSFA checks — Art. 35 DSGVO (Datenschutz-Folgenabschaetzung).
Level 1: Pflichtangabe erwaehnt?
Level 2: Pflichtangabe korrekt/vollstaendig?
"""
DSFA_CHECKLIST = [
# ── L1: Schwellwertanalyse ────────────────────────────────────────
{
"id": "trigger",
"label": "Schwellwertanalyse / Ausloesepruefung (Art. 35(1))",
"level": 1, "parent": None,
"patterns": [
r"art\.\s*35\s*(?:abs|absatz)?\s*\.?\s*1",
r"hohes\s+risiko",
r"voraussichtlich.*risiko",
r"schwellwert",
r"folgen.*(?:verarbeitung|schutz).*personenbezogen",
],
"severity": "HIGH",
},
# ── L1: Beschreibung der Verarbeitungsvorgaenge ───────────────────
{
"id": "description",
"label": "Beschreibung der Verarbeitungsvorgaenge (Art. 35(7)(a))",
"level": 1, "parent": None,
"patterns": [
r"beschreibung.*verarbeitung", r"verarbeitungsvorg(?:ae|ä)ng",
r"systematische\s+beschreibung", r"gegenstand.*verarbeitung",
r"social\s*media.*(?:angebot|nutzung|besteht\s+aus)",
r"(?:kan(?:ae|ä)le|plattform).*(?:facebook|twitter|instagram|youtube|linkedin|xing)",
],
"severity": "HIGH",
},
{
"id": "processing_named",
"label": "Konkreter Verarbeitungsvorgang benannt",
"level": 2, "parent": "description",
"patterns": [
r"(?:betrieb|nutzung|verwaltung|pflege)\s+(?:der|von|unserer|eines)\s+(?:seite|profil|kanal|account|fanpage|pr(?:ae|ä)senz)",
r"(?:verarbeitung|erhebung|speicherung)\s+(?:von|der)\s+(?:nutzerdaten|personenbezogen|besucher|mitglieder)",
],
"severity": "LOW",
},
# ── L1: Notwendigkeit / Verhaeltnismaessigkeit ────────────────────
{
"id": "necessity",
"label": "Notwendigkeit und Verhaeltnismaessigkeit (Art. 35(7)(b))",
"level": 1, "parent": None,
"patterns": [
r"notwendigkeit", r"verh(?:ae|ä)ltnism(?:ae|ä)(?:ss|ß)igkeit",
r"erforderlichkeit", r"zweckbindung",
r"geringen?\s+umfang",
r"nur\s+(?:die|sehr).*daten.*(?:verarbeitet|erhoben)",
r"freiwillig\s+angegeben",
],
"severity": "HIGH",
},
{
"id": "legal_basis_dsfa",
"label": "Rechtsgrundlage fuer die Verarbeitung",
"level": 2, "parent": "necessity",
"patterns": [
r"rechtsgrundlage.*(?:art\.\s*6|berechtigte|einwilligung)",
r"art\.\s*6\s*(?:abs\.\s*)?1\s*(?:lit\.\s*)?[a-f]",
r"(?:einwilligung|vertrag|berechtigt).*(?:rechtsgrundlage|grundlage)",
],
"severity": "LOW",
},
# ── L1: Risikobewertung ───────────────────────────────────────────
{
"id": "risks",
"label": "Risikobewertung fuer Betroffene (Art. 35(7)(c))",
"level": 1, "parent": None,
"patterns": [
r"risiko.*(?:bewertung|analyse|einsch(?:ae|ä)tzung|abw(?:ae|ä)gung)",
r"risiken.*(?:rechte|freiheit)",
r"eintrittswahrscheinlichkeit",
r"schwere.*(?:risiko|auswirkung)",
r"hohes\s+risiko.*(?:rechte|freiheit)",
r"systematische\s+beobachtung",
],
"severity": "HIGH",
},
{
"id": "risk_probability",
"label": "Eintrittswahrscheinlichkeit bewertet",
"level": 2, "parent": "risks",
"patterns": [
r"eintrittswahrscheinlichkeit",
r"(?:wahrscheinlichkeit|likelihood)\s*[:\|]",
r"(?:gering|mittel|hoch)\w*\s+(?:wahrscheinlichkeit|eintritt)",
],
"severity": "MEDIUM",
},
{
"id": "risk_severity",
"label": "Schwere/Auswirkung bewertet",
"level": 2, "parent": "risks",
"patterns": [
r"(?:schwere|auswirkung|schadensh(?:oe|ö)he|schadenpotential|schadenpotenzial)\s*[:\|]",
r"(?:gering|mittel|hoch|kritisch)\w*\s+(?:schwere|auswirkung|schaden)",
r"(?:physisch|materiell|immateriell)\w*\s+(?:schaden|nachteil|beeintr(?:ae|ä)chtigung)",
],
"severity": "MEDIUM",
},
# ── L1: Abhilfemassnahmen ─────────────────────────────────────────
{
"id": "measures",
"label": "Abhilfemassnahmen (Art. 35(7)(d))",
"level": 1, "parent": None,
"patterns": [
r"abhilfe", r"(?:ma(?:ss|ß)nahm).*(?:risiko|schutz|minderung)",
r"schutzma(?:ss|ß)nahm",
r"(?:technisch|organisatorisch).*ma(?:ss|ß)nahm",
r"tom",
r"risiko.*(?:minim|reduz|begrenzen)",
],
"severity": "HIGH",
},
{
"id": "tom_encryption",
"label": "Verschluesselung als Massnahme",
"level": 2, "parent": "measures",
"patterns": [
r"verschl(?:ue|ü)sselung|encryption|ssl|tls|https",
r"(?:transport|ende[\-\s]zu[\-\s]ende)[\-\s]?verschl(?:ue|ü)sselung",
],
"severity": "LOW",
},
{
"id": "tom_pseudonymization",
"label": "Pseudonymisierung als Massnahme",
"level": 2, "parent": "measures",
"patterns": [
r"pseudonymisierung|anonymisierung",
r"(?:pseudonymisiert|anonymisiert).*(?:daten|verarbeit)",
],
"severity": "LOW",
},
{
"id": "tom_access_control",
"label": "Zugriffskontrolle als Massnahme",
"level": 2, "parent": "measures",
"patterns": [
r"zugriffskontrolle|zugangskontrolle|zutrittskontrolle",
r"(?:berechtigungs|rollen).*(?:konzept|management|vergabe)",
r"(?:need[\-\s]to[\-\s]know|least\s+privilege|minimalprinzip)",
],
"severity": "LOW",
},
{
"id": "tom_logging",
"label": "Protokollierung/Logging als Massnahme",
"level": 2, "parent": "measures",
"patterns": [
r"(?:protokollierung|logging|audit[\-\s]?trail|nachvollziehbarkeit)",
r"(?:zugriff|(?:ae|ä)nderung).*(?:protokoll|logging|nachvollzieh)",
],
"severity": "LOW",
},
# ── L1: Landesbehoerden ───────────────────────────────────────────
{
"id": "lfdi",
"label": "Beruecksichtigung Landesbehoerden-Richtlinie",
"level": 1, "parent": None,
"patterns": [
r"l(?:an)?fdi", r"landesbeauftragt.*datenschutz",
r"landes.?datenschutz",
r"richtlinie.*(?:land|lfdi|landes)",
r"(?:aufsichtsbeh(?:oe|ö)rde|beh(?:oe|ö)rde).*(?:richtlinie|empfehlung|vorgabe)",
],
"severity": "MEDIUM",
},
# ── L1: Einbeziehung DSB ──────────────────────────────────────────
{
"id": "stakeholders",
"label": "Einbeziehung des DSB (Art. 35(2))",
"level": 1, "parent": None,
"patterns": [
r"datenschutzbeauftragt.*(?:einbez|konsult|beteilig|rat)",
r"dsb.*(?:konsult|einbez|rat)",
r"stellungnahme.*dsb",
r"(?:rat|empfehlung).*datenschutzbeauftragt",
],
"severity": "MEDIUM",
},
{
"id": "dsb_opinion_documented",
"label": "DSB-Stellungnahme dokumentiert",
"level": 2, "parent": "stakeholders",
"patterns": [
r"stellungnahme.*(?:dsb|datenschutzbeauftragt)",
r"(?:dsb|datenschutzbeauftragt).*(?:stellungnahme|empfiehlt|bewertet|best(?:ae|ä)tigt)",
r"(?:empfehlung|beurteilung|einsch(?:ae|ä)tzung)\s+(?:des|der)\s+(?:dsb|datenschutzbeauftragt)",
],
"severity": "LOW",
},
# ── L1: Dokumentation ─────────────────────────────────────────────
{
"id": "documentation",
"label": "Dokumentation der Ergebnisse",
"level": 1, "parent": None,
"patterns": [
r"(?:dokument|ergebnis|bericht).*(?:dsfa|folgenabsch(?:ae|ä)tzung)",
r"(?:ergebnis|schlussfolgerung|bewertung).*(?:risiko|verarbeitung)",
r"vorliegend.*(?:dsfa|analyse|bewertung|absch(?:ae|ä)tzung)",
],
"severity": "MEDIUM",
},
{
"id": "review_cycle",
"label": "Ueberpruefungszyklus/Review-Termin",
"level": 2, "parent": "documentation",
"patterns": [
r"(?:ueberpr(?:ue|ü)f|überpr(?:ue|ü)f|review|aktualisierung).*(?:zyklus|turnus|j(?:ae|ä)hrlich|regelm(?:ae|ä)(?:ss|ß)ig|termin)",
r"(?:regelm(?:ae|ä)(?:ss|ß)ig|j(?:ae|ä)hrlich|quartal|halbjahr).*(?:ueberpr(?:ue|ü)f|überpr(?:ue|ü)f|review|aktualisier)",
r"n(?:ae|ä)chste\s+(?:ueberpr(?:ue|ü)fung|überprüfung|review)",
],
"severity": "LOW",
},
]