diff --git a/tests/tools/test_computer_use_cua_0_10_permissions.py b/tests/tools/test_computer_use_cua_0_10_permissions.py index 49c189f418..edcd388d75 100644 --- a/tests/tools/test_computer_use_cua_0_10_permissions.py +++ b/tests/tools/test_computer_use_cua_0_10_permissions.py @@ -37,6 +37,29 @@ def test_any_explicit_hermes_bypass_maps_to_unrestricted_mode(): assert computer_use._cua_permission_mode("session-a") == "unrestricted" +def test_gateway_session_key_yolo_maps_to_unrestricted_mode(): + """Gateway /yolo keys bypass off the gateway session_key contextvar, + not the DB session_id the tool path passes. Mode resolution must consult + both namespaces or /yolo is silently dead on messaging platforms.""" + from tools import approval + from tools.computer_use import tool as computer_use + + gateway_key = "agent:main:telegram:private:12345" + token = approval.set_current_session_key(gateway_key) + try: + approval.enable_session_yolo(gateway_key) + # Tool dispatch passes the (different) DB session id. + assert computer_use._cua_permission_mode("db-sid-xyz") == "unrestricted" + approval.disable_session_yolo(gateway_key) + assert computer_use._cua_permission_mode("db-sid-xyz") == "standard" + finally: + approval.disable_session_yolo(gateway_key) + try: + approval.reset_current_session_key(token) + except Exception: + approval.set_current_session_key("") + + def test_mode_change_replaces_only_that_sessions_backend(): from tools.computer_use import tool as computer_use diff --git a/tools/computer_use/tool.py b/tools/computer_use/tool.py index aca17f50ab..dbe6fc1558 100644 --- a/tools/computer_use/tool.py +++ b/tools/computer_use/tool.py @@ -169,14 +169,29 @@ _always_allow: Dict[str, set] = {} def _cua_permission_mode(session_id: str) -> str: - """Map Hermes's explicit approval bypass onto Cua's immutable mode.""" + """Map Hermes's explicit approval bypass onto Cua's immutable mode. + + Hermes has TWO session-identity namespaces: the tool-dispatch path passes + the DB ``session_id`` (``agent.session_id``), while gateway ``/yolo`` + keys approval state off the gateway ``session_key`` (set per turn via the + ``set_current_session_key`` contextvar in tools/approval.py). CLI and TUI + use the DB id for both. Checking ONLY ``session_id`` here would make a + gateway ``/yolo`` toggle silently invisible to computer_use (works in + CLI, dead on messaging platforms), so we consult both namespaces — + bypass in either means the user explicitly opted out of approvals for + this run. Fails closed on any resolution error. + """ try: from tools.approval import ( + get_current_session_key, is_approval_bypass_active_for_session, ) if is_approval_bypass_active_for_session(session_id): return "unrestricted" + current_key = get_current_session_key(default="") + if current_key and is_approval_bypass_active_for_session(current_key): + return "unrestricted" except Exception: # Approval state must fail closed if it cannot be resolved. pass