Files
hermes-agent/tests/test_install_ps1_managed_python_provenance.py
ethernet 712734436e fix(pm): make bootstrap and bundle ownership explicit
Finish bootstrap uv before PM replaces its store entry. Keep failure
receipts stdlib-only and align the cryptography requirement and override
with the locked version.

Let bundle builders declare launch paths and update ownership. Remove
payload discovery, Store probing, and the unused develop command.
Derive Nix Python from the PM lock and share its provenance stamp.

Document setup, activation, optional dependencies, and distribution
ownership. Targeted Windows tests, relocated runtime launches, Electron
bundling, and bilingual docs builds pass. Native Nix and signed-package
acceptance remain CI gates.
2026-09-08 00:24:51 -04:00

72 lines
3.3 KiB
Python

"""The real installer waits for bootstrap uv before it delegates to PM."""
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import pytest
pytestmark = pytest.mark.platforms("windows")
INSTALLER = Path(__file__).resolve().parents[1] / "scripts" / "install.ps1"
@pytest.mark.parametrize("exit_code", [0, 17])
def test_python_stage_delegates_to_pin_without_touching_existing_env(tmp_path, exit_code):
powershell = shutil.which("powershell")
assert powershell
install = tmp_path / "install with spaces"
package = install / "pm"
package.mkdir(parents=True)
(package / "lock.json").write_text(json.dumps({"packages": {"python": {"version": "3.12.8+fixture"}}}), encoding="utf-8")
(package / "__init__.py").write_text("", encoding="utf-8")
(package / "cli.py").write_text(
"import json, os, pathlib, sys\n"
"assert not pathlib.Path(os.environ['UV_BUSY']).exists()\n"
"pathlib.Path(os.environ['PM_LOG']).write_text(json.dumps(sys.argv[1:]))\n"
"sys.exit(int(os.environ['PROBE_EXIT']))\n", encoding="utf-8",
)
existing = install / "venv" / "sentinel"
existing.parent.mkdir()
existing.write_text("previous generation", encoding="utf-8")
log = tmp_path / "uv-calls.jsonl"
pm_log = tmp_path / "pm-call.json"
wrapper = tmp_path / "boundary.ps1"
wrapper.write_text(r'''
param([string]$Installer, [string]$InstallDir, [string]$HomeDir, [string]$Log)
$ErrorActionPreference = 'Stop'
function uv {
Set-Content -Path $env:UV_BUSY -Value 'running'
try {
ConvertTo-Json -Compress -InputObject @($args) | Add-Content -Encoding UTF8 $Log
switch ($args[1]) {
'install' { }
'find' { Write-Output $env:BOOTSTRAP_PYTHON }
default { throw 'PM must not be a child of the bootstrap uv' }
}
$global:LASTEXITCODE = 0
} finally { Remove-Item $env:UV_BUSY }
}
function Invoke-WebRequest { throw 'network access outside test boundary' }
. $Installer -InstallDir $InstallDir -HermesHome $HomeDir
# Dot-sourcing defines Get-Uv, so override only that acquisition boundary.
function Get-Uv { return 'uv' }
Invoke-StageByName 'python-deps'
exit $LASTEXITCODE
''', encoding="utf-8-sig")
# uv python find returns the distribution interpreter, not a venv launcher.
env = dict(os.environ, PROBE_EXIT=str(exit_code), BOOTSTRAP_PYTHON=sys._base_executable,
PM_LOG=str(pm_log), UV_BUSY=str(tmp_path / "uv-busy"), PATHEXT=".COM;.EXE;.BAT;.CMD")
env.pop("PYTHONPATH", None)
run = subprocess.run([powershell, "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", str(wrapper),
"-Installer", str(INSTALLER), "-InstallDir", str(install), "-HomeDir", str(tmp_path / "home"), "-Log", str(log)],
cwd=tmp_path, env=env, stdin=subprocess.DEVNULL,
capture_output=True, text=True, timeout=120)
assert (run.returncode == 0) == (exit_code == 0), run.stdout + run.stderr
assert [json.loads(line) for line in log.read_text(encoding="utf-8-sig").splitlines()] == [
["python", "install", "--no-bin", "3.12"], ["python", "find", "--managed-python", "3.12"],
]
assert json.loads(pm_log.read_text(encoding="utf-8-sig")) == ["install"]
assert existing.read_text(encoding="utf-8-sig") == "previous generation"