fix(bot-screen): vault page operations honour the human lease
browser_vault_fill / enter_code / save_login reach the page over the supervisor CDP socket, outside _run_browser_command, so they skipped the Bot Desktop fence: with a human holding the screen an ordinary browser_snapshot was refused while enter_code focused, inspected and wrote to the very form the human was typing into. Their tool handlers now run under the same run_fenced admission + epoch check as every other page access.
This commit is contained in:
@@ -109,3 +109,23 @@ def test_browser_console_supervisor_fast_path_is_fenced_while_human_controls_sha
|
||||
assert evaluated == [] and commands == [], "human holds the lease, yet the page was evaluated"
|
||||
assert "WHAT-THE-HUMAN-TYPED" not in raw
|
||||
assert result.get("code") == "human_has_control"
|
||||
|
||||
|
||||
def test_vault_page_operations_respect_the_human_lease(monkeypatch):
|
||||
"""The vault tools reach the page over the supervisor socket, outside `_run_browser_command`: while a
|
||||
human holds the screen they must be refused like every other page access, and never focus, inspect or
|
||||
write to the form the human is typing into."""
|
||||
from tools import browser_tool as browser
|
||||
from tools import browser_vault_tool as vault
|
||||
|
||||
browser._active_sessions["default"] = {"session_name": "review", "cdp_url": None, "features": {"local": True}}
|
||||
touched = []
|
||||
for name in ("browser_vault_fill", "browser_vault_enter_code", "browser_vault_save_login"):
|
||||
monkeypatch.setattr(vault, name, lambda *a, **k: touched.append(name) or json.dumps({"success": True}))
|
||||
lease.acquire("human")
|
||||
for handler in (vault._handle_vault_fill, vault._handle_vault_enter_code, vault._handle_vault_save_login):
|
||||
res = json.loads(handler({"handle": "vault_x"}, task_id="default"))
|
||||
assert res["code"] == "human_has_control", handler.__name__
|
||||
assert touched == [], "no vault page access while the human holds the screen"
|
||||
lease.release("human")
|
||||
assert json.loads(vault._handle_vault_fill({"handle": "vault_x"}, task_id="default"))["success"] is True
|
||||
|
||||
@@ -660,12 +660,26 @@ BROWSER_VAULT_ENTER_CODE_SCHEMA = {
|
||||
}
|
||||
|
||||
|
||||
def _fenced_page_op(task_id: Optional[str], fn) -> str:
|
||||
"""Vault operations focus, inspect and fill the page over the supervisor socket, bypassing
|
||||
``_run_browser_command``; they must honour the Bot Desktop lease like every other page access,
|
||||
or a human typing a credential on the taken-over screen could be read or written to."""
|
||||
from tools.browser_tool import _active_sessions, _last_session_key
|
||||
from tools.browser_tool_session import run_fenced
|
||||
|
||||
session = _active_sessions.get(_last_session_key(task_id or "default")) or {}
|
||||
res = run_fenced(session, lambda: {"raw": fn()})
|
||||
return res["raw"] if "raw" in res else json.dumps(res)
|
||||
|
||||
|
||||
def _handle_vault_enter_code(args: Dict[str, Any], **kwargs) -> str:
|
||||
return browser_vault_enter_code(handle=str(args.get("handle") or ""), task_id=kwargs.get("task_id"))
|
||||
tid = kwargs.get("task_id")
|
||||
return _fenced_page_op(tid, lambda: browser_vault_enter_code(handle=str(args.get("handle") or ""), task_id=tid))
|
||||
|
||||
|
||||
def _handle_vault_save_login(args: Dict[str, Any], **kwargs) -> str:
|
||||
return browser_vault_save_login(label=str(args.get("label") or ""), task_id=kwargs.get("task_id"))
|
||||
tid = kwargs.get("task_id")
|
||||
return _fenced_page_op(tid, lambda: browser_vault_save_login(label=str(args.get("label") or ""), task_id=tid))
|
||||
|
||||
|
||||
def _handle_vault_list(args: Dict[str, Any], **kwargs) -> str:
|
||||
@@ -677,9 +691,8 @@ def _handle_vault_unlock(args: Dict[str, Any], **kwargs) -> str:
|
||||
|
||||
|
||||
def _handle_vault_fill(args: Dict[str, Any], **kwargs) -> str:
|
||||
return browser_vault_fill(
|
||||
handle=str(args.get("handle") or ""), task_id=kwargs.get("task_id")
|
||||
)
|
||||
tid = kwargs.get("task_id")
|
||||
return _fenced_page_op(tid, lambda: browser_vault_fill(handle=str(args.get("handle") or ""), task_id=tid))
|
||||
|
||||
|
||||
from tools.registry import no_cache_check_fn, registry # noqa: E402
|
||||
|
||||
Reference in New Issue
Block a user