from __future__ import annotations import os import json import subprocess import textwrap from pathlib import Path ROOT = Path(__file__).resolve().parents[3] SCRIPT = ( ROOT / "scripts" / "reboot-recovery" / "collect-windows99-vmx-source-backup-search.sh" ) RECEIPT_BUILDER = ( ROOT / "scripts" / "reboot-recovery" / "build-windows99-vmx-source-backup-search-receipt.py" ) def _write_executable(path: Path, text: str) -> None: path.write_text(textwrap.dedent(text).lstrip()) path.chmod(0o755) def _key_values(stdout: str) -> dict[str, str]: values: dict[str, str] = {} for line in stdout.splitlines(): if "=" not in line or line.startswith("HOST_SEARCH "): continue key, value = line.split("=", 1) values[key] = value return values def test_backup_search_collector_is_no_secret_no_content_check_mode() -> None: text = SCRIPT.read_text(encoding="utf-8") assert "windows99_vmx_source_backup_search_collector_v1" in text assert "BatchMode=yes" in text assert "PreferredAuthentications=publickey" in text assert "PasswordAuthentication=no" in text assert "KbdInteractiveAuthentication=no" in text assert "NumberOfPasswordPrompts=0" in text assert "path_fingerprint_only=true" in text assert "file_content_read=false" in text assert "remote_write_performed=false" in text for forbidden in [ "sshpass", "PasswordAuthentication=yes", "KbdInteractiveAuthentication=yes", "scp ", "sudo ", "cat \"$candidate_path\"", "Get-Content", "Start-VM", "vmrun start", "shutdown", "Restart-Computer", "Set-Content", "Copy-Item", "Move-Item", "Remove-Item", ]: assert forbidden not in text def test_backup_search_collector_emits_fingerprints_not_paths(tmp_path: Path) -> None: fake_bin = tmp_path / "bin" fake_bin.mkdir() _write_executable( fake_bin / "ssh", """ #!/usr/bin/env bash target="${@: -2:1}" if [[ "$target" == *"blocked"* ]]; then exit 255 fi printf '%s\n' 'fp-one' printf '%s\n' 'fp-two' """, ) env = os.environ.copy() env["PATH"] = f"{fake_bin}:{env['PATH']}" env["WINDOWS99_VMX_BACKUP_SEARCH_KNOWN_HOSTS_FILE"] = str( fake_bin / "known_hosts" ) result = subprocess.run( [ "bash", str(SCRIPT), "--hosts", "ok=wooo@ok,blocked=wooo@blocked", "--timeout", "3", ], cwd=ROOT, env=env, capture_output=True, text=True, check=False, ) assert result.returncode == 0 values = _key_values(result.stdout) assert values["schema_version"] == "windows99_vmx_source_backup_search_collector_v1" assert values["target_vm_alias"] == "111" assert values["candidate_source_count"] == "2" assert values["searched_host_count"] == "1" assert values["blocked_host_count"] == "1" assert "HOST_SEARCH alias=ok status=searched candidate_source_count=2" in result.stdout assert "HOST_SEARCH alias=blocked status=blocked_ssh_batchmode_unavailable" in ( result.stdout ) assert "path_fingerprints=fp-one,fp-two" in result.stdout assert "192.168.0." not in result.stdout assert "/home/wooo" not in result.stdout assert "file_content_read=false" in result.stdout assert "remote_write_performed=false" in result.stdout assert "vm_power_change_performed=false" in result.stdout def test_backup_search_collector_resolves_bare_aliases_and_blocks_unknown( tmp_path: Path, ) -> None: fake_bin = tmp_path / "bin" fake_bin.mkdir() _write_executable( fake_bin / "ssh", """ #!/usr/bin/env bash target="${@: -2:1}" if [[ "$target" == *"blocked"* ]]; then exit 255 fi printf '%s\n' 'fp-alias' """, ) env = os.environ.copy() env["PATH"] = f"{fake_bin}:{env['PATH']}" env["WINDOWS99_VMX_BACKUP_SEARCH_KNOWN_HOSTS_FILE"] = str( fake_bin / "known_hosts" ) env["WINDOWS99_VMX_BACKUP_SEARCH_HOST_DIRECTORY"] = ( "ok=wooo@ok,blocked=wooo@blocked" ) result = subprocess.run( [ "bash", str(SCRIPT), "--hosts", "ok,blocked,missing", "--timeout", "3", ], cwd=ROOT, env=env, capture_output=True, text=True, check=False, ) assert result.returncode == 0 values = _key_values(result.stdout) assert values["candidate_source_count"] == "1" assert values["searched_host_count"] == "1" assert values["blocked_host_count"] == "2" assert "HOST_SEARCH alias=ok status=searched candidate_source_count=1" in result.stdout assert "HOST_SEARCH alias=blocked status=blocked_ssh_batchmode_unavailable" in ( result.stdout ) assert "HOST_SEARCH alias=missing status=blocked_host_alias_unresolved" in ( result.stdout ) def test_backup_search_receipt_builder_projects_collector_stdout_safely( tmp_path: Path, ) -> None: collector_output = tmp_path / "collector.txt" collector_output.write_text( textwrap.dedent( """ schema_version=windows99_vmx_source_backup_search_collector_v1 search_hosts=110=wooo@192.168.0.110,120=wooo@192.168.0.120 secret_value_read=false file_content_read=false raw_path_output=false HOST_SEARCH alias=110 status=blocked_ssh_batchmode_unavailable candidate_source_count=0 path_fingerprints= HOST_SEARCH alias=120 status=searched candidate_source_count=2 path_fingerprints=abc12345,def67890 candidate_source_count=2 search_status=candidate_fingerprint_found_requires_internal_path_resolution """ ).strip() + "\n", encoding="utf-8", ) locator_receipt = tmp_path / "locator.json" locator_receipt.write_text( json.dumps( { "schema_version": "windows99_vmx_source_locator_receipt_v1", "collector_readback_present": True, "locate_status": "blocked_missing_expected_vmx_source_no_candidate_found", "candidate_source_count_known": True, "candidate_source_count": 0, "candidate_source_fingerprint_count": 0, } ), encoding="utf-8", ) result = subprocess.run( [ "python3", str(RECEIPT_BUILDER), "--collector-output", str(collector_output), "--locator-receipt", str(locator_receipt), "--generated-at", "2026-07-09T17:10:00+08:00", "--stdout", ], cwd=ROOT, capture_output=True, text=True, check=True, ) payload = json.loads(result.stdout) assert payload["schema_version"] == "windows99_vmx_source_backup_search_receipt_v1" assert payload["collector_readback_present"] is True assert payload["searched_host_count"] == 1 assert payload["blocked_host_count"] == 2 assert payload["candidate_source_count"] == 2 assert payload["candidate_source_fingerprint_count"] == 2 assert payload["search_status"] == ( "candidate_fingerprint_found_requires_internal_path_resolution" ) assert payload["raw_path_output"] is False assert payload["path_fingerprint_only"] is True assert payload["file_content_read"] is False assert payload["secret_value_read"] is False assert payload["remote_write_performed"] is False assert payload["vm_power_change_performed"] is False assert "192.168.0." not in result.stdout assert "D:\\" not in result.stdout assert "/Users/" not in result.stdout