Files
multi-agent-mux/tests/test_herdr_real_server_leak.py
GodopuandClaude Opus 5.5 db7f4cab9c test(sandbox): mam_sandbox also drops HERDR_SESSION (reviews 63919c5d / 191f0ec3, non-blocking)
The caller-server helpers read it, so tests branched on whether they ran in
an agent pane. L2 covers it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
2026-10-13 10:01:55 +09:00

89 lines
3.5 KiB
Python

"""Tests must not reach a real herdr server (found 2026-10-12).
A suite run from an agent pane with --basetemp .../pytest-pr56-shim left seven
workspaces on that pane's real server. Two causes, one test each:
- L1: the real-herdr resolvers skipped every PATH directory with "-shim"
anywhere in its path, so the basetemp hid the mock's bin/ and the real
herdr ran;
- L2: the sandbox kept the pane's HERDR_SOCKET_PATH, which the real herdr
follows over the sandbox HOME.
"""
import os
import subprocess
import pytest
DECOY = "#!/bin/sh\necho \"$@\" >> \"$DECOY_LOG\"\necho '{}'\n"
def test_l1_ancestor_named_shim_does_not_hide_the_mock(mam_sandbox, mock_herdr):
tmp = mam_sandbox
# The mock's bin/ under an ancestor named *-shim, as under that basetemp.
mock_bin = tmp / "pytest-x-shim" / "case0" / "bin"
mock_bin.mkdir(parents=True)
(mock_bin / "herdr").symlink_to(tmp / "bin" / "herdr")
# A decoy next in PATH stands in for the real herdr: with the old match it
# is what ran. The real herdr is never reached either way.
decoy_bin = tmp / "decoy" / "bin"
decoy_bin.mkdir(parents=True)
(decoy_bin / "herdr").write_text(DECOY)
(decoy_bin / "herdr").chmod(0o755)
decoy_log = tmp / "decoy.log"
env = dict(os.environ, PATH=f"{mock_bin}:{decoy_bin}:{os.environ['PATH']}",
DECOY_LOG=str(decoy_log))
lib = tmp / ".agents" / "skills" / "lib.sh"
script = f"""
source "{lib}"
_init_herdr_isolation
_resolve_real_herdr_path
"$WORKSPACE_ROOT/.mam/shim/herdr" workspace list >/dev/null
"""
res = subprocess.run(["bash", "-c", script], capture_output=True, text=True,
cwd=str(tmp), env=env)
assert res.returncode == 0, res.stderr
# lib.sh's resolver picks the mock's directory, not the decoy.
assert res.stdout.strip().splitlines()[0] == f"{mock_bin}/herdr", res.stdout
# The generated shim ran the mock too.
assert not decoy_log.exists(), decoy_log.read_text()
def test_l1_a_directory_named_shim_is_still_skipped(mam_sandbox, mock_herdr):
"""A wrapper directory that is itself *-shim stays excluded."""
tmp = mam_sandbox
wrapper = tmp / "herdr-shim"
wrapper.mkdir()
(wrapper / "herdr").write_text(DECOY)
(wrapper / "herdr").chmod(0o755)
decoy_log = tmp / "decoy.log"
env = dict(os.environ, PATH=f"{wrapper}:{os.environ['PATH']}", DECOY_LOG=str(decoy_log))
lib = tmp / ".agents" / "skills" / "lib.sh"
script = f"""
source "{lib}"
_init_herdr_isolation
_resolve_real_herdr_path
"$WORKSPACE_ROOT/.mam/shim/herdr" workspace list >/dev/null
"""
res = subprocess.run(["bash", "-c", script], capture_output=True, text=True,
cwd=str(tmp), env=env)
assert res.returncode == 0, res.stderr
assert res.stdout.strip().splitlines()[0] == f"{tmp}/bin/herdr", res.stdout
assert not decoy_log.exists(), decoy_log.read_text()
PANE_VARS = {"HERDR_SOCKET_PATH": "/nonexistent/sessions/real/herdr.sock",
"HERDR_PANE_ID": "w9:p1", "HERDR_TAB_ID": "w9:t1",
"HERDR_WORKSPACE_ID": "w9", "HERDR_SESSION_NAME": "real",
"HERDR_SESSION": "real"}
@pytest.fixture
def _agent_pane_env(monkeypatch):
"""What an agent pane on a named server carries; set before mam_sandbox."""
for k, v in PANE_VARS.items():
monkeypatch.setenv(k, v)
def test_l2_sandbox_drops_the_pane_routing(_agent_pane_env, mam_sandbox):
left = sorted(k for k in PANE_VARS if k in os.environ)
assert left == [], left