"""Local owner discovery must fence profile and lease identity.""" import json import os import threading from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer import pytest from hermes_cli.active_sessions import try_acquire_active_session def test_discovery_uses_exact_profile_and_owner_handshake(tmp_path): from hermes_cli.shared_session_attach import discover_attach_url home = tmp_path / "profile" other = tmp_path / "other" reply = {} requests = [] class Handler(BaseHTTPRequestHandler): def do_GET(self): requests.append(self.path) payload = json.dumps(reply).encode() self.send_response(200) self.end_headers() self.wfile.write(payload) def log_message(self, *args): pass server = ThreadingHTTPServer(("127.0.0.1", 0), Handler) thread = threading.Thread(target=server.serve_forever, daemon=True) thread.start() origin = f"http://127.0.0.1:{server.server_port}" lease, error = try_acquire_active_session( session_id="same-id", surface="desktop", config={}, registry_home=home, metadata={"live_session_id": "live", "shared_runtime_url": origin}, ) assert error is None reply.update(session_id="same-id", lease_id=lease.lease_id, profile_home=str(home.resolve()), websocket_url=origin.replace("http:", "ws:") + "/api/ws?token=real-token") try: assert discover_attach_url("same-id", registry_home=other) is None assert requests == [] assert discover_attach_url("same-id", registry_home=home) == reply["websocket_url"] assert len(requests) == 1 from hermes_cli.shared_session_attach import configure_tui_attachment env = {"HERMES_TUI_GATEWAY_URL": " "} configure_tui_attachment(env, "same-id", registry_home=home) assert env["HERMES_TUI_GATEWAY_URL"] == reply["websocket_url"] reply["profile_home"] = str(other.resolve()) with pytest.raises(ValueError, match="identity"): discover_attach_url("same-id", registry_home=home) reply["profile_home"] = str(home.resolve()) reply["websocket_url"] = "ws://example.com/api/ws?token=secret" with pytest.raises(ValueError, match="endpoint"): discover_attach_url("same-id", registry_home=home) finally: lease.release() server.shutdown() server.server_close() thread.join() def test_discovery_refuses_unsupported_owner_without_releasing_lease(tmp_path, monkeypatch): from hermes_cli.shared_session_attach import discover_attach_url from hermes_cli.active_sessions import active_session_registry_snapshot lease, error = try_acquire_active_session( session_id="old", surface="desktop", config={}, registry_home=tmp_path, ) assert error is None try: with pytest.raises(ValueError, match="not available in this build") as caught: discover_attach_url("old", registry_home=tmp_path) first, details = str(caught.value).splitlines() assert "hermes --resume old" in first assert details.startswith("Details: ") assert active_session_registry_snapshot(tmp_path)[0]["lease_id"] == lease.lease_id registry = tmp_path / "runtime" / "active_sessions.json" with monkeypatch.context() as patch: # Our own pid is never probed (#108005), so model a FOREIGN owner whose inspection is denied. from hermes_cli.active_sessions import _read_entries, _write_entries entries = _read_entries(registry) entries[0]["pid"] = os.getpid() + 2**22 _write_entries(registry, entries) before = registry.read_bytes() def denied(pid): raise PermissionError("process inspection denied") patch.setattr("gateway.status._pid_exists", denied) with pytest.raises(RuntimeError, match="liveness is unknown"): discover_attach_url("old", registry_home=tmp_path) assert registry.read_bytes() == before finally: lease.release() def test_discovery_failure_message_names_state_and_resume_path(tmp_path): """A refused handshake keeps the lease and points at the working alternative.""" from hermes_cli.shared_session_attach import discover_attach_url class Handler(BaseHTTPRequestHandler): def do_GET(self): self.send_response(500) self.end_headers() def log_message(self, *args): pass server = ThreadingHTTPServer(("127.0.0.1", 0), Handler) thread = threading.Thread(target=server.serve_forever, daemon=True) thread.start() origin = f"http://127.0.0.1:{server.server_port}" lease, error = try_acquire_active_session( session_id="held", surface="desktop", config={}, registry_home=tmp_path, metadata={"live_session_id": "live", "shared_runtime_url": origin}, ) assert error is None try: with pytest.raises(ValueError, match="just failed") as caught: discover_attach_url("held", registry_home=tmp_path) first, details = str(caught.value).splitlines() assert "hermes --resume held" in first assert details.startswith("Details: ") finally: lease.release() server.shutdown() server.server_close() thread.join()