From 901de1ca9722979551238502236b511fd56339db Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Thu, 11 Jun 2026 08:44:19 +0200 Subject: [PATCH] =?UTF-8?q?feat(cookie):=20A=20=E2=80=94=20Findings=20audi?= =?UTF-8?q?tfest=20an=20Controls=20verdrahten?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Jeder Cookie-Befund traegt jetzt ein strukturiertes control-Feld (control_id aus doc_check_controls + regulation + article) statt nur hardcodeter Strings: vague_duration->AUTH-2051-A03 (Art.5(1)e+13), tracker_as_necessary->DATA-2851-A05 (§25 TDDDG), third_country-> DATA-1624-A04 (Art.44). Kette Regulation->Article->Control->Finding. Frontend zeigt die Rechtsgrundlage je Befund. (Controls tragen regulation/article noch NULL -> hier mitgeliefert bis gepflegt.) Co-Authored-By: Claude Opus 4.7 --- .../sdk/agent/_components/CookieLibraryPanel.tsx | 7 +++++++ .../compliance/services/cookie_library_check.py | 16 ++++++++++++++++ .../tests/test_cookie_library_check.py | 15 +++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/admin-compliance/app/sdk/agent/_components/CookieLibraryPanel.tsx b/admin-compliance/app/sdk/agent/_components/CookieLibraryPanel.tsx index 2848a22c..b6b4c37b 100644 --- a/admin-compliance/app/sdk/agent/_components/CookieLibraryPanel.tsx +++ b/admin-compliance/app/sdk/agent/_components/CookieLibraryPanel.tsx @@ -16,6 +16,7 @@ export interface CookieFinding { declared: string library_purpose: string remediation: string + control?: { control_id?: string | null; regulation?: string; article?: string } } interface CheckData { @@ -71,6 +72,12 @@ export function CookieFindingList({ data }: { data: CheckData }) {
Library-Zweck: {f.library_purpose}
)}
{f.remediation}
+ {f.control?.regulation && f.control.regulation !== '—' && ( +
+ Rechtsgrundlage: {f.control.regulation} {f.control.article} + {f.control.control_id && ` · Control ${f.control.control_id}`} +
+ )} ))} diff --git a/backend-compliance/compliance/services/cookie_library_check.py b/backend-compliance/compliance/services/cookie_library_check.py index 89842fe0..38566b86 100644 --- a/backend-compliance/compliance/services/cookie_library_check.py +++ b/backend-compliance/compliance/services/cookie_library_check.py @@ -22,6 +22,19 @@ from compliance.services.cookie_knowledge_db import lookup_cookie _TRACKER_CATS = {"marketing", "statistics", "social_media", "targeting"} +# A — auditfeste Verdrahtung: jeder Befund-Typ → echter Control (control_id aus +# doc_check_controls) + legal_basis. Die Controls tragen regulation/article noch +# NULL, daher liefern wir die Rechtsgrundlage hier strukturiert mit (bis sie in +# den Controls gepflegt ist). Kette: Regulation → Article → Control → Finding. +_CONTROL_MAP = { + "vague_duration": {"control_id": "AUTH-2051-A03", "regulation": "DSGVO", "article": "Art. 5 Abs. 1 lit. e + Art. 13"}, + "excessive_lifetime": {"control_id": "AUTH-2051-A02", "regulation": "DSGVO", "article": "Art. 5 Abs. 1 lit. e"}, + "tracker_as_necessary": {"control_id": "DATA-2851-A05", "regulation": "TDDDG", "article": "§ 25 Abs. 1"}, + "missing_purpose": {"control_id": "AUTH-2053-A05", "regulation": "DSGVO", "article": "Art. 13"}, + "third_country": {"control_id": "DATA-1624-A04", "regulation": "DSGVO", "article": "Art. 44 ff."}, + "eu_alternative": {"control_id": None, "regulation": "—", "article": "kommerzielle Empfehlung"}, +} + def load_big_library(db, names: list[str]) -> dict: """Batch-Lookup der grossen Open-Cookie-Database (compliance.cookie_library, @@ -219,6 +232,9 @@ def analyze_cookies(vendors: list[dict], big_lib: dict | None = None) -> dict: ), }) + # A: jeden Befund an seinen Control + Rechtsgrundlage haengen (auditfest). + for f in findings: + f["control"] = _CONTROL_MAP.get(f["type"], {}) findings.sort(key=lambda f: _SEV_ORDER.get(f["severity"], 3)) return { "summary": { diff --git a/backend-compliance/compliance/tests/test_cookie_library_check.py b/backend-compliance/compliance/tests/test_cookie_library_check.py index da585dbc..2067154b 100644 --- a/backend-compliance/compliance/tests/test_cookie_library_check.py +++ b/backend-compliance/compliance/tests/test_cookie_library_check.py @@ -79,6 +79,21 @@ def test_excessive_lifetime(): assert el and "Art. 5" in el[0]["remediation"] +def test_findings_carry_control_and_legal_basis(): + # A: jeder Befund traegt control_id + Rechtsgrundlage (auditfest). + out = analyze_cookies([{ + "name": "Google", "category": "necessary", + "cookies": [{"name": "_ga", "purpose": "x", + "expiry": "Wird solange gespeichert, bis es deaktiviert wird."}], + }]) + assert out["findings"], "es sollte Befunde geben" + for f in out["findings"]: + assert "control" in f + vd = next(f for f in out["findings"] if f["type"] == "vague_duration") + assert vd["control"]["control_id"] == "AUTH-2051-A03" + assert "Art. 5" in vd["control"]["article"] + + def test_vague_duration_flagged_concrete_ok(): # User-Beispiel Salesforce: "bis der Nutzer es deaktiviert" = vage. out = analyze_cookies([{