"""B-3 — the herdr pre-flight must probe for the real BINARY. Two independent bypasses make the obvious one-liners useless once lib.sh is sourced: * ``command -v herdr`` matches the ``herdr()`` shell FUNCTION (lib.sh:498). * ``type -P herdr`` matches ``$WORKSPACE_ROOT/.mam/shim/herdr``, because ``_init_herdr_isolation`` runs at source time (lib.sh bottom) and prepends that dir to PATH. So a host with no herdr installed at all passes pre-flight, and the failure is deferred to a confusing runtime error from the shim. """ import os import stat import subprocess import pytest # A PATH with no herdr anywhere. Kept deliberately minimal so a herdr that # happens to be installed on the developer's box cannot mask a regression. BARE_PATH = "/usr/bin:/bin:/usr/sbin:/sbin" def _bash(sandbox, snippet, path=BARE_PATH, extra_env=None): env = dict(os.environ) env["PATH"] = path env["WORKSPACE_ROOT"] = str(sandbox) if extra_env: env.update(extra_env) script = f'source "{sandbox}/.agents/skills/lib.sh" >/dev/null 2>&1\n{snippet}' return subprocess.run(["bash", "-c", script], capture_output=True, text=True, cwd=str(sandbox), env=env) def _make_herdr(directory): directory.mkdir(parents=True, exist_ok=True) exe = directory / "herdr" exe.write_text("#!/bin/sh\necho fake herdr\n") exe.chmod(exe.stat().st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH) return exe # W-1 — document the two bypasses so a future refactor cannot silently # "simplify" has_real_herdr back into one of them. def test_b3_command_v_and_type_p_both_falsely_report_herdr(mam_sandbox): res = _bash(mam_sandbox, """ command -v herdr >/dev/null && echo "command-v:MATCH" || echo "command-v:miss" echo "type-t:$(type -t herdr)" type -P herdr >/dev/null 2>&1 && echo "type-P:MATCH($(type -P herdr))" || echo "type-P:miss" """) assert "command-v:MATCH" in res.stdout, res.stdout assert "type-t:function" in res.stdout, res.stdout assert "type-P:MATCH" in res.stdout, res.stdout assert "/.mam/shim/herdr" in res.stdout, \ f"type -P was expected to resolve the shim wrapper:\n{res.stdout}" # W-2 — has_real_herdr must be FALSE when no binary is installed def test_b3_has_real_herdr_false_without_binary(mam_sandbox): res = _bash(mam_sandbox, 'if has_real_herdr; then echo RESULT:TRUE; else echo RESULT:FALSE; fi') assert "RESULT:FALSE" in res.stdout, \ f"has_real_herdr passed with no herdr binary:\n{res.stdout}\n{res.stderr}" # W-3 — ... and TRUE when one is, resolving past the shim def test_b3_has_real_herdr_true_with_binary(mam_sandbox): real = _make_herdr(mam_sandbox / "realbin") res = _bash(mam_sandbox, 'if has_real_herdr; then echo RESULT:TRUE; else echo RESULT:FALSE; fi\n' 'echo "RESOLVED:$(_resolve_real_herdr_path)"', path=f"{mam_sandbox / 'realbin'}:{BARE_PATH}") assert "RESULT:TRUE" in res.stdout, f"{res.stdout}\n{res.stderr}" assert f"RESOLVED:{real}" in res.stdout, \ f"resolved the shim instead of the real binary:\n{res.stdout}" # W-4 — a herdr that only exists inside a wrapper/shim dir does not count @pytest.mark.parametrize("dirname", ["my-shim", "multi-agent-herdr-shim"]) def test_b3_shim_directories_do_not_satisfy_preflight(mam_sandbox, dirname): _make_herdr(mam_sandbox / dirname) res = _bash(mam_sandbox, 'if has_real_herdr; then echo RESULT:TRUE; else echo RESULT:FALSE; fi', path=f"{mam_sandbox / dirname}:{BARE_PATH}") assert "RESULT:FALSE" in res.stdout, \ f"a herdr inside wrapper dir '{dirname}' was accepted:\n{res.stdout}" # W-5 — create_session.sh pre-flight must actually FAIL without a binary. # This is the defect B-3 names. def test_b3_create_session_preflight_fails_without_herdr(mam_sandbox): script = mam_sandbox / ".agents" / "skills" / "multi-agent-mux-create" / "scripts" / "create_session.sh" env = dict(os.environ) env["PATH"] = BARE_PATH env["WORKSPACE_ROOT"] = str(mam_sandbox) res = subprocess.run( ["bash", str(script), "--workspace", str(mam_sandbox), "--agent", "claude", "--role", "worker"], capture_output=True, text=True, cwd=str(mam_sandbox), env=env) assert res.returncode != 0, \ f"pre-flight passed with no herdr installed:\n{res.stdout}\n{res.stderr}" assert "herdr not installed" in (res.stdout + res.stderr), \ f"failed, but not on the herdr pre-flight:\n{res.stdout}\n{res.stderr}" # W-6 — and must still pass the herdr gate when a binary IS present. # (It may fail later on the agent-CLI gate; that is a different check.) def test_b3_create_session_preflight_passes_herdr_gate_with_binary(mam_sandbox): _make_herdr(mam_sandbox / "realbin") script = mam_sandbox / ".agents" / "skills" / "multi-agent-mux-create" / "scripts" / "create_session.sh" env = dict(os.environ) env["PATH"] = f"{mam_sandbox / 'realbin'}:{BARE_PATH}" env["WORKSPACE_ROOT"] = str(mam_sandbox) res = subprocess.run( ["bash", str(script), "--workspace", str(mam_sandbox), "--agent", "claude", "--role", "worker"], capture_output=True, text=True, cwd=str(mam_sandbox), env=env) assert "herdr not installed" not in (res.stdout + res.stderr), \ f"herdr gate rejected a real binary:\n{res.stdout}\n{res.stderr}" # W-7 — the sharpest statement of B-3: with the agent CLI present and ONLY # herdr missing, pre-flight must stop on the herdr gate. This is the # test that is genuinely red before the fix without naming any new # helper, so it measures the defect rather than the implementation. def test_b3_preflight_stops_on_herdr_gate_when_only_herdr_is_missing(mam_sandbox): agentbin = mam_sandbox / "agentbin" agentbin.mkdir(parents=True, exist_ok=True) for name in ("claude",): exe = agentbin / name exe.write_text('#!/bin/sh\necho \'{"loggedIn": true}\'\n') exe.chmod(exe.stat().st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH) script = mam_sandbox / ".agents" / "skills" / "multi-agent-mux-create" / "scripts" / "create_session.sh" env = dict(os.environ) env["PATH"] = f"{agentbin}:{BARE_PATH}" # claude yes, herdr no env["WORKSPACE_ROOT"] = str(mam_sandbox) res = subprocess.run( ["bash", str(script), "--workspace", str(mam_sandbox), "--agent", "claude", "--role", "worker"], capture_output=True, text=True, cwd=str(mam_sandbox), env=env, timeout=120) combined = res.stdout + res.stderr assert "herdr not installed" in combined, ( "pre-flight did not stop on the herdr gate even though herdr is absent.\n" f"rc={res.returncode}\n--- stdout ---\n{res.stdout}\n--- stderr ---\n{res.stderr}") # W-8 — symlink bypass: a link in an ORDINARY bin dir pointing at the shim. # No directory-name pattern can reject this; only the resolved target # reveals it. def test_b3_symlink_into_shim_is_rejected(mam_sandbox): _bash(mam_sandbox, "true") # materialise the shim shim = mam_sandbox / ".mam" / "shim" / "herdr" assert shim.exists(), "shim wrapper was not created by _init_herdr_isolation" linkdir = mam_sandbox / "usrlocalbin" linkdir.mkdir(parents=True, exist_ok=True) (linkdir / "herdr").symlink_to(shim) res = _bash(mam_sandbox, 'if has_real_herdr; then echo RESULT:TRUE; else echo RESULT:FALSE; fi', path=f"{linkdir}:{BARE_PATH}") assert "RESULT:FALSE" in res.stdout, ( "a symlink pointing into .mam/shim was accepted as a real herdr:\n" f"{res.stdout}\n{res.stderr}") # W-9 — ... but a symlink to a REAL binary must still be accepted, so the # canonicalisation cannot be a blanket "reject all symlinks". def test_b3_symlink_to_real_binary_is_accepted(mam_sandbox): real = _make_herdr(mam_sandbox / "realbin") linkdir = mam_sandbox / "linkbin" linkdir.mkdir(parents=True, exist_ok=True) (linkdir / "herdr").symlink_to(real) res = _bash(mam_sandbox, 'if has_real_herdr; then echo RESULT:TRUE; else echo RESULT:FALSE; fi', path=f"{linkdir}:{BARE_PATH}") assert "RESULT:TRUE" in res.stdout, \ f"a symlink to a genuine herdr was rejected:\n{res.stdout}\n{res.stderr}" # W-10 — a bare relative PATH entry '.mam/shim' (no leading '/' or './') must # still be rejected. Requires normalising the dir with a leading slash. def test_b3_bare_relative_shim_entry_is_rejected(mam_sandbox): _bash(mam_sandbox, "true") # materialise the shim res = _bash(mam_sandbox, 'if has_real_herdr; then echo RESULT:TRUE; else echo RESULT:FALSE; fi', path=f".mam/shim:{BARE_PATH}") assert "RESULT:FALSE" in res.stdout, ( "a bare relative '.mam/shim' PATH entry was accepted:\n" f"{res.stdout}\n{res.stderr}")