Files
breakpilot-compliance/backend-compliance/compliance/services/doc_checks/dse_checks.py
T
Benjamin Admin 870953f579 fix: PLZ regex matches lowercase text and D-78467 format
Patterns ran on text.lower() but searched [A-Z] — changed to [a-z].
Also accept D-12345 prefix (common German format).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-07 13:28:00 +02:00

360 lines
14 KiB
Python

"""
DSE (Datenschutzinformation) checks — Art. 13/14 DSGVO.
Level 1: Pflichtangabe erwaehnt?
Level 2: Pflichtangabe korrekt/vollstaendig?
"""
ART13_CHECKLIST = [
# ── L1: Verantwortlicher ──────────────────────────────────────────
{
"id": "controller",
"label": "Verantwortlicher (Art. 13(1)(a))",
"level": 1, "parent": None,
"patterns": [
r"verantwortlich\w*\s+(?:ist|im sinne|fuer|f(?:ue|ü)r)",
r"kontaktdaten\s+des\s+verantwortlichen",
r"name\s+(?:und|&)\s+kontaktdaten\s+des",
r"controller", r"verantwortliche\s+stelle",
r"responsible\s+(?:party|for)",
],
"severity": "HIGH",
},
{
"id": "controller_address",
"label": "Vollstaendige Anschrift (PLZ + Ort)",
"level": 2, "parent": "controller",
"patterns": [
r"(?:d[\-\s]?)?\d{5}\s+[a-z\u00c0-\u017e]\w{2,}",
r"[a-z\u00c0-\u017e]\w+(?:str|stra(?:ss|ß)e|weg|platz|allee|gasse|ring|damm)\s*\.?\s*\d",
],
"severity": "MEDIUM",
},
{
"id": "controller_email",
"label": "E-Mail-Adresse des Verantwortlichen",
"level": 2, "parent": "controller",
"patterns": [
r"[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,}",
],
"severity": "MEDIUM",
},
{
"id": "controller_phone",
"label": "Telefonnummer des Verantwortlichen",
"level": 2, "parent": "controller",
"patterns": [
r"(?:tel(?:efon)?|phone|fon)\s*[.:]\s*[\+\d][\d\s/\-]{6,}",
r"\+49\s*[\d\s/\-]{8,}",
],
"severity": "MEDIUM",
},
# ── L1: Datenschutzbeauftragter ───────────────────────────────────
{
"id": "dpo",
"label": "Datenschutzbeauftragter (Art. 13(1)(b))",
"level": 1, "parent": None,
"patterns": [
r"datenschutzbeauftragt", r"data\s+protection\s+officer",
r"kontaktdaten\s+de[rs]\s+(?:beh(?:oe|ö)rdlichen\s+)?datenschutz",
r"dsb", r"dpo",
],
"severity": "MEDIUM",
},
{
"id": "dpo_contact",
"label": "Kontaktdaten des DSB (E-Mail oder Telefon)",
"level": 2, "parent": "dpo",
"patterns": [
r"datenschutz(?:beauftragter?|beauftragte).*?[a-z0-9._%+\-]+@",
r"dsb.*?@|dpo.*?@",
r"datenschutz@",
],
"severity": "MEDIUM",
},
# ── L1: Zwecke der Verarbeitung ───────────────────────────────────
{
"id": "purposes",
"label": "Zwecke der Verarbeitung (Art. 13(1)(c))",
"level": 1, "parent": None,
"patterns": [
r"zweck\w*\s+(?:der|und|die)\s+(?:verarbeitung|datenerhebung|datenverarbeitung|rechtsgrundlage)",
r"purpose\w*\s+(?:of|for)\s+(?:processing|data)",
r"zu\s+welch\w+\s+zweck",
r"welche\s+daten\s+werden.*verarbeitet",
r"daten\s+werden\s+(?:zu|fuer|für)\s+(?:folgende|diese)",
],
"severity": "HIGH",
},
{
"id": "purposes_specific",
"label": "Konkrete Zwecke benannt (min. 2)",
"level": 2, "parent": "purposes",
"patterns": [
r"(?:kontaktaufnahme|vertragserfuellung|vertragserf(?:ue|ü)llung|newsletter|analyse|statistik|werbung|marketing|bewerbung|bestellabwicklung|kundenkonto)",
r"(?:bereitstellung|betrieb|sicherheit|optimierung)\s+(?:der|des|unserer|unseres)",
],
"severity": "LOW",
},
# ── L1: Rechtsgrundlage ───────────────────────────────────────────
{
"id": "legal_basis",
"label": "Rechtsgrundlage (Art. 13(1)(c))",
"level": 1, "parent": None,
"patterns": [
r"rechtsgrundlage", r"art\.\s*6\s*(?:abs|absatz)?\s*\.?\s*1",
r"legal\s+basis", r"berechtigtes\s+interesse",
r"auf\s+grundlage\s+(?:von|des|der)\s+(?:art|§)",
r"lit\.\s*[a-f][\s\)]",
r"gem(?:ae|ä)(?:ss|ß)\s+art",
r"§\s*\d+\s+(?:abs|ihkg|bdsg|ldsg|bbig|tdddg)",
r"einwilligung\s+gem",
],
"severity": "HIGH",
},
{
"id": "legal_basis_consent_6a",
"label": "Art. 6(1)(a) — Einwilligung",
"level": 2, "parent": "legal_basis",
"patterns": [
r"art\.\s*6\s*(?:abs\.\s*)?1\s*(?:s\.\s*1\s*)?(?:lit\.\s*)?a",
r"einwilligung\s+(?:gem|nach|i\.?\s*s\.?\s*d\.?)",
],
"severity": "LOW",
},
{
"id": "legal_basis_contract_6b",
"label": "Art. 6(1)(b) — Vertragserfullung",
"level": 2, "parent": "legal_basis",
"patterns": [
r"art\.\s*6\s*(?:abs\.\s*)?1\s*(?:s\.\s*1\s*)?(?:lit\.\s*)?b",
r"vertragserf(?:ue|ü)llung",
r"durchf(?:ue|ü)hrung\s+(?:eines|des|vorvertragliche)",
],
"severity": "LOW",
},
{
"id": "legal_basis_interest_6f",
"label": "Art. 6(1)(f) — Berechtigtes Interesse",
"level": 2, "parent": "legal_basis",
"patterns": [
r"art\.\s*6\s*(?:abs\.\s*)?1\s*(?:s\.\s*1\s*)?(?:lit\.\s*)?f",
r"berechtigte[sn]?\s+interesse",
],
"severity": "LOW",
},
{
"id": "legal_basis_balancing",
"label": "Interessenabwaegung dokumentiert",
"level": 2, "parent": "legal_basis",
"patterns": [
r"interessenabw(?:ae|ä)gung",
r"(?:ueberwiegen|überwiegen).*interesse",
r"abw(?:ae|ä)gung.*(?:recht|interesse|freiheit)",
],
"severity": "LOW",
},
# ── L1: Empfaenger ────────────────────────────────────────────────
{
"id": "recipients",
"label": "Empfaenger (Art. 13(1)(e))",
"level": 1, "parent": None,
"patterns": [
r"empf(?:ae|ä)nger", r"(?:ueber|über|weiter)mitt(?:el|l)ung",
r"recipient", r"weitergabe\s+(?:an|von)\s+daten",
r"dritte", r"third\s+part",
r"auftragsverarbeit",
],
"severity": "MEDIUM",
},
{
"id": "recipients_categories",
"label": "Konkrete Empfaenger-Kategorien benannt",
"level": 2, "parent": "recipients",
"patterns": [
r"(?:hosting|server|cloud|payment|zahlungs|versand|logistik|steuerberater|buchhalter|newsletter|crm|erp)",
r"(?:dienstleister|auftragnehmer|subunternehmer).*(?:fuer|für|im bereich)",
],
"severity": "LOW",
},
{
"id": "recipients_processor",
"label": "Auftragsverarbeiter erwaehnt",
"level": 2, "parent": "recipients",
"patterns": [
r"auftragsverarbeit(?:er|ung)",
r"art\.\s*28",
r"avv|av-vertrag|auftragsverarbeitungsvertrag",
],
"severity": "LOW",
},
# ── L1: Drittlandtransfer ─────────────────────────────────────────
{
"id": "third_country",
"label": "Drittlandtransfer (Art. 13(1)(f))",
"level": 1, "parent": None,
"patterns": [
r"drittland", r"dritt\s*staat", r"drittl(?:ae|ä)nder",
r"third\s+countr", r"angemessenheitsbeschluss",
r"standard\s*vertragsklausel", r"scc",
r"(?:ueber|über)mittlung.*(?:ausserhalb|außerhalb)",
r"(?:europ(?:ae|ä)ischen\s+wirtschaftsraum|ewr|eea)",
r"privacy\s+shield", r"data\s+privacy\s+framework",
],
"severity": "MEDIUM",
},
{
"id": "third_country_mechanism",
"label": "Transfermechanismus benannt (SCC/DPF/Angemessenheit)",
"level": 2, "parent": "third_country",
"patterns": [
r"standard\s*vertragsklausel|scc|standard\s+contractual",
r"data\s+privacy\s+framework|dpf",
r"angemessenheitsbeschluss|adequacy\s+decision",
r"art\.\s*4[5-9]",
],
"severity": "MEDIUM",
},
# ── L1: Speicherdauer ─────────────────────────────────────────────
{
"id": "retention",
"label": "Speicherdauer (Art. 13(2)(a))",
"level": 1, "parent": None,
"patterns": [
r"speicherdauer", r"aufbewahrungsfrist",
r"(?:wie\s+lange|dauer)\s+(?:der\s+)?(?:werden|gespeicher|speicherung)",
r"retention\s+period", r"l(?:oe|ö)sch(?:ung|frist|konzept)",
r"daten\s+werden\s+gel(?:oe|ö)scht",
r"(?:\d+\s+(?:tage|monate|jahre)|nach\s+\d+\s+(?:tag|monat|jahr))",
r"dauer\s+der\s+speicherung",
r"aufbewahrung(?:sdauer|spflicht|szeit)",
r"gesetzliche.*aufbewahrung",
],
"severity": "HIGH",
},
{
"id": "retention_periods",
"label": "Konkrete Zeitangaben (Tage/Monate/Jahre)",
"level": 2, "parent": "retention",
"patterns": [
r"\d+\s+(?:tage?|monate?|jahre?|days?|months?|years?)",
r"(?:6|10)\s+jahre.*(?:handels|steuer|hgb|ao)",
r"(?:nach|innerhalb)\s+(?:von\s+)?\d+\s+(?:tag|monat|jahr)",
],
"severity": "MEDIUM",
},
{
"id": "retention_deletion",
"label": "Loeschkonzept/-prozess beschrieben",
"level": 2, "parent": "retention",
"patterns": [
r"l(?:oe|ö)schkonzept", r"l(?:oe|ö)schfrist",
r"(?:regel|routinem(?:ae|ä)(?:ss|ß)ig).*l(?:oe|ö)sch",
r"nach\s+(?:ablauf|wegfall).*(?:gel(?:oe|ö)scht|l(?:oe|ö)sch)",
],
"severity": "LOW",
},
# ── L1: Betroffenenrechte ─────────────────────────────────────────
{
"id": "rights",
"label": "Betroffenenrechte (Art. 13(2)(b))",
"level": 1, "parent": None,
"patterns": [
r"recht\s+auf\s+auskunft", r"recht\s+auf\s+l(?:oe|ö)schung",
r"recht\s+auf\s+berichtigung", r"widerspruchsrecht",
r"art\.\s*1[5-9]", r"art\.\s*2[0-2]",
r"right\s+to\s+(?:access|erasure|rectification|object)",
r"betroffenenrecht", r"rechte\s+(?:des|der)\s+betroffenen",
r"ihnen\s+(?:stehen|steht)\s+(?:ein|folgende)\s+recht",
],
"severity": "HIGH",
},
{
"id": "rights_art15",
"label": "Recht auf Auskunft (Art. 15)",
"level": 2, "parent": "rights",
"patterns": [r"art\.\s*15", r"recht\s+auf\s+auskunft", r"right\s+(?:of|to)\s+access"],
"severity": "LOW",
},
{
"id": "rights_art16",
"label": "Recht auf Berichtigung (Art. 16)",
"level": 2, "parent": "rights",
"patterns": [r"art\.\s*16", r"recht\s+auf\s+berichtigung", r"right\s+to\s+rectification"],
"severity": "LOW",
},
{
"id": "rights_art17",
"label": "Recht auf Loeschung (Art. 17)",
"level": 2, "parent": "rights",
"patterns": [r"art\.\s*17", r"recht\s+auf\s+l(?:oe|ö)schung", r"right\s+to\s+erasure"],
"severity": "LOW",
},
{
"id": "rights_art18",
"label": "Recht auf Einschraenkung (Art. 18)",
"level": 2, "parent": "rights",
"patterns": [r"art\.\s*18", r"einschr(?:ae|ä)nkung\s+der\s+verarbeitung", r"right\s+to\s+restriction"],
"severity": "LOW",
},
{
"id": "rights_art20",
"label": "Recht auf Datenportabilitaet (Art. 20)",
"level": 2, "parent": "rights",
"patterns": [r"art\.\s*20", r"daten(?:ue|ü)bertragbarkeit|datenportabilit", r"right\s+to\s+data\s+portability"],
"severity": "LOW",
},
{
"id": "rights_art21",
"label": "Widerspruchsrecht (Art. 21)",
"level": 2, "parent": "rights",
"patterns": [r"art\.\s*21", r"widerspruchsrecht", r"right\s+to\s+object"],
"severity": "LOW",
},
{
"id": "rights_art22_profiling",
"label": "Automatisierte Entscheidungen / Profiling (Art. 22)",
"level": 2, "parent": "rights",
"patterns": [
r"art\.\s*22", r"automatisierte\s+entscheidung",
r"profiling", r"automated\s+(?:decision|individual)",
],
"severity": "LOW",
},
# ── L1: Beschwerderecht ───────────────────────────────────────────
{
"id": "complaint",
"label": "Beschwerderecht (Art. 13(2)(d))",
"level": 1, "parent": None,
"patterns": [
r"beschwerderecht", r"aufsichtsbeh(?:oe|ö)rde",
r"right\s+to\s+lodge\s+a\s+complaint",
r"supervisory\s+authority", r"datenschutzbeh(?:oe|ö)rde",
r"recht\s+auf\s+beschwerde", r"art\.\s*77",
r"beschwerde.*(?:wenden|einlegen|erheben)",
r"(?:zust(?:ae|ä)ndige|competent)\s+(?:beh(?:oe|ö)rde|authority)",
],
"severity": "MEDIUM",
},
{
"id": "complaint_authority_named",
"label": "Konkrete Aufsichtsbehoerde benannt",
"level": 2, "parent": "complaint",
"patterns": [
r"(?:landes|l)(?:beauftragt|datenschutz).*(?:niedersachsen|bayern|nrw|nordrhein|hessen|baden|schleswig|brandenburg|sachsen|berlin|hamburg|bremen|thueringen|thüringen|saarland|rheinland|mecklenburg)",
r"l(?:an)?fdi\s+\w+",
r"bfdi",
r"(?:bayerische|hessische|s(?:ae|ä)chsische|berliner)\s+(?:datenschutz|aufsicht)",
],
"severity": "LOW",
},
]