feat(audit): P71 JC-vs-AVV Entscheidungsbaum
CI / detect-changes (push) Successful in 10s
CI / branch-name (push) Has been skipped
CI / validate-canonical-controls (push) Successful in 15s
CI / test-python-backend (push) Successful in 39s
CI / test-python-document-crawler (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / loc-budget (push) Failing after 17s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Has been skipped
CI / test-go (push) Has been skipped
CI / iace-gt-coverage (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
CI / detect-changes (push) Successful in 10s
CI / branch-name (push) Has been skipped
CI / validate-canonical-controls (push) Successful in 15s
CI / test-python-backend (push) Successful in 39s
CI / test-python-document-crawler (push) Has been skipped
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / loc-budget (push) Failing after 17s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / nodejs-build (push) Has been skipped
CI / test-go (push) Has been skipped
CI / iace-gt-coverage (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped
jc_avv_decision.py: detect_ambiguous_jc_avv prueft ob DSE-Text sowohl JC-Signale (gemeinsame Auswertung, Schwesterunternehmen, Konzern...) als auch AVV-Signale (Auftragsverarbeiter, weisungsgebunden...) enthaelt. Bei Treffer rendert build_jc_avv_decision_html einen Block mit 4 EDPB- basierten Leitfragen + jeweiliger Empfehlung. Quellen: EDPB Guidelines 7/2020, EuGH C-25/17, C-40/17. In Mail-Render zwischen Solutions-Block und VVT eingehaengt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1220,6 +1220,16 @@ async def _run_compliance_check(check_id: str, req: ComplianceCheckRequest):
|
||||
except Exception as e:
|
||||
logger.warning("P73 MC-Solution-Generator skipped: %s", e)
|
||||
|
||||
# P71: JC-vs-AVV Entscheidungsbaum (nur wenn DSE ambig)
|
||||
jc_decision_html = ""
|
||||
try:
|
||||
from compliance.services.jc_avv_decision import (
|
||||
build_jc_avv_decision_html,
|
||||
)
|
||||
jc_decision_html = build_jc_avv_decision_html(doc_texts.get("dse"))
|
||||
except Exception as e:
|
||||
logger.warning("P71 jc_avv_decision skipped: %s", e)
|
||||
|
||||
# P82: GF-1-Pager ganz oben in der Mail — 5-Bullet-Zusammenfassung
|
||||
# damit die GF nicht 124k Char lesen muss.
|
||||
gf_one_pager_html = ""
|
||||
@@ -1285,6 +1295,7 @@ async def _run_compliance_check(check_id: str, req: ComplianceCheckRequest):
|
||||
+ scorecard_html + redundancy_html
|
||||
+ providers_html + banner_deep_html + library_mismatch_html
|
||||
+ consistency_html + signals_html + solutions_html
|
||||
+ jc_decision_html
|
||||
+ vvt_html + report_html
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
"""
|
||||
P71 — JC-vs-AVV Entscheidungsbaum.
|
||||
|
||||
Hilft dem Nutzer zu bestimmen, ob ein bestimmtes Verarbeitungsverhaeltnis
|
||||
gemeinsame Verantwortlichkeit (Art. 26 DSGVO) oder Auftragsverarbeitung
|
||||
(Art. 28 DSGVO) ist. EDPB 7/2020 ist die Grundlage.
|
||||
|
||||
Wird gerendert als kleiner Block am Ende der Mail, wenn im DSE-Text
|
||||
Konstrukte vorkommen die ambivalent sind (z.B. 'gemeinsame Auswertung
|
||||
mit Schwesterunternehmen', 'gemeinsame Plattform-Nutzung'). Liefert
|
||||
3-4 Leitfragen + jeweilige Empfehlung.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_JC_SIGNALS = (
|
||||
"schwesterunternehmen", "konzernschwester", "gemeinsame plattform",
|
||||
"gemeinsame auswertung", "gemeinsame studie", "joint venture",
|
||||
"konzernweite analyse", "gemeinsame zwecke", "gemeinsame ziele",
|
||||
"konzernweit", "gemeinsamer kunde", "gemeinsamer datenpool",
|
||||
)
|
||||
|
||||
_AVV_SIGNALS = (
|
||||
"auftragsverarbeiter", "auftragsverarbeitung", "weisungsgebunden",
|
||||
"im auftrag von", "im namen des verantwortlichen",
|
||||
"art. 28 dsgvo", "art 28 dsgvo", "dpa (data processing agreement",
|
||||
)
|
||||
|
||||
_QUESTIONS = [
|
||||
{
|
||||
"q": "Bestimmen beide Seiten gemeinsam Zweck UND Mittel der Verarbeitung?",
|
||||
"yes": "JC (Art. 26)",
|
||||
"no": "AVV-Indikator",
|
||||
"explain": "EDPB 7/2020 Rn. 51-65: beidseitige Zweckbestimmung ist "
|
||||
"das Hauptmerkmal der gemeinsamen Verantwortlichkeit.",
|
||||
},
|
||||
{
|
||||
"q": "Verfolgen die Parteien eigene, getrennte Zwecke (z.B. eigene "
|
||||
"Kundenbeziehung) oder einen gemeinsamen Zweck?",
|
||||
"yes": "Wenn getrennt: AVV (oder zwei getrennte Verantwortliche)",
|
||||
"no": "Wenn gemeinsam: JC (Art. 26)",
|
||||
"explain": "EuGH C-25/17 Zeugen Jehovas: getrennte Zwecke "
|
||||
"schliessen JC aus.",
|
||||
},
|
||||
{
|
||||
"q": "Existiert eine schriftliche Weisungs-Hierarchie und Pflicht "
|
||||
"zur Loeschung am Vertragsende?",
|
||||
"yes": "AVV (Art. 28 Pflichten erfuellt)",
|
||||
"no": "Pruefen ob JC vorliegt + Art. 26-Vereinbarung noetig",
|
||||
"explain": "Art. 28 (3)(g) DSGVO + EDPB 7/2020 Rn. 88.",
|
||||
},
|
||||
{
|
||||
"q": "Haben Betroffene gegenueber beiden Stellen vollstaendige "
|
||||
"Rechte (Art. 15-22)?",
|
||||
"yes": "JC — Art. 26 (3) verlangt einheitliche Anlaufstelle",
|
||||
"no": "AVV — Auftragsverarbeiter weist Rechtsausuebung an "
|
||||
"Verantwortlichen zurueck",
|
||||
"explain": "Art. 26 (3) DSGVO macht beide Stellen als gemeinsame "
|
||||
"Anlaufstelle ansprechbar.",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def detect_ambiguous_jc_avv(dse_text: str | None) -> bool:
|
||||
"""Heuristik: liegen sowohl JC- als auch AVV-Signale im DSE? Dann
|
||||
ist die Konstellation typischerweise unklar und der Entscheidungsbaum
|
||||
hilft."""
|
||||
if not dse_text:
|
||||
return False
|
||||
t = dse_text.lower()
|
||||
has_jc = any(s in t for s in _JC_SIGNALS)
|
||||
has_avv = any(s in t for s in _AVV_SIGNALS)
|
||||
return has_jc and has_avv
|
||||
|
||||
|
||||
def build_jc_avv_decision_html(dse_text: str | None) -> str:
|
||||
if not detect_ambiguous_jc_avv(dse_text):
|
||||
return ""
|
||||
items = []
|
||||
for i, q in enumerate(_QUESTIONS, 1):
|
||||
items.append(
|
||||
f'<li style="margin-bottom:8px;font-size:11px;line-height:1.5">'
|
||||
f'<strong>{i}. {q["q"]}</strong><br>'
|
||||
f'<span style="color:#16a34a">Ja: </span>{q["yes"]} | '
|
||||
f'<span style="color:#dc2626">Nein: </span>{q["no"]}<br>'
|
||||
f'<span style="color:#64748b;font-size:10px;font-style:italic">'
|
||||
f'{q["explain"]}</span>'
|
||||
f'</li>'
|
||||
)
|
||||
return (
|
||||
'<div style="font-family:-apple-system,BlinkMacSystemFont,sans-serif;'
|
||||
'max-width:760px;margin:0 auto 16px;padding:12px 16px;'
|
||||
'background:#f1f5f9;border:1px solid #cbd5e1;border-radius:6px">'
|
||||
'<div style="font-size:11px;color:#475569;text-transform:uppercase;'
|
||||
'letter-spacing:1.2px;margin-bottom:4px;font-weight:600">'
|
||||
'JC vs AVV — Entscheidungshilfe</div>'
|
||||
'<h3 style="margin:0 0 6px;font-size:14px;color:#1e293b">'
|
||||
'Im DSE-Text gibt es sowohl gemeinsame-Verantwortlichkeits- als '
|
||||
'auch Auftragsverarbeitungs-Hinweise</h3>'
|
||||
'<p style="margin:0 0 10px;font-size:11px;color:#475569;line-height:1.5">'
|
||||
'Pruefen Sie mit dem DSB die folgenden 4 Leitfragen aus EDPB 7/2020. '
|
||||
'Das Ergebnis bestimmt ob eine Art. 26-Vereinbarung (JC) oder ein '
|
||||
'Art. 28-AVV vorliegen muss.'
|
||||
'</p>'
|
||||
'<ol style="margin:0 0 0 18px;padding:0">'
|
||||
+ "".join(items) +
|
||||
'</ol>'
|
||||
'<p style="margin:8px 0 0;font-size:10px;color:#94a3b8;'
|
||||
'font-style:italic">Quelle: EDPB Guidelines 7/2020 (Controller/Processor) '
|
||||
'+ EuGH C-25/17, C-40/17.</p>'
|
||||
'</div>'
|
||||
)
|
||||
Reference in New Issue
Block a user