From 10c73a1a33d248180d6df8c0ff746190fba7813b Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Fri, 22 May 2026 19:17:21 +0200 Subject: [PATCH] fix(cookies): parse_flat_cookie_text whitespace-tolerant fuer HTTP-fetch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bisheriges _FLAT_ROW_RE erwartete textContent-Output (Cookie-Tabelle konkateniert ohne Whitespace zwischen Zellen). Bei VW lieferte das deterministische 10 Vendors / 35 Cookies, aber nur weil der DSE-Text- Fallback unvollstaendige Tabellen-Fragmente enthielt. Beim echten cookie-richtlinie.html Fetch (8086 Worte HTML→text) sind die Spalten durch Whitespace getrennt — und der Regex hat 0 gematcht. Fix: \s* zwischen jedem Anker und dem Cookie-Namen erlaubt. Direct-Test auf VW: 0 → 60 Cookies / 16 Vendors (Google 13, Adobe-Familie 16, Meta, Salesforce, Cloudflare, Akamai etc.). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../services/cookies_table_parser.py | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/backend-compliance/compliance/services/cookies_table_parser.py b/backend-compliance/compliance/services/cookies_table_parser.py index 0ce67068..1ac3da98 100644 --- a/backend-compliance/compliance/services/cookies_table_parser.py +++ b/backend-compliance/compliance/services/cookies_table_parser.py @@ -307,12 +307,20 @@ def parse_cookie_table(text: str) -> list[dict]: # - Danach: Kategorie-Token (Tracking Cookies, Funktionscookie, ...) # Dazwischen: der Cookie-Name (3-50 Zeichen, alphanum/underscore/dash). _FLAT_ROW_RE = re.compile( - r"(?:Permanent/Protokoll|Session Cookie|Persistent Cookie|" - r"TagePersistent|TageSitzungs-Cookie|TageSession Cookie|" - r"MinutenPersistent|MinutenSession Cookie|StundenPersistent|" - r"MonatePersistent|JahrePersistent)" - r"([A-Za-z_][A-Za-z0-9_\-\.]{1,40}?)" - r"(?=Tracking Cookies|Session Cookies|Funktionscookie|Funktional|" + # VW + andere flat-text Cookie-Tabellen: + # Layout: [NAME] [KATEGORIE] [ZWECK ...lang] [DAUER] [ART] + # Anchor 1 (davor): Cookie-Art-Token aus vorheriger Row + # Name dazwischen: 3-40 Zeichen alphanum/underscore/dash + # Anchor 2 (danach): Kategorie-Token der aktuellen Row + # Whitespace zwischen den Tokens ist OPTIONAL (textContent vs body.text). + r"(?:Permanent/Protokoll|Session\s*Cookie|Persistent\s*Cookie|" + r"Tage\s*Persistent|Tage\s*Sitzungs-Cookie|Tage\s*Session\s*Cookie|" + r"Minuten\s*Persistent|Minuten\s*Session\s*Cookie|Stunden\s*Persistent|" + r"Monate\s*Persistent|Jahre\s*Persistent)" + r"\s*" # P-fix: optionales Whitespace nach Art-Token (HTML-fetch hat es, textContent nicht) + r"([A-Za-z_][A-Za-z0-9_\-\.]{2,40}?)" + r"\s*" # P-fix: optionales Whitespace vor Kategorie-Anchor + r"(?=Tracking\s*Cookies?|Session\s*Cookies?|Funktionscookie|Funktional|" r"Marketing|Analytics|Necessary)", re.I, )