fix(cookie+impressum): Drittland-FP, Impressum-Beleg, neuer Opt-Out-Finding

- Drittland: unbekannte Herkunft ('N/A') + Self-Hosting feuern nicht mehr —
  First-Party-Session-Cookies (PHPSESSID/JSESSIONID) waren False Positives.
- Impressum _line_of: enges Fenster um den Treffer bei Texten ohne Umbrüche
  (BMW = ein Block) → jede Pflichtangabe zeigt IHREN Beleg statt denselben Satz.
- Neuer Finding-Typ missing_opt_out: einwilligungspflichtiger Anbieter mit
  Cookies ohne Opt-Out-/Widerspruchs-Link (Art. 7 Abs. 3 + Art. 21).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-06-11 11:59:48 +02:00
parent 5b36b3f367
commit 877d540ce1
5 changed files with 104 additions and 5 deletions
@@ -58,6 +58,38 @@ def test_third_country_and_eu_alternative_for_us_tracker():
assert "eu_alternative" in t
def test_session_cookie_unknown_country_no_third_country():
# PHPSESSID: rich-DB vendor_country 'N/A' → KEIN Drittland (war False Positive,
# weil 'N/A' nicht im EWR-Set steht). First-Party-Session-Cookie.
out = analyze_cookies([{
"name": "BMW AG — Infrastructure Basic", "category": "necessary",
"cookies": [{"name": "PHPSESSID", "purpose": "Session", "expiry": "Session"}],
}])
assert not [f for f in out["findings"] if f["type"] == "third_country"]
def test_missing_opt_out_for_marketing_vendor():
out = analyze_cookies([{
"name": "AdVendor", "category": "marketing", "opt_out_url": "",
"cookies": [{"name": "track1", "purpose": "ads", "expiry": "1 Jahr"}],
}])
mo = [f for f in out["findings"] if f["type"] == "missing_opt_out"]
assert len(mo) == 1
assert mo[0]["kind"] == "finding"
assert "Widerspruch" in mo[0]["remediation"] or "Opt-Out" in mo[0]["remediation"]
def test_no_missing_opt_out_when_url_present_or_necessary():
# Mit Opt-Out-URL → kein Finding; notwendige Kategorie → ebenfalls keins.
out = analyze_cookies([
{"name": "A", "category": "marketing", "opt_out_url": "https://x/opt",
"cookies": [{"name": "t", "purpose": "ads", "expiry": "1 Jahr"}]},
{"name": "B", "category": "necessary", "opt_out_url": "",
"cookies": [{"name": "sess", "purpose": "x", "expiry": "Session"}]},
])
assert not [f for f in out["findings"] if f["type"] == "missing_opt_out"]
def test_kind_splits_findings_from_hinweise():
# third_country/eu_alternative = Hinweis (advisory); Rest = Finding.
out = analyze_cookies([{