Commit Graph

203 Commits

Author SHA1 Message Date
Saurav Panda 8c41cf795a fix(daemon): restrict unix socket file to owner-only access
The per-session HMAC auth token (de14b9aa) gates command dispatch, but
asyncio.start_unix_server creates the socket file with the process
umask, leaving it 0o755 by default. On multi-user hosts a co-tenant
can connect() and probe behavior even though the handshake will
ultimately fail.

Set umask to 0o077 around start_unix_server and chmod 0o600 after,
matching the auth-token file's posture.
2026-05-18 18:28:10 -07:00
Saurav Panda 44f7ead5cd Drop timeout on recording finalize in daemon shutdown
`asyncio.wait_for(stop_recording(), timeout=5.0)` could expire while the
ffmpeg encoder was still flushing, leading the daemon's subsequent
`os._exit(0)` to kill the executor thread mid-write and leave the exact
truncated MP4 this hook was meant to prevent. `stop_recording()` already
offloads the blocking close to an executor, so awaiting it directly is
safe — and if it genuinely hangs, a stuck daemon is a clearer failure
signal than silent video corruption.

Verified end-to-end: start recording → `open` → `close` (no explicit
`record stop`) now produces a decodable MP4 with the captured frames.
2026-04-20 15:38:34 -07:00
Saurav Panda 132756dabb Address PR review feedback for record start/stop
- `on_BrowserConnectedEvent` now catches `RuntimeError` from
  `start_recording()` so sessions with `record_video_dir` configured but
  missing `[video]` extras (or a viewport that can't be sized) keep
  starting — prior graceful-degradation behavior is restored.
- Lazy `RecordingWatchdog` in the CLI handler now calls
  `attach_to_session()`, so `AgentFocusChangedEvent` / `BrowserStopEvent`
  handlers are wired correctly if the session dispatches them.
- Daemon shutdown finalizes any in-progress recording before tearing the
  browser down, preventing truncated MP4s on `close`, idle timeout, or
  signal-driven exit.
- Added regression test that monkeypatches `start_recording` to raise and
  asserts `on_BrowserConnectedEvent` swallows it without breaking startup.
2026-04-20 15:11:49 -07:00
Saurav Panda b1d933258c Add record start/stop CLI command for session video capture
Closes #4533.

- `RecordingWatchdog` gains public `start_recording(path, size?, framerate?)`,
  `stop_recording() -> Path`, and `is_recording`; the existing
  `BrowserConnectedEvent`/`BrowserStopEvent` path is refactored to use them,
  so profile-driven recording behavior is unchanged.
- `browser-use record start <path>` / `record stop` / `record status`
  subcommands wired through argparse, daemon dispatch, and the browser
  command handler. `record stop` prints the saved file path so it can be
  captured programmatically, matching the issue's requested UX. Works with
  `--session NAME` via the existing named-daemon infrastructure.
- The CLI's `CLIBrowserSession` intentionally skips watchdogs; the handler
  lazily instantiates `RecordingWatchdog` on first `record start` so CLI
  recording doesn't pay the watchdog-setup cost for non-recording sessions.
- Output format is `.mp4` (libx264) since that's what the existing
  `VideoRecorderService` encodes; optional dependency gate is unchanged
  (`pip install "browser-use[video]"`).
- New `tests/ci/test_action_record.py` exercises the full stack against a
  real headless browser + `pytest-httpserver`, verifying decodable MP4
  output, double-start rejection, stop-without-start no-op, that the
  existing `profile.record_video_dir` flow still works, and the argparse /
  dispatch wiring.
2026-04-20 14:50:52 -07:00
Laith Weinberger 4476f6e16e fix input clear fallbacks and clarify clear-then-type behavior 2026-04-15 17:31:04 -04:00
laithrw 9c314e626e Merge branch 'main' into fix/local-state-utf8-encoding 2026-04-15 16:06:56 -04:00
voidborne-d 4c2d136de9 fix: add utf-8 encoding to Local State file read in list_chrome_profiles
On Windows with a non-UTF-8 default locale (e.g. Chinese GBK/CP936),
open() without an explicit encoding uses the system code page. Chrome's
Local State file is always UTF-8, so profile names containing non-ASCII
characters (e.g. Chinese '用户1') are decoded as mojibake.

Fixes #4673
2026-04-15 17:07:51 +00:00
Shawn Pana d0fbf4c580 improve connect failure UX: fix chrome://inspect link and add fallback guidance
When `browser-use connect` fails to discover a running Chrome, the error
now points to the correct `chrome://inspect/#remote-debugging` URL. The
SKILL.md also guides agents to prompt users with two options: enable
remote debugging or use managed Chromium with a Chrome profile.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 11:23:50 -07:00
Laith Weinberger 99a8674214 fix asyncio.get_event_loop for python 3.14 cli compatibilit 2026-04-11 18:10:12 -04:00
Alezander9 76569995fd Improve OSS-to-cloud conversion: UTM tracking, better error messages, and cloud nudges
- Add UTM params to all cloud-bound links across README, CLI, and error messages
- Rewrite README Open Source vs Cloud section: position cloud browsers as
  recommended pairing for OSS users, remove separate Use Both section
- Rewrite error messages for use_cloud=True and ChatBrowserUse() to clearly
  state what is wrong and what to do next
- Add missing URLs: invalid API key now links to key page, insufficient
  credits now links to billing page
- Add cloud browser nudge on captcha detection (logger.warning)
- Add cloud browser nudge on local browser launch failure
2026-04-08 22:05:50 -07:00
sauravpanda ca2185ba61 fix: create token temp file with 0o600 at open() time; raise on failure
- Use os.open() with mode 0o600 instead of write-then-chmod to eliminate
  the permission race window where the temp file is briefly world-readable.
- Raise instead of warn when token file write fails: a daemon that cannot
  persist its auth token is permanently unauthorized for all clients, so
  failing fast is correct (identified by cubic).
2026-04-02 17:58:12 -07:00
sauravpanda a05a053da6 fix: add per-session auth token to daemon socket to prevent unauthorized code execution
Generate a secrets.token_hex(32) on daemon startup, write it atomically
to ~/.browser-use/{session}.token (chmod 0o600), and validate it on every
incoming request via hmac.compare_digest. The client reads the token file
and includes it in each send_command() call.

This closes the arbitrary-code-execution vector where any local process
could connect to the deterministic Windows TCP port (or a world-readable
Unix socket) and dispatch the 'python' action to run eval()/exec() as the
daemon owner.
2026-04-02 17:41:15 -07:00
Saurav Panda 14ada65183 Merge branch 'main' into worktree-fix+aiohttp-security-upgrade 2026-04-02 16:31:45 -07:00
sauravpanda 22f0e501e9 fix: upgrade aiohttp to 3.13.4 to patch memory exhaustion vulnerability
Bumps aiohttp from 3.13.3 to 3.13.4 in requirements-cli.txt.
Fixes uncapped memory usage from insufficient trailer header restrictions
(aio-libs/aiohttp@0c2e9da).
2026-04-02 16:26:39 -07:00
sauravpanda 56d8aa8483 fix: address review violations — drop env var fallback, fix cross-fs move
- cloud.py: remove BROWSER_USE_API_KEY env var fallback (violates CLI
  policy of config.json as single source of truth); instead detect the
  env var in the error path and print a targeted migration hint
- setup.py: replace Path.rename() with shutil.move() so the temp file
  can be moved across filesystems (e.g. /tmp -> /usr/local/bin)
2026-04-02 16:21:24 -07:00
sauravpanda ea99055e53 fix: write config.json atomically via tmp+rename to prevent silent data loss
A SIGKILL mid-write truncates config.json; read_config() catches
json.JSONDecodeError and returns {}, silently wiping the API key and
all other settings. Mirror the pattern already used by _write_state():
write to a sibling temp file, fsync, chmod 600, then os.replace() into
place — which is atomic on POSIX and effectively atomic on Windows.
2026-04-02 13:08:37 -07:00
sauravpanda 7a887e156e fix: verify cloudflared binary SHA256 checksum before installing on Linux
Downloads to a temp file, fetches the .sha256sum file Cloudflare publishes
alongside each release, and verifies before moving to the install destination.
Protects against MITM/CDN tampering. Temp file is cleaned up on failure.
2026-04-02 13:08:37 -07:00
sauravpanda 96bb65dcb5 fix: warn on deprecated BROWSER_USE_API_KEY env var instead of silently ignoring it
The CLI previously accepted the env var as a fallback; this PR dropped it
without a migration path, breaking CI/CD pipelines that set it as a secret.
Restore backwards-compat by checking the env var after config.json and
printing a deprecation warning with the migration command.
2026-04-02 13:08:37 -07:00
ShawnPana 0530545c1a fix: API key single source of truth (config.json only), daemon-safe profile creation
- Remove BROWSER_USE_API_KEY env var as a read source from CLI code; config.json is the only source of truth
- Split _create_cloud_profile into daemon-safe _inner (raises) and CLI wrapper (sys.exit)
- Daemon auto-heal no longer kills process on profile creation API errors
2026-04-02 11:51:38 -07:00
ShawnPana 47ba16b8ab ux: show Connecting.../Closing... status during slow operations 2026-04-02 11:29:03 -07:00
ShawnPana 1deb430f8f perf: skip profile validation HTTP call on cloud connect
_get_or_create_cloud_profile reads config instantly instead of
validating via GET /profiles/{id} on every connect. If the profile
is invalid, _provision_cloud_browser auto-heals by creating a new
one and retrying. Saves ~500ms-1s on every cloud connect.
2026-04-02 11:21:12 -07:00
ShawnPana 63904858f4 fix: CDP URL only in sessions --json, not in table output 2026-04-01 22:40:48 -07:00
ShawnPana 8c6d042a79 fix: truncate CDP URL in sessions table, full URL in --json 2026-04-01 22:39:30 -07:00
ShawnPana b1522b5e23 fix: sessions shows CDP URL for cloud sessions too
Ping response now returns live CDP URL from the browser session
(not just the constructor arg). Cloud sessions show their
provisioned CDP URL.
2026-04-01 22:37:23 -07:00
ShawnPana c09ea5a0b2 feat: sessions command shows CDP URL for each session 2026-04-01 22:35:11 -07:00
ShawnPana d6c9b8a24b fix: reject invalid boolean config values instead of silently coercing to False 2026-04-01 22:29:36 -07:00
ShawnPana f27c567aad fix: enable_recording defaults False in library, configurable in CLI
Library keeps recording off by default. CLI reads cloud_connect_recording
from config (defaults True). Users can disable with:
  browser-use config set cloud_connect_recording false
2026-04-01 22:22:33 -07:00
ShawnPana a2bcc1a3f9 fix: wrap Page.enable in try/except (not supported on root CDP client)
Page.enable fails on browser-level CDP targets. Wrap in try/except
like the library's PopupsWatchdog does. Dialog handler still
registers regardless — events may fire on some CDP implementations.
2026-04-01 22:13:55 -07:00
ShawnPana 778984af8e fix: remove unnecessary string quotes on BrowserSession type hint 2026-04-01 21:49:10 -07:00
ShawnPana 92181538d3 fix: type-narrow actions instead of assert (fixes pyright + test compat) 2026-04-01 21:43:56 -07:00
ShawnPana 080eeae62a fix: CI type errors and test compatibility
- type: ignore on each param line in sessions.py (pyright per-line)
- Remove ActionHandler assert in browser.py (breaks pre-existing tests)
- Ruff format
2026-04-01 21:39:51 -07:00
ShawnPana a3b6217e8f fix: SessionInfo.browser_session typed as BrowserSession
Fixes type errors in test_cli_upload and test_cli_coordinate_click
which construct SessionInfo with BrowserSession instances.
2026-04-01 21:31:18 -07:00
ShawnPana 51244762cc fix: ActionHandler accepts BrowserSession (not just CLIBrowserSession)
Fixes type errors in test_cli_upload and test_cli_coordinate_click
which pass BrowserSession. CLIBrowserSession inherits from it so
the runtime behavior is unchanged.
2026-04-01 21:26:08 -07:00
ShawnPana 0bf1f02d97 fix: CI failures — ruff formatting, type errors, test_setup_command
- Ruff format all skill_cli and test files
- Fix type: get_config_value returns str|int|None, callers cast properly
- Fix type: BrowserWrapper.actions is non-optional (always provided)
- Fix type: config comparison uses 'is' not '=='
- Rewrite test_setup_command for new setup.handle(yes=True) API
- Add None guard in test_cli_lifecycle for state file
2026-04-01 19:58:33 -07:00
ShawnPana bebb3d1a80 fix: treat empty BROWSER_USE_API_KEY as missing in ensure_daemon
Consistent with the same fix applied to config.py and browser.py.
2026-04-01 19:51:36 -07:00
ShawnPana 4163531dfd fix: title fallback checks if focused tab was found, not if title is empty
A tab with empty title (about:blank) should show empty, not
fall back to tabs[0]'s title.
2026-04-01 19:48:51 -07:00
ShawnPana 6759ba9783 fix: add curl prerequisite check to install_lite.sh 2026-04-01 19:40:00 -07:00
ShawnPana d750babbec fix: timeout cloud browser stop to prevent blocking event loop
5s timeout on stop_browser() API call. If it hangs, skip and
disconnect — cloud browser will time out server-side.
2026-04-01 19:34:53 -07:00
ShawnPana 1711a8918e fix: sessions won't delete socket of live daemon with stale PID
Check socket_reachable before cleaning up files. A daemon with a
corrupt/stale PID file but a live socket is still running.
2026-04-01 19:31:59 -07:00
ShawnPana 074ff9c2d2 fix: state reports focused tab's title instead of tabs[0]
In multi-tab sessions, state was always reporting the first tab's
title. Now uses agent_focus_target_id to find the correct tab,
falling back to tabs[0] if no focus is set.
2026-04-01 19:26:37 -07:00
ShawnPana b19a8bb0b0 fix: treat empty BROWSER_USE_API_KEY as unset
Empty string or whitespace-only env var now treated as missing
across all CLI code that checks the API key.
2026-04-01 19:24:23 -07:00
ShawnPana 7132935aa0 fix: detect Linux arch for cloudflared download (amd64 vs arm64) 2026-04-01 19:14:32 -07:00
ShawnPana f26bd52af0 fix: enable Page domain before registering dialog handler
Page.enable() must be called on the root CDP client before
javascriptDialogOpening events will fire. Without this, JS dialogs
freeze all CDP commands because the auto-dismiss handler never triggers.
2026-04-01 19:11:52 -07:00
ShawnPana 094b699eb7 fix: add 'new' to tab command error message 2026-04-01 19:01:25 -07:00
ShawnPana 6c0ac3adab fix: only create new profile on 404, guard JSON parsing
Profile validation now fails on auth/server errors instead of silently
creating a new profile. Also wraps profile creation response parsing
in try/except for malformed payloads.
2026-04-01 18:59:51 -07:00
ShawnPana b4c874721a fix: scroll handles left/right directions correctly
window.scrollBy now maps left/right to X axis instead of always
using Y axis. Fixes horizontal scroll regression from CDP-to-JS rewrite.
2026-04-01 18:57:52 -07:00
ShawnPana b92c7486bf fix: remove 9229 from Chrome CDP port probing (Node.js debugger port, not Chrome) 2026-04-01 18:24:41 -07:00
ShawnPana e09f55eedc chore: remove more dead code (second codex pass)
- Removed utils.py is_daemon_alive() (stale duplicate of main.py version)
- Removed TunnelManager.is_available() (unused, get_status() used instead)
- Removed dead json_output param from setup.handle()
2026-04-01 17:56:39 -07:00
ShawnPana 01995138f1 chore: remove dead code found by codex review
- Deleted commands/utils.py (format_duration never referenced)
- Removed COMMANDS constant from doctor.py (never read)
- Removed list_sessions and get_log_path from utils.py (no callers)
- Removed unreachable event_bus fallbacks from BrowserWrapper
- Fixed dead assignment in doctor _check_browser
2026-04-01 17:43:42 -07:00
ShawnPana ca05f46352 refactor: remove --agent/register/tab-ownership, sessions-as-agents model
Multi-agent isolation is now achieved through separate sessions
(--session NAME), each with its own browser. Removed:
- register command and agents.json
- --agent flag and agent_id plumbing
- TabOwnershipManager and all tab locking logic
- dispatch lock and focus swapping between agents
- tab_ownership.py (deleted)
- test_tab_ownership.py (deleted)

Simplified tab commands: no lock checks, no _tab_list injection,
no _resolved_target_id params. agent_focus_target_id stays for
single-agent tab tracking.

Tested: 3 concurrent subagents on separate cloud sessions,
3 concurrent subagents on separate headless Chromium sessions.
2026-04-01 17:34:46 -07:00