#!/usr/bin/env python3 """CI drive gate — the firefox-8 catcher. A raw `firefox --screenshot` proves nothing about automation: a juggler-less binary renders a screenshot just fine and ships broken (firefox-8 did exactly that). This DRIVES the binary the way users will — Playwright launches it over the juggler pipe, loads a real page, and round-trips JS. A binary with a missing/broken juggler throws TargetClosedError here and the gate fails. Headless, NO screenshot → GPU-free, so it can't false-fail on GPU-less hosted runners. Zero proxy / zero secrets → safe in public CI. (The proxy realness gate — fppro/webrtc — stays local, it needs secrets.) 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. """ from __future__ import annotations import sys from playwright.sync_api import sync_playwright def main(exe: str) -> int: with sync_playwright() as p: browser = p.firefox.launch(executable_path=exe, headless=True) page = browser.new_page() # data: URL → real HTML parse + DOM + JS, fully offline (no network/proxy). page.goto("data:text/html,