Files
awoooi/scripts/reboot-recovery/tests/test_windows99_vmx_source_backup_search.py
ogt a636fa5b11
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m12s
CD Pipeline / build-and-deploy (push) Successful in 7m4s
AWOOOI Harbor 110 Local Repair / workflow-shape (push) Successful in 1s
AWOOOI Harbor 110 Local Repair / harbor-110-local-repair (push) Successful in 19s
CD Pipeline / post-deploy-checks (push) Has been cancelled
fix(reboot): automate windows99 backup search receipt
2026-07-09 17:10:32 +08:00

256 lines
7.8 KiB
Python

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