Files
breakpilot-compliance/backend-compliance/tests/test_specialist_cookie_policy.py
T
Benjamin Admin f4357a2e9b feat(agents): Specialist-Agents Phase 2 Foundation + Cookie-Policy-Agent
Sprint 1 — Foundation (User-Vorgabe 2026-06-08):

Foundation:
- _base.py: BaseSpecialistAgent ABC + Pydantic Contract
  (AgentInput/AgentOutput/Finding/Recommendation/McCoverage/EscalationLog).
- _base.lint_output(): Disclaimer-Linter verbietet "rechtssicher" /
  "garantiert" / "gesetzeskonform" — scrubbed inline + Log in notes.
- _registry.py: AgentRegistry mit MC-Owner-Mapping (verhindert
  Doppel-Ownership).
- _escalation.py: cascade(local → ovh). qwen2.5:7b default,
  OVH 120b als Stage-2 (deaktiviert wenn OVH_URL leer).
- _rollup.py: deterministisches Dedup ähnlicher actions zu
  Recommendations mit related_finding_ids[].
- _evidence_vault.py: Pro-Run File-Vault für Playwright-Videos,
  Screenshots, CSV. SHA256 + manifest.json. DSR-tauglich (delete_run).

Agenten:
- ImpressumAgent v2 (impressum/agent.py + mcs.py) — konsolidiert
  v1-Pattern-Match + v2-LLM-MVP unter dem neuen Contract. 12 MCs.
- CookiePolicyAgent v1 (cookie_policy/agent.py + mcs.py) — 12 MCs
  zu Cookie-Richtlinie-Vollständigkeit + KB-Layer für
  CMP-Vendor-Cross-Check.

Tests: 25/25 grün (10 Impressum + 9 Vault + 6 Cookie-Policy).

Roadmap: SSE-Test-Endpoint + Frontend-Tab → DSE/AGB-Agents →
Cookie-Banner-Themen-Agent → Cross-Doc-Konsistenz-Agent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-08 17:40:05 +02:00

144 lines
4.3 KiB
Python

"""Tests für Cookie-Policy-Agent."""
from __future__ import annotations
import asyncio
import pytest
from compliance.services.specialist_agents import (
REGISTRY,
AgentInput,
CookiePolicyAgent,
Severity,
)
FULL_POLICY = """Cookie-Richtlinie
Stand: 1. Juni 2026
Wir verwenden auf unserer Website verschiedene Cookies. Diese werden
in folgende Kategorien eingeteilt:
1. Essentielle Cookies (unbedingt erforderlich)
Zweck: Diese Cookies dienen der grundlegenden Funktion der Website.
Rechtsgrundlage: § 25 Abs. 2 TDDDG
Laufzeit: Session
2. Funktionale Cookies
Zweck: Speichern Ihre Präferenzen wie Sprache und Region.
Rechtsgrundlage: Art. 6 Abs. 1 lit. a DSGVO
Laufzeit: 30 Tage
3. Analytics-Cookies (Performance)
Drittanbieter: Google LLC, USA
Zweck: Nutzungsstatistiken erheben.
Laufzeit: 24 Monate
Cookies: _ga, _gid
Drittland: USA — Standardvertragsklauseln + Data Privacy Framework
4. Marketing-Cookies (Tracking)
Drittanbieter: Meta Platforms Inc., USA
Cookies: _fbp, _fbc
Laufzeit: 90 Tage
Sie können Ihre Cookie-Einstellungen jederzeit ändern über den Link
unten oder das Banner erneut öffnen.
Browser-Einstellungen: Auch in Chrome, Firefox, Safari und Edge
können Sie Cookies blockieren oder löschen.
Kontakt: datenschutz@example.com
Datenschutzbeauftragter: Max Mustermann
"""
GAPPY_POLICY = """Cookies
Wir verwenden Cookies um die Website zu betreiben.
Cookies werden so lange gespeichert wie nötig.
"""
def _run(coro):
return asyncio.get_event_loop().run_until_complete(coro)
def test_agent_is_registered():
agent = REGISTRY.get("cookie_policy")
assert agent is not None
assert agent.doc_type == "cookie"
def test_short_text_skipped(monkeypatch):
async def _no_cascade(*a, **kw): return None, []
monkeypatch.setattr(
"compliance.services.specialist_agents.cookie_policy.agent.cascade",
_no_cascade,
)
agent = CookiePolicyAgent()
out = _run(agent.evaluate(AgentInput(doc_type="cookie", text="x")))
assert out.mc_total > 0
assert all(c.status == "skipped" for c in out.mc_coverage)
def test_full_policy_has_few_high_findings(monkeypatch):
async def _no_cascade(*a, **kw): return None, []
monkeypatch.setattr(
"compliance.services.specialist_agents.cookie_policy.agent.cascade",
_no_cascade,
)
agent = CookiePolicyAgent()
out = _run(agent.evaluate(AgentInput(doc_type="cookie", text=FULL_POLICY)))
high = [f for f in out.findings if f.severity == Severity.HIGH.value]
assert not high, f"unexpected HIGH findings: {[f.field_id for f in high]}"
def test_gappy_policy_triggers_high(monkeypatch):
async def _no_cascade(*a, **kw): return None, []
monkeypatch.setattr(
"compliance.services.specialist_agents.cookie_policy.agent.cascade",
_no_cascade,
)
agent = CookiePolicyAgent()
out = _run(agent.evaluate(AgentInput(doc_type="cookie",
text=GAPPY_POLICY)))
field_ids = {f.field_id for f in out.findings}
# 4 Kategorien fehlen, Vendoren fehlen, Opt-Out fehlt, Tabelle fehlt
assert "categories_named" in field_ids
assert "vendor_recipients" in field_ids
assert "opt_out_mechanism" in field_ids
def test_cmp_vendor_cross_check_emits_finding(monkeypatch):
async def _no_cascade(*a, **kw): return None, []
monkeypatch.setattr(
"compliance.services.specialist_agents.cookie_policy.agent.cascade",
_no_cascade,
)
agent = CookiePolicyAgent()
out = _run(agent.evaluate(AgentInput(
doc_type="cookie", text=FULL_POLICY,
context={"cmp_vendors": [
{"name": "Hotjar"}, # NICHT in Policy
{"name": "Google LLC"}, # IN Policy
]},
)))
field_ids = {f.field_id for f in out.findings}
assert "vendor_consistency" in field_ids
cmp_f = next(f for f in out.findings
if f.field_id == "vendor_consistency")
assert "Hotjar" in cmp_f.evidence
assert "Google" not in cmp_f.evidence
def test_recommendations_are_built():
agent = CookiePolicyAgent()
out = _run(agent.evaluate(AgentInput(doc_type="cookie",
text=GAPPY_POLICY)))
assert out.recommendations
# Jede Recommendation hat mind. ein related_finding
for r in out.recommendations:
assert r.related_finding_ids