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"