fix(providers): secure web text entry, harden WebDriver transport and buttons, honor --relaunch

Merged
TH
4h ago
+1234-90

Summary

Fixes 2026-11-10 audit findings PROV-3, PROV-10, PROV-1, PROV2-1, PROV2-3, CONTR3-1, PROV-9, PROV-7, PROV-8 and PROV-6.

Web text entry (PROV-3)

  • fill and type send the text to agent-browser on stdin, as a one-entry batch. The text no longer appears in argv or in error details. This was checked with agent-browser 0.39.0 and headless Chromium.

WebDriver

  • PROV-10: session DELETE now retries (it is idempotent), and a W3C 404 invalid session id counts as already deleted. This stops a billed session leaking after one transient failure.
  • PROV-1: an error with a non-JSON body keeps its status, retry and dispatch disclosure.
  • PROV2-1:
    • Android home and app-switcher use mobile: pressKey 3 and 187, because UiAutomator2 has no pressButton.
    • iOS app-switcher is declared unsupported, because XCUITest pressButton only knows home, volumeup and volumedown.
  • PROV2-3: openDevice sends nothing, because activateApp needs an app id on both drivers. iOS deep links send bundleId.

Relaunch (CONTR3-1)

  • open --relaunch now works on Linux, HarmonyOS, Vega and tv-cdp. closeBeforeRelaunch is now a required field. Web relaunch is wired, but open --relaunch still refuses URL targets, so it cannot be exercised from the CLI today.

Other fixes

  • PROV-7: hosted uploads have a 15-minute deadline, typed failures, UNAUTHORIZED for 401/403, and stream the file instead of reading it into memory.
  • PROV-8: Device Farm artifact lookup uses the region from the session ARN.
  • PROV-9: a malformed CDP frame no longer crashes the daemon.
  • PROV-6: Linux open <binary> runs detached. A provider that injects runCommand must now also inject launchDetached; the type enforces this.

Not done

  • Dropped, PROV-4: keeping superseded plugin installs is documented behavior. Running daemons keep the files they started with.
  • Deferred, PROV2-4: the scroll page-source read needs a device run.
  • Deferred, PROV2-5: it belongs with the process-identity change in #4359.

29 files changed, +1239/−90.

Validation

  • Tested SHA f1d7af3 (test-only change on top of 373b157) (origin/main merged, including the Tizen provider):
    • format, lint, typecheck, layering, fallow, build and vitest-related pass;
    • the vitest unit suite passes (1963 files);
    • check:quick and check:fallow --base origin/main pass.
  • Local smoke failures: the test:smoke stage fails 2 smoke-daemon-clean cases locally. In that container, PID 1 (process_api) does not reap orphans, so the stopped daemon stays a <defunct> zombie and still reads as alive. Neither case touches code in this PR. CI is the authority for them.
  • Live runs:
    • BrowserStack, Pixel 8 / Android 14: home and app-switcher change the screen.
    • BrowserStack, iPhone 15 / iOS 17: device-only open and a Safari deep link work.
    • agent-browser 0.39.0: fill and type succeed, the secret never appears in argv or state, and a stale-ref fill fails typed with no backend text.
    • Linux (Xvfb): --relaunch yields a new pid.
  • Not adopted: one shared deferred-diagnostic helper fails the eager-closure budget.
  • Follow-ups:
    • Vega closeBeforeRelaunch.
    • A third keycode source.
    • agent-browser reports success on removed elements.

Generated by Claude Code