"""Focused tests for Hermes-to-Herdr routing and the shared auth patch.""" from __future__ import annotations import importlib.util import sys from pathlib import Path import pytest import yaml SCRIPTS = Path(__file__).parents[2] / "services/hermes/scripts" HERMES = Path(__file__).parents[2] / "services/hermes" def _load(name: str): spec = importlib.util.spec_from_file_location(name, SCRIPTS / f"{name}.py") assert spec and spec.loader module = importlib.util.module_from_spec(spec) sys.modules[spec.name] = module spec.loader.exec_module(module) return module dispatch = _load("herdr_dispatch") auth_patch = _load("patch_hermes_auth") def test_herdr_plan_chooses_task_shape_and_caps_effort(): status = { "routes": { "codex-high": [ "openai-codex/gpt-5.6-sol", "anthropic/claude-opus-5", "custom/qwen2.5:14b-instruct-q4_0", ], "claude-medium": [ "anthropic/claude-sonnet-5", "openai-codex/gpt-5.6-terra", ], } } implementation = dispatch.select_plan(status, "implementation", "high") architecture = dispatch.select_plan(status, "architecture", "medium") assert implementation["worker"] == "codex" assert implementation["model"] == "gpt-5.6-sol" assert architecture["worker"] == "claude" assert architecture["model"] == "claude-sonnet-5" with pytest.raises(ValueError, match="effort"): dispatch.select_plan(status, "review", "max") def test_claude_worker_waits_for_prompt_readiness(tmp_path: Path, monkeypatch): herdr = tmp_path / "herdr" herdr.touch() project = tmp_path / "project" project.mkdir() calls = [] def fake_run(command, env): calls.append(command) if command[1:3] == ["workspace", "create"]: return {"result": {"root_pane": {"pane_id": "w2:p1"}}} return {"result": {"ok": True}} monkeypatch.setattr(dispatch, "HERDR_BIN", herdr) monkeypatch.setattr(dispatch, "_run", fake_run) plan = { "worker": "claude", "model": "claude-haiku-4-5-20251001", "effort": "low", } dispatch.launch_worker(plan, project, "review", "Check the implementation.") ready = calls[-2] assert ready[1:] == [ "pane", "wait-output", "w2:p1", "--match", "accept edits on", "--source", "recent", "--lines", "120", "--timeout", "120000", ] prompt = calls[-1] assert prompt[1:5] == [ "agent", "prompt", "claude-review", "Check the implementation.", ] assert prompt[-9:] == [ "--wait", "--until", "working", "--until", "done", "--until", "blocked", "--timeout", "15000", ] def test_auth_patch_honors_explicit_shared_store(tmp_path: Path): source = tmp_path / "auth.py" destination = tmp_path / "patched" / "auth.py" source.write_text( "from pathlib import Path\nimport os\n\n" "def _auth_file_path() -> Path:\n" " path = get_hermes_home() / \"auth.json\"\n" " return path\n", encoding="utf-8", ) auth_patch.patch(source, destination) content = destination.read_text(encoding="utf-8") assert 'os.environ.get("HERMES_AUTH_FILE"' in content assert "Path(configured)" in content def test_auth_patch_fails_closed_on_upstream_drift(tmp_path: Path): source = tmp_path / "auth.py" source.write_text("def changed():\n pass\n", encoding="utf-8") with pytest.raises(RuntimeError, match="context changed"): auth_patch.patch(source, tmp_path / "patched.py") def test_agent_ttyd_defers_identity_to_owner_only_oauth_boundary(): deployment = yaml.safe_load((HERMES / "agent-deployment.yaml").read_text()) containers = deployment["spec"]["template"]["spec"]["containers"] ttyd = next(container for container in containers if container["name"] == "herdr-tui") command = ttyd["args"][0] assert "--check-origin" in command assert "--auth-header" not in command oauth_documents = [ document for document in yaml.safe_load_all((HERMES / "oauth2-proxy.yaml").read_text()) if document ] oauth = next( document for document in oauth_documents if document["kind"] == "Deployment" and document["metadata"]["name"] == "oauth2-proxy-hermes-agent" ) oauth_args = oauth["spec"]["template"]["spec"]["containers"][0]["args"] assert "--authenticated-emails-file=/etc/oauth2-proxy/allowed-emails" in oauth_args assert "--proxy-websockets=true" in oauth_args network_documents = [ document for document in yaml.safe_load_all((HERMES / "networkpolicy.yaml").read_text()) if document ] isolation = next( document for document in network_documents if document["kind"] == "NetworkPolicy" and document["metadata"]["name"] == "hermes-agent-isolation" ) ingress = isolation["spec"]["ingress"] assert ingress == [ { "from": [{"podSelector": {"matchLabels": {"app": "oauth2-proxy-hermes-agent"}}}], "ports": [{"protocol": "TCP", "port": 7681}], } ] def test_agent_installs_hermes_integration_before_startup(): deployment = yaml.safe_load((HERMES / "agent-deployment.yaml").read_text()) pod = deployment["spec"]["template"]["spec"] init_config = next( container for container in pod["initContainers"] if container["name"] == "init-config" ) assert "ln -s /opt/data /opt/data/home/.hermes" in init_config["command"][-1] installer = next( container for container in pod["initContainers"] if container["name"] == "install-herdr-integrations" ) command = installer["command"][-1] assert "herdr integration install codex" in command assert "herdr integration install claude" in command assert "herdr integration install hermes" in command assert "|| true" not in command containers = {container["name"]: container for container in pod["containers"]} for name in ("herdr-tui", "herdr-server"): env = {item["name"]: item["value"] for item in containers[name]["env"]} assert "/opt/hermes/.venv/bin" in env["PATH"].split(":") server_command = containers["herdr-server"]["command"][-1] assert 'herdr pane process-info --pane "${pane}"' in server_command assert 'herdr workspace close "${workspace}"' in server_command assert 'item.get("label") == "coordinator"' in server_command assert 'item["workspace_id"] != active' in server_command assert 'herdr workspace close "${stale_workspace}"' in server_command assert "herdr agent start coordinator" in server_command assert "--kind hermes" in server_command assert "--timeout 60000" in server_command def test_agent_mounts_auto_router_into_both_hermes_runtimes(): deployment = yaml.safe_load((HERMES / "agent-deployment.yaml").read_text()) pod = deployment["spec"]["template"]["spec"] containers = {container["name"]: container for container in pod["containers"]} for name in ("hermes", "herdr-server"): mounts = { mount["mountPath"]: mount["name"] for mount in containers[name]["volumeMounts"] } assert mounts["/opt/data/plugins/auto-router"] == "auto-router-plugin" volume = next( item for item in pod["volumes"] if item["name"] == "auto-router-plugin" ) assert volume["configMap"]["name"] == "hermes-auto-router-plugin" def test_agent_coordinator_has_a_long_running_tool_budget(): configmap = yaml.safe_load((HERMES / "agent-configmap.yaml").read_text()) config = yaml.safe_load(configmap["data"]["config.yaml"]) assert config["agent"]["max_turns"] == 180 assert config["tool_loop_guardrails"]["hard_stop_enabled"] is True