Files
hermes-agent/tests/scripts/test_bootstrap_mirror.py
ethernet cb7c688171 test: mirror the source tree for 27 misfiled root tests; one PM home fixture
Root-level tests/ is for root-level modules; 19 files testing scripts/, 3 testing
pm/ and 5 testing hermes_cli/ move to the mirrored directory (workflow file lists
and cross-imports updated; path arithmetic bumped one level).

tests/pm gains a conftest with the isolated_machine_home fixture that seven
modules had copy-pasted verbatim.
2026-09-18 20:13:26 -04:00

172 lines
7.8 KiB
Python

"""Real bootstrap downloads preserve the pin across an upstream outage."""
import hashlib
import io
import json
import os
from pathlib import Path
import shutil
import subprocess
import tarfile
import threading
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
import pytest
ROOT = Path(__file__).resolve().parents[2]
@pytest.fixture
def server():
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.server.requests.append(self.path)
body = self.server.files.get(self.path)
self.send_response(200 if body is not None else 404)
self.send_header("Content-Length", str(len(body or b"")))
self.end_headers()
self.wfile.write(body or b"")
def log_message(self, *_args):
pass
http = ThreadingHTTPServer(("127.0.0.1", 0), Handler)
http.files, http.requests = {}, []
thread = threading.Thread(target=http.serve_forever, daemon=True)
thread.start()
try:
yield http, f"http://127.0.0.1:{http.server_port}"
finally:
http.shutdown()
http.server_close()
thread.join(timeout=5)
def fixture_bytes(server, mode, body):
http, base = server
if mode != "missing":
http.files["/primary"] = b"bad bytes" if mode == "corrupt" else body
http.files["/mirror"] = body
return base + "/primary", base + "/mirror", hashlib.sha256(body).hexdigest()
@pytest.mark.platforms("windows")
@pytest.mark.parametrize("mode", ["primary", "missing", "corrupt", "both-missing"])
def test_windows_download_uses_only_verified_candidates(tmp_path, server, mode):
body = b"exact archive bytes"
primary, mirror, digest = fixture_bytes(server, mode, body)
if mode == "both-missing":
server[0].files.clear()
destination = tmp_path / "out.zip"
script = tmp_path / "driver.ps1"
script.write_text(
f". '{ROOT / 'scripts/install.ps1'}' -HermesHome '{tmp_path / 'home'}' -InstallDir '{tmp_path / 'repo'}'\n"
f"Invoke-VerifiedDownload -Url '{primary}' -MirrorUrl '{mirror}' -Sha256 '{digest}' -OutFile '{destination}'\n",
encoding="utf-8",
)
result = subprocess.run(["powershell", "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", str(script)],
capture_output=True, text=True, timeout=60)
if mode in ("primary", "missing"):
assert result.returncode == 0, result.stdout + result.stderr
assert destination.read_bytes() == body
else:
assert result.returncode != 0
assert primary in result.stdout + result.stderr
if mode == "both-missing":
assert mirror in result.stdout + result.stderr
assert server[0].requests == (["/primary", "/mirror"] if mode in ("missing", "both-missing") else ["/primary"])
@pytest.mark.platforms("windows")
@pytest.mark.parametrize("name", ["uv", "git"])
def test_windows_bootstrap_rejects_corrupt_bytes_before_extract(tmp_path, server, name):
primary, mirror, digest = fixture_bytes(server, "corrupt", b"expected archive")
script = tmp_path / "caller.ps1"
script.write_text(
f". '{ROOT / 'scripts/install.ps1'}' -HermesHome '{tmp_path / 'home'}'\n"
f"$env:HERMES_RUNTIME_DIR = '{tmp_path / 'tools'}'\n"
"function Get-Command { param($Name) return $null }\n"
"$target = 'win32-' + (Get-WindowsArch)\n"
f"$pin = @{{Url='{primary}'; MirrorUrl='{mirror}'; Sha256='{digest}'}}\n"
+ ("$script:UvPinFiles[$target] = $pin\nGet-Uv\n" if name == "uv" else "$script:GitPinFiles[$target] = $pin\nGet-PinnedGit\n"),
encoding="utf-8",
)
result = subprocess.run(["powershell", "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", str(script)],
capture_output=True, text=True, timeout=60)
assert result.returncode != 0
assert "digest mismatch" in result.stdout + result.stderr
assert server[0].requests == ["/primary"]
assert not (tmp_path / "tools").exists()
def uv_archive():
data = b"#!/bin/sh\n[ \"$1\" = --version ] && { printf 'fixture uv\\n'; exit 0; }; exit 73\n"
buffer = io.BytesIO()
with tarfile.open(fileobj=buffer, mode="w:gz") as archive:
member = tarfile.TarInfo("uv/uv")
member.mode, member.size = 0o755, len(data)
archive.addfile(member, io.BytesIO(data))
return buffer.getvalue()
@pytest.mark.platforms("posix")
@pytest.mark.parametrize("mode", ["primary", "missing", "corrupt", "both-missing"])
def test_posix_download_keeps_the_pinned_hash(tmp_path, server, mode):
primary, mirror, digest = fixture_bytes(server, mode, uv_archive())
if mode == "both-missing":
server[0].files.clear()
script = f"""
source '{ROOT / 'scripts/install.sh'}'
command() {{ if [ "$*" = '-v uv' ]; then return 1; fi; builtin command "$@"; }}
uv_bootstrap_pin() {{ UV_PIN_VERSION=fixture; UV_PIN_URL='{primary}'; UV_PIN_MIRROR='{mirror}'; UV_PIN_SHA256='{digest}'; }}
ensure_uv
"""
env = {**os.environ, "HERMES_HOME": str(tmp_path / "home"), "HOME": str(tmp_path / "home"), "HERMES_RUNTIME_DIR": str(tmp_path / "tools")}
result = subprocess.run(["bash", "-c", script], cwd=tmp_path, env=env, capture_output=True, text=True, timeout=60)
assert (result.returncode == 0) == (mode in ("primary", "missing")), result.stdout + result.stderr
if mode == "corrupt":
assert "digest mismatch" in result.stderr
if mode == "both-missing":
assert primary in result.stderr and mirror in result.stderr
assert server[0].requests == (["/primary", "/mirror"] if mode in ("missing", "both-missing") else ["/primary"])
@pytest.mark.platforms("windows")
def test_generated_windows_pins_match_the_shared_authority(tmp_path):
from pm.artifact_mirror import mirror_url
script = tmp_path / "pins.ps1"
script.write_text(
f". '{ROOT / 'scripts/install.ps1'}' -HermesHome '{tmp_path / 'home'}'\n"
"@{uv=$script:UvPinFiles; git=$script:GitPinFiles} | ConvertTo-Json -Depth 5 -Compress\n",
encoding="utf-8",
)
result = subprocess.run(["powershell", "-NoProfile", "-NonInteractive", "-File", str(script)], capture_output=True, text=True, timeout=30)
assert result.returncode == 0, result.stderr
emitted = json.loads(result.stdout)
lock = json.loads((ROOT / "pm/lock.json").read_text(encoding="utf-8"))["packages"]
for name, targets in emitted.items():
assert targets
for target, pin in targets.items():
authority = lock[name]["artifacts"][target]
assert (pin["Url"], pin["Sha256"], pin["MirrorUrl"]) == (authority["url"], authority["sha256"], mirror_url(authority["sha256"]))
@pytest.mark.platforms("posix")
def test_dev_setup_reaches_the_same_mirror_without_python(tmp_path, server):
from pm.store import current_target
body = uv_archive()
digest = hashlib.sha256(body).hexdigest()
http, base = server
http.files["/archive/" + digest] = body
repo = tmp_path / "repo"
(repo / "pm").mkdir(parents=True)
shutil.copyfile(ROOT / "setup-hermes.sh", repo / "setup-hermes.sh")
(repo / "pm/artifact-mirror.json").write_text(json.dumps({"origin": base, "prefix": "archive/"}, indent=2), encoding="utf-8")
(repo / "pm/lock.json").write_text(json.dumps({"packages": {
"uv": {"version": "fixture", "artifacts": {current_target(): {"url": base + "/missing.tar.gz", "sha256": digest}}},
"python": {"version": "3.14.7"},
}}, indent=2, sort_keys=True), encoding="utf-8")
env = {**os.environ, "HERMES_HOME": str(tmp_path / "home"), "HOME": str(tmp_path / "home"), "HERMES_RUNTIME_DIR": str(tmp_path / "tools")}
result = subprocess.run(["bash", str(repo / "setup-hermes.sh")], cwd=repo, env=env, text=True, capture_output=True, timeout=60)
assert result.returncode == 73, result.stdout + result.stderr # stop at the bootstrap interpreter boundary
assert http.requests == ["/missing.tar.gz", "/archive/" + digest]