diff --git a/consent-tester/checks/banner_runner.py b/consent-tester/checks/banner_runner.py index 8166f03..0336120 100644 --- a/consent-tester/checks/banner_runner.py +++ b/consent-tester/checks/banner_runner.py @@ -38,7 +38,10 @@ def map_scan_to_checks(scan_result: dict) -> dict: # For checks whose check_key appears in violations → failed # For checks whose check_key appears only in passes → passed - # For checks where neither → assume passed (not tested = no finding) + # For checks where neither: + # - Phase-based checks (tracking/cookies) → PASS (absence = good) + # - Banner UI checks → PASS only if banner was detected and + # the scanner actually ran the relevant check if is_violation_key: passed = False matched_text = violation_codes[key] @@ -46,12 +49,20 @@ def map_scan_to_checks(scan_result: dict) -> dict: passed = True matched_text = pass_codes.get(key, "") else: - # Key not found in violations or explicit passes. - # If the scan ran (banner detected) → assume passed. - # If banner not detected → only banner_detected fails. - passed = scan_result.get("banner_detected", False) or key == "banner_detected" + banner_detected = scan_result.get("banner_detected", False) if key == "banner_detected": - passed = scan_result.get("banner_detected", False) + passed = banner_detected + elif key in _ABSENCE_IS_PASS: + # For these checks, no violation = passed (e.g. no tracking cookies) + passed = True + elif banner_detected: + # Banner was detected but this specific check produced no result. + # If the scanner ran banner_checks → assume checked and passed. + # If banner_checks is empty → scanner couldn't test → not passed. + has_banner_results = bool(scan_result.get("banner_checks", {}).get("violations") is not None) + passed = has_banner_results + else: + passed = False matched_text = "" # L2 checks are skipped if their parent L1 failed @@ -213,6 +224,17 @@ def _collect_pass_codes(scan: dict) -> dict[str, str]: return passes +# Checks where absence of a violation means PASS (not "untested") +# These are phase-based checks: if no tracking was detected, that's good. +_ABSENCE_IS_PASS = { + "tracking_before_consent", + "cookies_before_consent", + "tracking_after_reject", + "google_consent_mode_defaults", + "banner_language_mismatch", + "cookie_wall", +} + _TRACKING_COOKIE_PREFIXES = ( "_ga", "_gid", "_fbp", "_fbc", "IDE", "_gcl", "fr", "_pin", "_tt_", "li_sugr", "_hj", "mp_", "ajs_", "_clck", "_clsk",