RELEASE-4 W4: acceptance-complete offline stealth probe plus informational detectors (G-D) - #45
RELEASE-4 W4: acceptance-complete offline stealth probe plus informational detectors (G-D)#45AminDhouib wants to merge 1 commit into
Conversation
…al detectors (G-D) plan_RELEASE W4. Lands the deterministic offline stealth-invariant gate plus the non-gating informational online tier, asserting the product's headline "undetectable" promise (G-D) that was previously asserted nowhere. - tests/fixture_app/stealth_probe.html: armed passive signal collector served by the ONE fixture mechanism (release_gate_harness.serve_fixture_app). Publishes a single closed-schema window.__STEALTH_PROBE_RESULT__ and one completion event; collects nothing until explicitly released. - tests/test_stealth.py: versioned predicate table; closed-schema validator with deterministic negative controls; per-collector-family sensitivity controls; the exact ordered CDP prerequisite transcript (Runtime.enable -> Page.enable -> Network.enable -> DOM.getDocument -> Runtime.evaluate(nonce) -> Page.captureScreenshot) driven via the project's own tab.send(uc.cdp.*) seam; process-flag evidence with W2's exact-binary identity; a redacted result artifact; and a real vanilla-control that must be detected. The vanilla control is the SAME product spawn path with the stealth arg-filter neutralized (the one intentional treatment) -- no second Chrome-launch path. - pyproject.toml: adds the `stealth` (gating) and `online` (non-gating) markers. Gate lane selects `-m "stealth and not online"`; unit lane `-m "not integration"` excludes the whole module. Zero src/ edits. One product predicate does not pass and is pinned honestly as a strict xfail (F-770): under headless the product UA still advertises "HeadlessChrome"; nodriver's default stealth does not mask it. An xfailed invariant does NOT satisfy the stealth release claim -- the headless UA vector remains detectable and is flagged for a fix owner. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
CI status: the stealth tier itself is green. The ubuntu integration job reports The single failure is inherited, not W4's: No action needed here: merging #44 before #45 (or rebasing #45 onto it) makes this green. Deliberately not cherry-picking the same fix onto both branches to avoid duplicate commits colliding at merge. |
…n (F-780) #43, #45 and #47 are red on the legacy `Browser Integration Tests (Chrome + Xvfb)` check while main and #42 are green on the same check. Read at face value that says FIX-B broke browser integration. It did not, and the reason is provable without reading a single CI log. test.yml runs `pytest -m integration --timeout=120`. The harness it drives declares INIT=60, LIST=130, SPAWN=120, WARMUP=150 with 4 attempts -- under a comment saying "the pytest --timeout is the outer net". Two of those single-step bounds are LARGER than the whole job's per-test budget, and BACKEND_READY_TIMEOUT is exactly equal to it. A 120s outer net cannot contain a 150s inner step. The job is structurally incapable of finishing that test; no timing luck is involved. It only started failing at FIX-B because W1 landed the transport journey already xfail'd (B1 was open), and an xfail costs nothing on the clock. FIX-B C2 correctly removed the marker once B1 was fixed, so from that commit the test actually runs -- and immediately hits the wall. The controlled comparison is #46: it contains FIX-B transitively, runs the SAME `-m integration` selection on the SAME OS under the release gate's 180s budget, and is green 23/23. Deliberately NOT fixed. W2 deletes this job, so patching a doomed file on three in-review branches is churn that also mutates PRs under human review. Recorded instead, because the trap is expensive: the merge queue will show red at #43 -> #45 -> #47 until W2 lands, and someone will otherwise go hunting for a regression that was never there. Not added to RELEASE_CONTRACT.md on purpose -- the contract describes what a user receives, not our merge plumbing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
RELEASE-4 (W4) — stacked on #43 (audit/release-fix-b), sibling of #44 (W2)
Closes the biggest honesty gap in the scorecard: the headline claim is undetectable browser automation and the repo had zero runtime stealth tests (only a launch-flag sanitizer).
Offline gating tier (
stealthmarker; gate lane-m "stealth and not online", the lane #44 wired): an armed passive collector (tests/fixture_app/stealth_probe.html) served by the ONE existing fixture mechanism, releasing its closed-schema result only after an exact ordered CDP prerequisite transcript (Runtime.enable → Page.enable → Network.enable → DOM.getDocument → Runtime.evaluate(nonce) → Page.captureScreenshot) driven through the project's owntab.send(uc.cdp.*)seam. A versioned signal table of 10 gating predicates coversnavigator.webdriver, CDP-leak globals, plugins, languages,window.chromemembers, Notification/permissions coherence, per-OS platform, UA client hints, patchedFunction.prototype.toString, and non-zero outer dimensions. Env-dependent signals (WebGL renderer) are collected informational only, never gated.Teeth, two ways: (1) a vanilla control — the same product
spawn_browserpath with the stealth arg-filter neutralized (the single intentional treatment, restored infinally) plus--enable-automation→navigator.webdriver === true, asserted detected; (2) per-collector deterministic controls feeding each predicate its forbidden observation. Also asserts live-process evidence: Chrome'scmdline[0]equals the exact resolved binary and carries no--enable-automation/--test-type.Non-gating online tier (
onlinemarker): CreepJS + bot.incolumitas, hard invariants only, skips on network error, excluded from every default run and the gate.Under headless — the posture the offline gate runs — the product's default User-Agent still advertises
HeadlessChrome. nodriver does not mask the UA token. Per plan_RELEASE's zero-src rule this is pinned as a strict xfail, not hidden by weakening the probe. Release-claim integrity: an xfailed invariant does not satisfy the stealth claim — the headless UA vector remains detectable and needs a fix owner (or an explicitly qualified claim) before G-D can be honestly asserted for the headless posture.Local evidence: offline lane 14 passed / 1 xfailed / 2 deselected (real headless Chrome; product passes all 10 gating predicates; vanilla control detected). Gate lane contains zero public URLs (the 2 deselected are exactly the online tests). Unit suite unchanged. ruff / ty (76 baseline) / vulture / budgets / suppression-owners clean. Zero
src/edits.Reviewer judgment call: the control routes through the product's own spawn path with the arg-filter neutralized, rather than a raw
nodriver.uc.start— chosen to honor "no second Chrome-launch path" while still producing a genuinely leaking browser. Easy to swap if you prefer the raw launch.Merge order: after #42 → #43. Independent of #44 (file-disjoint; both add the same
stealthmarker line). True merge commits, please.