feat(consent-tester): /scan-matrix echt — Profil je Engine + Per-Engine-Summary (Phase 1.2)

- _scanner_run reicht browser_profile an run_consent_test durch (statt Single-Chromium-Shim)
- neue scan_matrix_summary.matrix_scan_dict: ConsentTestResult -> schlanke
  Matrix-dict-Form (phases fuer _extract_dimensions + kompakter `summary`:
  cookies_before_consent/after_reject, reject_respected-Heuristik [keine
  Verstoesse UND kein neuer Tracker], surface, screenshot)
- multi_browser_scanner._run_one hebt summary + engine + is_mobile an die
  Zeile, verwirft die vollen Cookie-Listen (JSONB-Persistenz schlank)
- consent_scanner: _ctx_base mit Mobile-Device-Emulation (iPhone-Profil ->
  echtes Mobile-Viewport/Touch), alle 5 new_context auf **_ctx_base
- Tests: test_scan_matrix_summary (6) inkl. _extract_dimensions-Vertrag

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-06-12 22:46:42 +02:00
parent c816827720
commit 881e9c28de
5 changed files with 208 additions and 44 deletions
+17 -12
View File
@@ -5,11 +5,9 @@ returns the aggregated robustness-score per browser plus a
worst-of/best-of summary. Kept in its own module so main.py stays
under the 500-LOC cap.
KNOWN LIMITATION (stage 1.a):
The underlying `run_consent_test` does not yet accept a
`browser_profile` kwarg — all profiles currently execute on the
same Chromium instance. Engine diversity (real Firefox/WebKit
contexts) ships in stage 1.b once consent_scanner is split.
Stage 1.b (erledigt): `run_consent_test` nimmt jetzt einen `browser_profile`
kwarg → echte Engine-Diversität (Firefox/Gecko, WebKit/Safari, Blink inkl.
Chrome-/Edge-Channel + Brave). `_scanner_run` reicht das Profil durch.
"""
from __future__ import annotations
@@ -22,6 +20,7 @@ from pydantic import BaseModel
from services.consent_scanner import run_consent_test
from services.multi_browser_scanner import run_matrix
from services.scan_matrix_summary import matrix_scan_dict
logger = logging.getLogger(__name__)
router = APIRouter()
@@ -36,12 +35,18 @@ class MatrixScanRequest(BaseModel):
browser_profiles: list[str] | None = None
async def _scanner_shim(url: str, browser_profile: dict | None = None,
timeout_per_phase: int = 10,
categories: list[str] | None = None):
"""Shim that ignores `browser_profile` until consent_scanner accepts it."""
return await run_consent_test(url, timeout_per_phase,
categories or [])
async def _scanner_run(url: str, browser_profile: dict | None = None,
timeout_per_phase: int = 10,
categories: list[str] | None = None):
"""Adapter: reicht das aufgelöste `browser_profile` (Engine/Channel/Device)
an `run_consent_test` durch, damit jede Matrix-Zeile auf der echten Engine
läuft (Firefox/WebKit/Blink + Chrome-/Edge-Channel + Brave). Projiziert
das ConsentTestResult auf die schlanke Matrix-dict-Form (phases +
kompakter `summary`)."""
result = await run_consent_test(url, timeout_per_phase,
categories or [],
browser_profile=browser_profile)
return matrix_scan_dict(result)
@router.post("/scan-matrix")
@@ -50,7 +55,7 @@ async def scan_matrix(req: MatrixScanRequest):
logger.info("Matrix scan for %s profiles=%s", req.url,
req.browser_profiles or "default")
matrix = await run_matrix(
_scanner_shim,
_scanner_run,
req.url,
requested_profiles=req.browser_profiles,
timeout_per_phase=req.timeout_per_phase,