Skip to content

Latest commit

 

History

History
317 lines (241 loc) · 15.5 KB

File metadata and controls

317 lines (241 loc) · 15.5 KB

@mochi.js/harness

0.1.17

Patch Changes

  • Updated dependencies [dcf3dd2]
    • @mochi.js/core@0.9.5

0.1.16

Patch Changes

  • Updated dependencies [7bd80bb]
    • @mochi.js/consistency@0.1.5
    • @mochi.js/behavioral@0.1.7
    • @mochi.js/core@0.9.4
    • @mochi.js/profiles@0.2.1

0.1.15

Patch Changes

  • Updated dependencies [8dd25a8]
    • @mochi.js/core@0.9.3

0.1.14

Patch Changes

  • Updated dependencies [b0c5987]
    • @mochi.js/core@0.9.2

0.1.13

Patch Changes

  • @mochi.js/core@0.9.1

0.1.12

Patch Changes

  • Updated dependencies [c8e2055]
    • @mochi.js/core@0.9.0
    • @mochi.js/behavioral@0.1.6

0.1.11

Patch Changes

  • Updated dependencies [080e418]
    • @mochi.js/core@0.8.2

0.1.10

Patch Changes

  • 22b2a02: Wire real captured profile baselines into mochi.launch and bump the placeholder + CfT pin to Chrome 148.

    The bug. Every user shipping a string profile: got the hardcoded Chrome/131 placeholder UA against an installed Chromium-for-Testing v148. R-004's relational matrix dutifully emitted Chrome/131.0.6778.110 (canonical for the bogus minVersion: "131" the placeholder hardcoded), but the binary serving TLS, fonts, and media-device IDs is real Chromium 148. Fingerprint validators that compare the spoofed UA against the actual binary's behavior caught the mismatch.

    Three compounding causes, fixed in one pass.

    • @mochi.js/profiles.getProfile() was a throw new Error("not yet implemented") stub. The six captured baselines on disk under data/<id>/profile.json (Chrome/146–147 UAs, Mac M4 / Mac Intel / Linux / Windows / mac-brave / mac-beta) were never read by the runtime. Now: getProfile(id) reads the captured profile.json via Bun.file(). New error classes UnknownProfileIdError (id outside KNOWN_PROFILE_IDS) and ProfileBaselineMissingError (id known but no baseline shipped yet) let callers distinguish the two failure modes. hasProfile(id) helper added.
    • synthesizePlaceholderProfile() in @mochi.js/core/launch.ts was hardcoded minVersion: "131", Chrome/131.0.0.0 UA. The launcher always called the placeholder for string ids, never getProfile(). Now: the launcher tries getProfile(id) first and only falls back to synthesizePlaceholderProfile on ProfileBaselineMissingError (catalog ids without captures yet) or on truly unknown ids (with a console.warn so typos stay visible — preserves the pre-0.8 contract that any string id produces a working session, important for synthetic test-fixture ids). The placeholder itself bumps 131 → 148.
    • @mochi.js/consistency's BROWSER_TIP_FULL_VERSION table topped out at "147" for chrome / edge / brave / arc. Now: adds "148": "148.0.7778.97" so R-004's tip-locked lookup resolves the new placeholder major to a real published patch.
    • @mochi.js/cli PINNED_FALLBACK_VERSION was 131.0.6778.85 (very stale). Now: 148.0.7778.97, the live CfT stable pin verified in manifest tests. Capture-flow defaults that hardcoded Chrome/131 in derive-profile.ts, capture/index.ts, and provenance.ts JSDoc also bump to Chrome/148 so a fresh mochi capture produces a profile whose UA major matches the running binary.

    Profile data fix — linux-chrome-stable. The captured Linux baseline shipped with degraded GPU/display values that read as headless-server (SwiftShader) to Cloudflare Turnstile: gpu.renderer: "Generic Renderer", webglUnmaskedRenderer: "ANGLE (Generic)", 1280×800 display, 32 cores / 64GB, and a sec-ch-ua missing the branded "Google Chrome" entry (only "Chromium";v="147"). Now: realistic Intel Iris Xe values (Intel Iris Xe Graphics / ANGLE (Intel Inc., Intel Iris Xe Graphics, OpenGL 4.1)), 1920×1080, 8 cores / 16GB, and sec-ch-ua: "Google Chrome";v="147", "Not.A/Brand";v="8", "Chromium";v="147" — empirically validated as passing FingerprintJS Pro (bot=notDetected) and Cloudflare Turnstile in the wild.

    Harness conformance — host-OS-matched profile + per-baseline asserts. CONFORMANCE_PROFILE was hardcoded to mac-m4-chrome-stable for every host; this was silently masked pre-0.8 because the placeholder always returned a Linux profile regardless of id. Post-0.8 it loads the real Mac baseline on Linux CI, producing an OS mismatch that Cloudflare Turnstile catches. Now: CONFORMANCE_PROFILE resolves via defaultProfileForHost() (same decision table the launcher uses) — Linux CI gets linux-chrome-stable, Mac dev gets mac-m4-chrome-stable, etc. The audio + canvas fingerprint conformance test loads expected byte-exact hashes from the host-matched profile's baseline.manifest.json instead of hardcoding Mac M4's values, so it passes for any profile in the catalog with a captured baseline.

  • Updated dependencies [22b2a02]

    • @mochi.js/profiles@0.2.0
    • @mochi.js/core@0.8.1
    • @mochi.js/consistency@0.1.4
    • @mochi.js/behavioral@0.1.5

0.1.9

Patch Changes

  • Updated dependencies [52b5a45]
    • @mochi.js/core@0.8.0

0.1.8

Patch Changes

  • Updated dependencies [5705d38]
  • Updated dependencies [d79b782]
  • Updated dependencies [dd9a3c9]
    • @mochi.js/core@0.6.0
    • @mochi.js/consistency@0.1.3
    • @mochi.js/profiles@0.1.1
    • @mochi.js/behavioral@0.1.4

0.1.7

Patch Changes

  • Updated dependencies [60dac27]
  • Updated dependencies [a92cebf]
  • Updated dependencies [5cb8160]
    • @mochi.js/core@0.4.0

0.1.6

Patch Changes

  • Updated dependencies [6761997]
  • Updated dependencies [61ee52c]
  • Updated dependencies [92b8a57]
    • @mochi.js/profiles@0.1.0
    • @mochi.js/core@0.3.0
    • @mochi.js/consistency@0.1.2
    • @mochi.js/behavioral@0.1.3

0.1.5

Patch Changes

  • Updated dependencies [92eda96]
  • Updated dependencies [7cb4997]
    • @mochi.js/core@0.2.2

0.1.4

Patch Changes

  • Updated dependencies [59d7b91]
  • Updated dependencies [2855668]
  • Updated dependencies [a7d8ca9]
  • Updated dependencies [ddcc49e]
  • Updated dependencies [ef00f63]
    • @mochi.js/core@0.2.1

0.1.3

Patch Changes

  • Updated dependencies [be1c69b]
  • Updated dependencies [4f1b81e]
  • Updated dependencies [1231131]
    • @mochi.js/core@0.2.0
    • @mochi.js/consistency@0.1.1
    • @mochi.js/behavioral@0.1.2
    • @mochi.js/profiles@0.0.4

0.1.2

Patch Changes

  • Updated dependencies [707e42d]
    • @mochi.js/core@0.1.2

0.1.1

Patch Changes

  • 7073097: Hot-fix v0.1.0's broken workspace:* references in published package.json files. v0.1.0 leaked the Bun workspace protocol verbatim into published tarballs because changeset publish (which wraps npm publish) does NOT rewrite workspace:* to concrete semver ranges — that's a pnpm/yarn courtesy npm doesn't replicate. As a result, bun add @mochi.js/core@0.1.0 fails with Workspace dependency not found for every internal dep (behavioral, consistency, inject, net), and the same for the 6 other packages with internal deps.

    The fix adds scripts/rewrite-workspace-deps.ts as a publish-time pre-hook in the root release script. Pre-publish, every workspace:* in packages/<name>/package.json is rewritten to ^<sibling-version> resolved from the local workspace map. Bun's workspace links during dev still resolve via the name field, so concrete versions on disk between cycles don't break local development.

    Verified by bun pack-ing the affected packages locally and inspecting the resulting tarball's package.json deps before pushing v0.1.1.

    @mochi.js/consistency and @mochi.js/net-rs are leaf packages with no internal deps; they ship at v0.1.0/0.1.0 already and don't need a bump.

  • Updated dependencies [7073097]

    • @mochi.js/behavioral@0.1.1
    • @mochi.js/core@0.1.1
    • @mochi.js/profiles@0.0.3

0.1.0

Minor Changes

  • c38d7aa: Phase 0.5 — @mochi.js/harness MVP + mochi harness subcommand.

    • @mochi.js/harness ships the five public functions (capture, normalize, diff, categorize, report) and the runHarnessAgainstProfile orchestrator. Drives a Mochi-spoofed session through tests/fixtures/probe-page.html, normalizes per-session entropy on both the captured manifest and the committed baseline, structurally diffs the two, and categorizes each divergence as guid-class | intentional | material. PR gate: counts.material === 0 (PLAN.md §13.6).
    • mochi harness <profile-id> + mochi harness all runs the harness from the CLI. Without --out, prints verdict + counts. With --out <dir>, writes report.json + report.html for each profile.
    • Per-profile expected-divergences.json ships at packages/profiles/data/<id>/expected-divergences.json. Glob paths are categorized as intentional. Every entry has a human-readable comment — phase-0.7-deferred surfaces (audio bytes, canvas hash, full WebGL extensions, full font lists, MediaDevices, SpeechSynthesis voices, etc.) are pre-populated for mac-m4-chrome-stable.
    • Root bun harness:smoke / bun harness:full / bun harness:diff <id> scripts replace the v0.0 echo placeholders.
    • pr-fast.yml gains a soft-fail bun harness:smoke step. Hard-fail flips on at the end of phase 0.7.
  • f0c1a8a: Task 0150 — humanize conformance suite + supporting Page surface.

    • @mochi.js/harness gains a new conformance suite under src/conformance/humanize/__tests__/ — a mochi-native port of CloakHQ/CloakBrowser's tests/test_humanize_unit.mjs + tests/test_human_visual.mjs. Seven test files cover config resolution, Bezier math, mouse trajectory (E2E), keystroke timing, fill clearing (E2E), patching integrity, and (online, MOCHI_ONLINE=1) the deviceandbrowserinfo.com bot-detection form. Run via bun run conformance:humanize (offline) or bun run conformance:humanize:online.
    • @mochi.js/core ships three Page-surface additions:
      • Page.humanMove(x, y, opts?) — animate the cursor to (x, y) along a Bezier trajectory without dispatching a click. Same underlying synth as humanClick minus the press/release.
      • Page.cursorPosition() — read the tracked cursor (x, y) so sequences of humanMove/humanClick chain realistically.
      • Page.humanType("", selector) — clearing semantics. Emits Backspace × value.length with realistic key timing instead of being a no-op as it was before.
    • Companion correctness fix: Input.dispatchKeyEvent now carries the proper code + windowsVirtualKeyCode for control keys (Backspace/Enter/Tab/Escape/Delete) so Chromium fires the edit-action handler, not just the JS keydown event. Printable letters/digits/space also get plausible KeyA/Digit0/Space codes for layout-aware page code.
    • Root scripts + CI gates wired:
      • bun run conformance:humanize is a PR-fast hard-fail step.
      • bun run conformance:humanize is a release-pre-publish gate.
    • Initial cursor position now defaults to the matrix's display.width/2, display.height/2 (PLAN.md I-5) instead of (0, 0) — a real human's pointer is never at the viewport origin.
  • 74443f7: Phase 0.5.x — stealth conformance suite (port of CloakBrowser tests/test_stealth.py).

    • @mochi.js/harness gains a new conformance/stealth/ subtree. Layer 1 (webdriver-detection.test.ts) runs as the load-bearing PR-fast gate alongside bun harness:smoke — six offline assertions ported verbatim from CloakBrowser's TestWebDriverDetection: navigator.webdriver===false, no HeadlessChrome UA, typeof window.chrome === "object", navigator.plugins.length >= 5, navigator.languages.length >= 1, no cdc_* / __webdriver* window keys. Layer 2 (bot-detection-sites.test.ts) runs gated by MOCHI_ONLINE=1 against bot.sannysoft, bot.incolumitas, browserscan, deviceandbrowserinfo, and demo.fingerprint.com/web-scraping. Three online tests carry typed expected-failure entries (incolumitas anti-debugger trap, sannysoft MQ_SCREEN, fingerprint.com IP-class blocking) — see docs/limits.md.
    • @mochi.js/inject gains two CloakBrowser-surfaced defensive shim modules: window-chrome.ts (mirrors Chrome's window.chrome shape with loadTimes/csi/app only when the underlying browser doesn't already expose it; runtime is intentionally undefined for non-extension contexts) and plugins.ts (curated 5-plugin PluginArray + 2-mimetype MimeTypeArray, matching the mac-m4-chrome-stable baseline; only installed when the underlying browser reports an empty list). Both shims no-op on real Chrome.app where the surfaces are native, so the existing harness Zero-Diff gate is unchanged at runtime.
    • New scripts: bun conformance:stealth (Layer 1, PR-fast) and bun conformance:stealth:online (Layer 2, network-gated). Wired into .github/workflows/pr-fast.yml (Layer 1 hard-fail) and .github/workflows/release.yml (both layers gate publish).
    • Vendored upstream source: tests/fixtures/cloakbrowser/test_stealth.py (sha-pinned to 13b1b98b6840b68316e43fd46f43ffa7f50fd967).

Patch Changes

  • 4f09750: Initial v0.0.1 claim release with placeholder exports. Surface lands incrementally per PLAN.md §14.

  • ff75595: Land proxy authentication for HTTP / HTTPS / SOCKS5 / SOCKS4 proxies, wire the live conformance:stealth:online gate to a residential proxy via the HTTP_PROXY repo secret, and harden the bot.incolumitas.com test against goto soft-fail timeouts.

    • @mochi.js/core ships a new proxy-auth.ts that attaches a CDP Fetch.authRequired listener on session start when credentials are present, answering proxy auth challenges with Fetch.continueWithAuth. No extension, no Runtime.enable, no Page.createIsolatedWorld — PLAN.md §8.2 invariants preserved (Fetch.enable is not on the forbidden list and produces no page-observable signals). The handler is wired with empty patterns so regular request flow is unaffected; a defensive Fetch.requestPaused handler short-circuits via Fetch.continueRequest if Chromium ever pauses a request despite the empty pattern set. Fetch.disable runs on session close.

      parseProxyUrl(url) is exported and handles the four protocols, with and without auth, percent-encoded credentials, IPv6 hosts, and missing ports (defaults: HTTP=80, HTTPS=443, SOCKS5/4=1080). LaunchOptions.proxy accepts both the string form (http://user:pass@host:port) and the ProxyConfig record shape; both feed the same auth path. Credentials are forwarded to the network FFI too, so Session.fetch shares the same authenticated egress as the browser.

    • @mochi.js/harnesslaunchSharedSession() now reads MOCHI_PROXY and feeds it to mochi.launch({ proxy }) when set. Empty / unset = unproxied (fork PRs without secrets still run cleanly). The bot.incolumitas.com test short-circuits to its registered expected-failure when bestEffortGoto reports navigated: false, preventing the 12s sleep + 30s evaluate + worker-injection cascade from eating the 90s test budget.

    • CI — both release.yml (existing Layer 2 step) and pr-fast.yml (newly added Layer 2 step, gated if: github.event_name == 'pull_request') now pass MOCHI_PROXY: ${{ secrets.HTTP_PROXY }} so the live runs egress from a residential IP. The secret value is never echoed.

  • Updated dependencies [3fefd93]

  • Updated dependencies [e97c732]

  • Updated dependencies [5ea34c6]

  • Updated dependencies [29e1bb2]

  • Updated dependencies [f0c1a8a]

  • Updated dependencies [4f09750]

  • Updated dependencies [e7cc610]

  • Updated dependencies [ff75595]

    • @mochi.js/behavioral@0.1.0
    • @mochi.js/consistency@0.1.0
    • @mochi.js/core@0.1.0
    • @mochi.js/profiles@0.0.2