feat(stealth): engine owns all anti-detect stealth#2
Merged
Conversation
A raw 0xB1 (latin-1 '±') byte in a generated docstring made mithwire/cdp/network.py invalid UTF-8 with no encoding declaration, so a clean-source 'import mithwire' failed (it only worked off cached bytecode). Re-encode the byte as proper UTF-8. Co-authored-by: Cursor <cursoragent@cursor.com>
Move the anti-detect implementation out of the mithwire-mcp client and into
the engine, which now owns every browser-altering capability. Any client (the
MCP server, or a custom script) gets identical stealth by describing the
identity it wants; it never reimplements patching.
- add mithwire/stealth/ package:
- FingerprintConfig: declarative identity (moved verbatim from the MCP)
- Stealth: applies fingerprint, headless UA cleanup, WebRTC leak protection,
the new-document shim, and the timezone override over CDP/JS
- compute_launch_args: stealth launch flags (--lang,
--force-webrtc-ip-handling-policy, headless window size)
- Config accepts fingerprint + webrtc_leak_protection and injects the launch
flags; proxy presence is inferred from --proxy-server (engine stays agnostic
of any client's proxy abstraction)
- Browser.start() applies stealth post-launch and exposes browser.stealth for
client re-application (e.g. once a proxy egress geo is resolved)
- start()/Config thread the new params through
Co-authored-by: Cursor <cursoragent@cursor.com>
The stealth-ownership change added `await self._apply_stealth()` to `Browser.start`, a post-connect side effect that drives CDP overrides and new-document scripts against the live tab. The connect-retry regression suite already stubs `attach`/`update_targets` for the same reason (they need a real browser/websocket and aren't the unit under test); without also stubbing `_apply_stealth` the mocked CDP raised StopIteration -> RuntimeError, and its real ~1.2s settle sleep broke the warm-connect timing assertion. Stub it alongside the others. Co-authored-by: Cursor <cursoragent@cursor.com>
…ispatch Port the two release-pipeline fixes proven on mithwire-mcp (#5, #6) before the engine's first release-please-driven publish exercises the same code. - Gate the publish chain on the top-level `release_created` output. release-please-action@v4 leaves the path-prefixed `outputs['.--release_created']` key empty for a single-root manifest config; the engine never hit this only because v0.50.3 shipped via workflow_dispatch and bypassed the gate. The release-please push path would otherwise tag + release without ever publishing. - Add `always() && needs.build.result == 'success'` to testpypi/pypi. GitHub Actions' implicit success() gate evaluates the transitive needs graph, so a skipped release-please (workflow_dispatch path) cascades a skip through build into the publish jobs regardless of build's outcome. - Add a `tag` workflow_dispatch input to (re)publish an existing tag verbatim -- an escape hatch for any tag-without-publish drift. - Consolidate the prerelease decision in the build job's `publish_pypi` output so the release-please and tag-replay paths share one rule. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Completes the architectural realignment: the engine (
mithwire) now owns every browser-altering anti-detect capability, and any client (the MCP, or any custom script) is a pure consumer. The engine is fully agnostic about how it's used.mithwire/stealth/package:fingerprint.py—FingerprintConfig(moved into the engine; was previously owned client-side).controller.py—Stealthcontroller that applies the anti-detect patch set (window.chrome shim, headless UA cleanup, WebRTC leak protection, JS injections, etc.) against a live browser.__init__.py—compute_launch_argshelper for stealth-specific Chrome flags (--lang,--force-webrtc-ip-handling-policy,--window-size).Configacceptsfingerprint+webrtc_leak_protectionand injects stealth launch args viacompute_launch_args.Browser.start()applies stealth automatically after connect/attach and exposes the liveStealthinstance asbrowser.stealthso a client can re-apply an identity later (e.g. once a proxy egress geo resolves). Stealth presence is inferred purely from launch flags, so the engine never depends on a client's proxy abstraction.FingerprintConfig,Stealth,compute_launch_args.Bundled fixes required to land this safely:
test(connect): stub_apply_stealthin the connect-retry suite (same rationale as the existingattach/update_targetsstubs — it's a post-connect side effect needing a real browser, and its ~1.2s settle sleep would otherwise break the warm-connect timing assertion).fix(cdp): repair an invalid latin-1 byte innetwork.pythat brokeimport mithwirefrom a clean checkout.ci(release): port the two release-pipeline fixes proven onmithwire-mcp(fix: ship the mithwire.stealth subpackage in the wheel #5, chore(main): release 0.50.5 #6) — the latentrelease_createdgate bug and thesuccess()skip-cascade — before the engine's first release-please-driven publish trips over them. Also adds the tag-replay dispatch escape hatch.Test plan
import mithwire+from mithwire import Stealth, FingerprintConfig, compute_launch_argsresolve from a cleanuv sync.uv run pytest -q— 3 passed (connect-retry regression suite green after the_apply_stealthstub).Made with Cursor