"""The PreToolUse hook's pure helpers. The decision paths are exercised live.""" import importlib.util from pathlib import Path import pytest spec = importlib.util.spec_from_file_location( "zerto_guard_hook", Path(__file__).resolve().parent.parent / "hooks" / "zerto_guard_hook.py" ) hook = importlib.util.module_from_spec(spec) spec.loader.exec_module(hook) @pytest.mark.parametrize( ("tool_name", "expected"), [ ("mcp__ssh__exec", ("ssh", "exec")), ("mcp__winrm__run_ps", ("winrm", "run_ps")), # server names may themselves contain underscores; split on the FIRST __ ("mcp__plugin_my_thing__write_file", ("plugin_my_thing", "write_file")), ("mcp__ob1__OB1__search_thoughts", ("ob1", "OB1__search_thoughts")), ("Bash", None), ("", None), ], ) def test_split_mcp_name(tool_name, expected): assert hook.split_mcp_name(tool_name) == expected def test_resolve_vm_prefers_the_catalog_arg(): assert hook.resolve_vm({"host": "a", "computer_name": "b"}, "computer_name") == "b" def test_resolve_vm_falls_back_when_catalog_arg_is_wrong(): # a slightly wrong catalog entry should degrade to a prompt, not a crash assert hook.resolve_vm({"computer_name": "web01"}, "host") == "web01" def test_resolve_vm_returns_empty_when_no_vm_present(): assert hook.resolve_vm({"command": "ls"}, "host") == "" def test_emit_with_no_decision_and_no_context_exits_silently(capsys): with pytest.raises(SystemExit) as exc: hook.emit(None) assert exc.value.code == 0 assert capsys.readouterr().out == "" def test_emit_deny_shape(capsys): import json with pytest.raises(SystemExit) as exc: hook.emit("deny", "no checkpoint") assert exc.value.code == 0 # exit 2 would discard the JSON and lose the reason out = json.loads(capsys.readouterr().out)["hookSpecificOutput"] assert out["hookEventName"] == "PreToolUse" assert out["permissionDecision"] == "deny" assert out["permissionDecisionReason"] == "no checkpoint" def test_emit_context_without_decision(capsys): import json with pytest.raises(SystemExit): hook.emit(None, context="checkpoint 7180") out = json.loads(capsys.readouterr().out)["hookSpecificOutput"] assert "permissionDecision" not in out assert out["additionalContext"] == "checkpoint 7180"