feat(browser-matrix): Cross-Browser-Befunde + Browser-Default-Einordnung (Phase 4)

- browser_cross_finding: deterministische Sicht ueber die Matrix (keine 2.
  Engine, kein LLM). Findet Inkonsistenzen ZWISCHEN Browsern (Cookies vor
  Consent / Ablehnen nicht universell respektiert / Banner-Links fehlend) und
  ordnet ein: Safari-ITP / Brave-Shields / Firefox-ETP maskieren Verstoesse
  clientseitig → strenge Engine "sauber" ist KEIN Compliance-Beleg, massgeblich
  sind die nachgiebigen (Chrome/Edge). Coverage-Hinweis fuer nicht verfuegbare
  Browser. Je Befund Titel/Detail/Severity/affected/Massnahme.
- snapshot_check_routes: cross_findings frisch in run + GET (nicht persistiert).
- BrowserBehaviorView: "Cross-Browser-Befunde"-Block ueber der Tabelle.
- Tests: test_browser_cross_finding (6).

Offen (Folge-Task): Borlabs-Consent-Historie-Live-Erkennung (braucht
consent-tester-Storage-Scan).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-06-12 23:22:57 +02:00
parent 9587726936
commit 85a8a1d545
4 changed files with 277 additions and 2 deletions
@@ -191,6 +191,10 @@ async def snapshot_browser_behavior_run(
status_code=502,
detail=f"consent-tester /scan-matrix fehlgeschlagen: {e}")
update_browser_matrix(db, snapshot_id, matrix)
# Cross-Browser-Befunde frisch ableiten (deterministische Sicht, nicht
# persistiert → GET berechnet identisch neu).
from compliance.services.browser_cross_finding import build_cross_findings
matrix["cross_findings"] = build_cross_findings(matrix)
return matrix
finally:
db.close()
@@ -202,8 +206,12 @@ async def snapshot_browser_behavior(snapshot_id: str):
ist null, solange der On-demand-Lauf noch nie ausgelöst wurde."""
from database import SessionLocal
from compliance.services.check_snapshot import load_browser_matrix
from compliance.services.browser_cross_finding import build_cross_findings
db = SessionLocal()
try:
return {"browser_matrix": load_browser_matrix(db, snapshot_id)}
matrix = load_browser_matrix(db, snapshot_id)
if matrix:
matrix["cross_findings"] = build_cross_findings(matrix)
return {"browser_matrix": matrix}
finally:
db.close()