feat: harden remote serve and reuse connections
Testing / remote-protocol-compat (0.9.5) (push) Successful in 56s
Testing / remote-protocol-compat (0.9.3) (push) Successful in 59s
Testing / test (push) Successful in 1m1s
Build & Publish Package / publish (push) Successful in 33s
Package Extension / package-extension (push) Successful in 36s

- Gate TCP serve commands with safe-by-default policies, per-key allow tokens, per-key rate limiting, and audit labels.
- Reuse authenticated encrypted remote sessions and parallelize/caches multi-browser fanout to reduce repeated handshake roundtrips.
- Increase paged native-host batch size with extension-side byte budgeting to speed large tab listings safely.
- Point install output at public Chrome Web Store / Firefox AMO listings by default, with --dev preserving unpacked workflows.
- Share search-engine metadata between CLI and SDK and bump the package/extension version to 0.16.0.
- Cover the new security, pooling, paging, install, and fanout behavior with expanded Python and extension tests.
This commit is contained in:
2026-06-18 14:24:15 +02:00
parent 8dece7800f
commit 6fa931aa36
49 changed files with 3407 additions and 1878 deletions
+32 -11
View File
@@ -10,6 +10,7 @@ class ServeControlMixin:
addr: tuple
command: str
auth_keys_path: Path | None
auth_label: str | None
async def send_error(self, msg: str, msg_id=None) -> None: ...
async def send_ok(self, payload, command: str | None = None) -> None: ...
@@ -23,25 +24,32 @@ class ServeControlMixin:
try:
clients = send_command("clients.list", profile=target.profile, suppress_pq_warning=True)
if clients:
browser_name = clients[0].get("name")
if browser_name:
item["browserName"] = browser_name
# Carry the full client info so a remote `clients` command can render
# from this single roundtrip instead of issuing another clients.list.
info = clients[0]
for src, dst in (("name", "browserName"), ("version", "version"), ("extensionVersion", "extensionVersion")):
value = info.get(src)
if value:
item[dst] = value
except Exception:
pass
targets.append(item)
await self.send_ok(targets, self.command)
log_request(self.addr, self.command, None, "OK")
log_request(self.addr, self.command, None, "OK", identity=self.auth_label)
return True
if self.command == "browser-cli.auth.keys":
if self.auth_keys_path is None:
await self.send_error("no authorized keys file configured on this server")
log_request(self.addr, self.command, None, "ERROR", "no authorized keys file")
log_request(self.addr, self.command, None, "ERROR", "no authorized keys file", identity=self.auth_label)
return True
from browser_cli.auth import load_authorized_keys_with_names
entries = [{"pubkey": pk, "name": name} for pk, name in load_authorized_keys_with_names(self.auth_keys_path)]
from browser_cli.auth import load_authorized_keys_with_policies
entries = [
{"pubkey": pk, "name": name, "allow": cats}
for pk, name, cats in load_authorized_keys_with_policies(self.auth_keys_path)
]
await self.send_ok(entries, self.command)
log_request(self.addr, self.command, None, "OK")
log_request(self.addr, self.command, None, "OK", identity=self.auth_label)
return True
if self.command == "browser-cli.auth.trust":
@@ -54,14 +62,27 @@ class ServeControlMixin:
log_request(self.addr, self.command, None, "ERROR", "no authorized keys file")
return True
from browser_cli.auth import add_authorized_key
from browser_cli.serve.security import policy_from_categories
args = msg.get("args") or {}
pubkey = str(args.get("pubkey") or "")
name = str(args.get("name") or "")
categories = args.get("allow")
if not re.fullmatch(r"[0-9a-f]{64}", pubkey):
await self.send_error("invalid pubkey: expected 64 lowercase hex characters")
log_request(self.addr, self.command, None, "ERROR", "invalid pubkey")
log_request(self.addr, self.command, None, "ERROR", "invalid pubkey", identity=self.auth_label)
return True
added = add_authorized_key(self.auth_keys_path, pubkey, name)
if categories is not None:
if not isinstance(categories, list):
await self.send_error("invalid allow: expected a list of category strings")
log_request(self.addr, self.command, None, "ERROR", "invalid allow", identity=self.auth_label)
return True
try:
policy_from_categories(categories) # validate before persisting
except ValueError as exc:
await self.send_error(str(exc))
log_request(self.addr, self.command, None, "ERROR", "invalid allow category", identity=self.auth_label)
return True
added = add_authorized_key(self.auth_keys_path, pubkey, name, categories)
await self.send_ok({"added": added}, self.command)
log_request(self.addr, self.command, None, "OK" if added else "ALREADY_TRUSTED")
log_request(self.addr, self.command, None, "OK" if added else "ALREADY_TRUSTED", identity=self.auth_label)
return True