diff --git a/scripts/ci_drive_gate.py b/scripts/ci_drive_gate.py index f84f3df..9885b0f 100644 --- a/scripts/ci_drive_gate.py +++ b/scripts/ci_drive_gate.py @@ -10,17 +10,28 @@ It deliberately covers the failure modes that HISTORICALLY shipped green: - juggler missing entirely → TargetClosedError on launch (firefox-8) - mouse/keyboard input broken → click/move/type assertions (firefox-2 #9: jugglerSendMouseEvent / synthesizeMouseEvent) - - cross-origin iframe broken → content_frame() reachable (issue #20) - canvas non-deterministic → identical draw → identical dataURL (stealth seed must be per-session, not per-readback) - headless navigator tells → navigator.webdriver falsy, languages non-empty, plugins is a real PluginArray All of this is headless, NO screenshot → GPU-free (can't false-fail on the -GPU-less hosted runners), and fully offline — data: URLs only, NO network, NO -proxy, NO secrets → safe in public CI. WebGL determinism is intentionally NOT -checked here (it needs SWGL and can false-fail headless); it lives in the local -proxy realness gate, alongside the fingerprint/WebRTC-vs-vanilla checks. +GPU-less hosted runners), and fully offline → safe in public CI. WebGL +determinism is intentionally NOT checked here (it needs SWGL and can false-fail +headless); it lives in the local proxy realness gate. + +NOT covered here on purpose: + - Cross-origin iframe (issue #20): a same-origin srcdoc/data iframe is a weak + proxy for it AND races Juggler's frame tracking (the frame re-navigates, its + id changes → "Frame was detached" ~1-in-8). The faithful #20 sentinel is + `tests/test_cross_origin_iframe.py` (e2e, two localhost origins); wire that + as its own gate job rather than a fragile in-gate check. + +Robustness (learned the hard way): the page is a SIMPLE +`goto("data:text/html,...")` with NO subframe. `set_content` throws "The +operation is insecure" on this build (its document.write is rejected), and a +nested `data:`/srcdoc iframe races the evaluates → intermittent "execution +context destroyed by navigation" / "Frame was detached". Usage: python ci_drive_gate.py /path/to/firefox[.exe | .app/Contents/MacOS/firefox] Exit 0 + "DRIVE GATE OK ..." on success; non-zero with a reason on failure. @@ -31,18 +42,13 @@ import sys from playwright.sync_api import sync_playwright -# Single offline page that wires up every probe: a clickable button, a text -# input, a same-document iframe, and a mousemove counter. data: URLs execute -# inline scripts and are same-origin, so this needs no server. +# Simple, subframe-free data: URL — proven stable across runners. PAGE = ( "data:text/html," "