Files
hermes-agent/tests/hermes_cli/test_shared_session_attach.py
kshitijk4poor 0caf219aaf fix(tui): drop the no-op drain reset; model a foreign owner in the denied-inspection attach test
Gate r2: resetting last_bot_poll after a started delivery never re-polled early (the next
tick re-probes while the turn is still running), so the plumbing is gone and the 5 s cadence
is stated plainly. test_shared_session_attach denied inspection for the test's own pid, which
the self-pid skip (#108005) legitimately never probes — it now denies a foreign owner.
2026-09-20 15:16:35 +05:30

132 lines
5.3 KiB
Python

"""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()