From 05a1795ea839d8bc572d523be224d91468267c0e Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Thu, 11 Jun 2026 09:33:41 +0200 Subject: [PATCH] =?UTF-8?q?feat(cookie):=20=E2=91=A1=20Documentation=20Dri?= =?UTF-8?q?ft=20=E2=80=94=20Richtlinie=20vs.=20Browser-Realit=C3=A4t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cookie-Check-Endpoint liefert jetzt out["drift"] (audit_cookie_compliance): deklariert (Cookie-Richtlinie-Text) vs. tatsaechlich geladen (Browser). Frontend zeigt den Reality-Check-Strip oben im Panel: X dokumentiert · Y geladen · Z undokumentiert. Pinnt den Vertrag mit test_cookie_drift.py (undokumentiert-geladen + beide Drift-Richtungen) + Vitest Drift-Strip. Co-Authored-By: Claude Opus 4.7 --- .../agent/_components/CookieLibraryPanel.tsx | 22 +++++++++ .../__tests__/CookieLibraryPanel.test.tsx | 10 ++++ .../api/agent_compliance_check_routes.py | 12 +++++ .../compliance/tests/test_cookie_drift.py | 49 +++++++++++++++++++ 4 files changed, 93 insertions(+) create mode 100644 backend-compliance/compliance/tests/test_cookie_drift.py diff --git a/admin-compliance/app/sdk/agent/_components/CookieLibraryPanel.tsx b/admin-compliance/app/sdk/agent/_components/CookieLibraryPanel.tsx index ad5141a8..c939588c 100644 --- a/admin-compliance/app/sdk/agent/_components/CookieLibraryPanel.tsx +++ b/admin-compliance/app/sdk/agent/_components/CookieLibraryPanel.tsx @@ -28,6 +28,12 @@ interface CheckData { real_cookies?: number other_storage?: number } + drift?: { + declared_count?: number + browser_count?: number + high_findings?: number + low_findings?: number + } } const SEV_COLOR: Record = { @@ -55,8 +61,24 @@ export function CookieFindingList({ data }: { data: CheckData }) { const findings = data.findings || [] const s = data.summary || {} const inv = data.storage_inventory + const drift = data.drift + const driftShown = + !!drift && ((drift.declared_count ?? 0) + (drift.browser_count ?? 0)) > 0 return (
+ {driftShown && ( +
+ Richtlinie ↔ Realität:{' '} + {drift!.declared_count ?? 0} in der Cookie-Richtlinie + dokumentiert · {drift!.browser_count ?? 0} im Browser geladen + {(drift!.high_findings ?? 0) > 0 && ( + <> · {drift!.high_findings} undokumentiert geladen + )} + {(drift!.low_findings ?? 0) > 0 && ( + <> · {drift!.low_findings} dokumentiert, aber nicht geladen + )} +
+ )} {inv && (inv.total ?? 0) > 0 && (
Storage-Inventar:{' '} diff --git a/admin-compliance/app/sdk/agent/_components/__tests__/CookieLibraryPanel.test.tsx b/admin-compliance/app/sdk/agent/_components/__tests__/CookieLibraryPanel.test.tsx index c0a46559..9e05ec19 100644 --- a/admin-compliance/app/sdk/agent/_components/__tests__/CookieLibraryPanel.test.tsx +++ b/admin-compliance/app/sdk/agent/_components/__tests__/CookieLibraryPanel.test.tsx @@ -27,6 +27,16 @@ describe('CookieFindingList', () => { expect(screen.getByText(/Keine Abweichungen/)).toBeInTheDocument() }) + it('zeigt den Drift-Strip (Richtlinie vs. Browser-Realität)', () => { + render() + expect(screen.getByText(/Richtlinie ↔ Realität/)).toBeInTheDocument() + expect(screen.getByText(/31 undokumentiert geladen/)).toBeInTheDocument() + }) + it('zeigt das Storage-Inventar (echte Cookies vs. andere)', () => { render( dict: + return {"phases": {"after_accept": { + "cookies": [{"name": n} for n in cookie_names]}}} + + +def test_undeclared_browser_cookies_are_high_drift(): + # BMW-Fall: Richtlinie nennt nichts, Browser lädt Tracker → undokumentiert. + audit = audit_cookie_compliance(None, None, _banner("_ga", "_fbp")) + assert audit["declared_count"] == 0 + assert audit["browser_count"] == 2 + assert audit["high_findings"] == 2 + assert set(audit["undeclared_in_browser"]) == {"_ga", "_fbp"} + assert audit["low_findings"] == 0 + + +def test_empty_inputs_yield_zero_drift(): + audit = audit_cookie_compliance(None, None, None) + for k in ("declared_count", "browser_count", "high_findings", "low_findings"): + assert audit[k] == 0 + + +def test_drift_both_directions(): + # Richtlinie deklariert 3 Cookies (Tab-Tabelle), Browser lädt 2 davon + 1 neuen. + doc = ( + "Name\tKategorie\tZweck\tSpeicherdauer\n" + "_ga\tAnalytics\tBesucher unterscheiden\t2 Jahre\n" + "_gid\tAnalytics\tBesucher unterscheiden\t1 Tag\n" + "consent\tNotwendig\tEinwilligung speichern\t1 Jahr\n" + ) + audit = audit_cookie_compliance(None, doc, _banner("_ga", "_gid", "_fbp")) + # _fbp ist geladen aber nicht deklariert → HIGH-Drift. + assert "_fbp" in audit["undeclared_in_browser"] + assert audit["high_findings"] >= 1 + # consent ist deklariert aber nicht geladen → LOW-Drift. + assert "consent" in audit["declared_not_loaded"] + assert audit["low_findings"] >= 1