72 lines
2.6 KiB
Python
72 lines
2.6 KiB
Python
import json
|
|
from pathlib import Path
|
|
|
|
from zerto_rewind_mcp.catalog import CatalogEntry, MutatingCatalog, entry_from_dict
|
|
|
|
|
|
def test_add_and_get(tmp_path: Path):
|
|
path = tmp_path / "config.json"
|
|
path.write_text(
|
|
json.dumps({"zerto_url": "https://zvm", "mutating_tools": []}),
|
|
encoding="utf-8",
|
|
)
|
|
cat = MutatingCatalog(path=path)
|
|
cat.add(CatalogEntry(server="ssh", tool="exec", vm_arg="host", notes="guest shell"))
|
|
found = cat.get("SSH", "Exec")
|
|
assert found is not None
|
|
assert found.vm_arg == "host"
|
|
saved = json.loads(path.read_text(encoding="utf-8"))
|
|
assert saved["zerto_url"] == "https://zvm"
|
|
assert saved["mutating_tools"][0]["tool"] == "exec"
|
|
|
|
|
|
def test_unlisted_is_missing():
|
|
cat = MutatingCatalog()
|
|
assert cat.get("foo", "bar") is None
|
|
|
|
|
|
def test_entry_requires_fields():
|
|
try:
|
|
entry_from_dict({"server": "ssh"})
|
|
raise AssertionError("expected ValueError")
|
|
except ValueError:
|
|
pass
|
|
|
|
|
|
def test_example_config_covers_windows_and_linux():
|
|
"""The starter catalog must not be Linux-only.
|
|
|
|
The catalog is opt-in: an unlisted tool passes through unguarded. A
|
|
Windows-only shop taking the shipped defaults would therefore mutate
|
|
protected guests with no checkpoint at all.
|
|
"""
|
|
example = Path(__file__).resolve().parent.parent / "config.example.json"
|
|
data = json.loads(example.read_text(encoding="utf-8"))
|
|
cat = MutatingCatalog.from_config(data)
|
|
assert cat.get("ssh", "exec") is not None
|
|
assert cat.get("winrm", "run_command") is not None
|
|
assert cat.get("winrm", "run_ps") is not None
|
|
assert cat.get("powershell", "invoke_command") is not None
|
|
# every entry must name the arg holding the VM, or the guard cannot resolve one
|
|
for entry in cat.list():
|
|
assert entry.vm_arg, f"{entry.server}/{entry.tool} has no vm_arg"
|
|
|
|
|
|
def test_classify_three_way():
|
|
data = {
|
|
"mutating_tools": [{"server": "winrm", "tool": "run_ps", "vm_arg": "host"}],
|
|
"read_only_tools": [{"server": "ssh", "tool": "read_file"}],
|
|
}
|
|
cat = MutatingCatalog.from_config(data)
|
|
assert cat.classify("winrm", "run_ps") == "mutating"
|
|
assert cat.classify("SSH", "Read_File") == "read_only"
|
|
# unknown is not safe; it means nobody classified it
|
|
assert cat.classify("anything", "else") == "unknown"
|
|
|
|
|
|
def test_read_only_entries_need_no_vm_arg():
|
|
data = {"read_only_tools": [{"server": "ssh", "tool": "stat"}]}
|
|
cat = MutatingCatalog.from_config(data)
|
|
assert cat.classify("ssh", "stat") == "read_only"
|
|
assert [e.tool for e in cat.read_only()] == ["stat"]
|