fix: Banner checks no longer default to PASS when untested
20 checks were defaulting to PASS when no violation was found, even if the scanner couldn't actually test them. Now: - Phase-based checks (tracking/cookies): absence = PASS (correct) - UI checks: only PASS if banner_checks actually ran - If banner not detected: everything except banner_detected = FAIL This prevents false 100% scores when violations exist but the text→code mapping doesn't cover them. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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 in violations → failed
|
||||||
# For checks whose check_key appears only in passes → passed
|
# 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:
|
if is_violation_key:
|
||||||
passed = False
|
passed = False
|
||||||
matched_text = violation_codes[key]
|
matched_text = violation_codes[key]
|
||||||
@@ -46,12 +49,20 @@ def map_scan_to_checks(scan_result: dict) -> dict:
|
|||||||
passed = True
|
passed = True
|
||||||
matched_text = pass_codes.get(key, "")
|
matched_text = pass_codes.get(key, "")
|
||||||
else:
|
else:
|
||||||
# Key not found in violations or explicit passes.
|
banner_detected = scan_result.get("banner_detected", False)
|
||||||
# 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"
|
|
||||||
if key == "banner_detected":
|
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 = ""
|
matched_text = ""
|
||||||
|
|
||||||
# L2 checks are skipped if their parent L1 failed
|
# L2 checks are skipped if their parent L1 failed
|
||||||
@@ -213,6 +224,17 @@ def _collect_pass_codes(scan: dict) -> dict[str, str]:
|
|||||||
return passes
|
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 = (
|
_TRACKING_COOKIE_PREFIXES = (
|
||||||
"_ga", "_gid", "_fbp", "_fbc", "IDE", "_gcl", "fr", "_pin",
|
"_ga", "_gid", "_fbp", "_fbc", "IDE", "_gcl", "fr", "_pin",
|
||||||
"_tt_", "li_sugr", "_hj", "mp_", "ajs_", "_clck", "_clsk",
|
"_tt_", "li_sugr", "_hj", "mp_", "ajs_", "_clck", "_clsk",
|
||||||
|
|||||||
Reference in New Issue
Block a user