feat: token-auth removal, security hardening, Stripe-style compat layer (v0.9.2)
Testing / test (push) Successful in 41s
Package Extension / package-extension (push) Successful in 35s
Build & Publish Package / publish (push) Successful in 46s

- Remove token auth entirely; only Ed25519 pubkey auth or --no-auth
- Add 32 MB message-size cap in serve and client (DoS protection)
- Set Unix socket to 0o600 after bind in native_host (multi-user hardening)
- Enforce browser-cli/VERSION user-agent on all TCP connections
- Add PROTOCOL_MIN_CLIENT check (>= 0.9.0) server- and client-side
- Include server_version + min_client_version in challenge frame
- Add browser_cli/version_manager.py: parse_version, get_installed_version
- Add browser_cli/compat.py: Stripe-style versioning layer with adapt_request
  / adapt_response hooks; baseline 0.9.2, no shims needed yet
- Fix BrowserCLI key handling: no Path() wrap for agent specs
- Fix _multi_browser_targets() to forward key to remote_browser_targets()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-02 21:59:46 +02:00
parent b98c4ae116
commit c1a5ef9dd7
17 changed files with 267 additions and 237 deletions
+5 -5
View File
@@ -17,10 +17,10 @@ def _handle(command, args=None, profile=None):
raise SystemExit(1)
def _handle_multi(command, args=None, profile=None, remote=None, token=None):
def _handle_multi(command, args=None, profile=None, remote=None):
try:
if remote:
return send_command(command, args or {}, profile=profile, remote=remote, token=token)
return send_command(command, args or {}, profile=profile, remote=remote)
return send_command(command, args or {}, profile=profile)
except (BrowserNotConnected, RuntimeError):
return None
@@ -33,7 +33,7 @@ def _multi_browser_targets():
remote = root.obj.get("remote")
key = root.obj.get("key")
if remote:
targets = remote_browser_targets(remote, root.obj.get("token"), key=key)
targets = remote_browser_targets(remote, key=key)
else:
targets = active_browser_targets(key=key)
if len(targets) <= 1 and not any(target.remote for target in targets):
@@ -78,7 +78,7 @@ def group_list():
if targets:
groups = []
for target in targets:
result = _handle_multi("group.list", profile=target.profile, remote=target.remote, token=target.token)
result = _handle_multi("group.list", profile=target.profile, remote=target.remote)
if result is None:
continue
groups.extend({**group, "browser": target.display_name} for group in result)
@@ -111,7 +111,7 @@ def group_count():
total = 0
rows = 0
for target in targets:
count = _handle_multi("group.count", profile=target.profile, remote=target.remote, token=target.token)
count = _handle_multi("group.count", profile=target.profile, remote=target.remote)
if count is None:
continue
count = int(count or 0)