""" Consent Tester Service — Playwright-based 3-phase cookie consent test. Tests what scripts/cookies load BEFORE consent, AFTER rejection, and AFTER acceptance. Runs as independent microservice on port 8094. """ import logging from datetime import datetime, timezone from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel from services.consent_scanner import run_consent_test, ConsentTestResult logging.basicConfig(level=logging.INFO, format="%(levelname)s:%(name)s: %(message)s") logger = logging.getLogger(__name__) app = FastAPI(title="BreakPilot Consent Tester", version="1.0.0") app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"], ) class ScanRequest(BaseModel): url: str timeout_per_phase: int = 10 # seconds to wait after page load class ScanResponse(BaseModel): url: str banner_detected: bool banner_provider: str phases: dict summary: dict scanned_at: str @app.get("/health") async def health(): return {"status": "healthy", "service": "consent-tester"} @app.post("/scan", response_model=ScanResponse) async def scan_consent(req: ScanRequest): """Run 3-phase consent test on a URL.""" logger.info("Starting consent test for %s", req.url) result = await run_consent_test(req.url, req.timeout_per_phase) return ScanResponse( url=req.url, banner_detected=result.banner_detected, banner_provider=result.banner_provider, phases={ "before_consent": { "scripts": result.before_scripts, "cookies": result.before_cookies, "tracking_services": result.before_tracking, "violations": [v.__dict__ for v in result.before_violations], }, "after_reject": { "scripts": result.reject_scripts, "cookies": result.reject_cookies, "new_tracking": result.reject_new_tracking, "violations": [v.__dict__ for v in result.reject_violations], }, "after_accept": { "scripts": result.accept_scripts, "cookies": result.accept_cookies, "new_tracking": result.accept_new_tracking, "undocumented": result.accept_undocumented, }, }, summary={ "critical": sum(1 for v in result.reject_violations if v.severity == "CRITICAL"), "high": len(result.before_violations), "undocumented": len(result.accept_undocumented), "total_violations": len(result.before_violations) + len(result.reject_violations), }, scanned_at=datetime.now(timezone.utc).isoformat(), )