Files
hermes-agent/tests/hermes_cli/test_setup_pin_values.py
ethernet f7561667c7 fix: round-8 CI backlog (Windows-only lane)
- tests/conftest.py: `real_bash` fixture — the Windows runners resolve `bash` to System32's
  WSL launcher (UTF-16 "no installed distributions", exit 1); prefer Git for Windows'. Used
  by the setup-pin, install stage-frame and source-launcher shell tests.
- source-build-env.ps1: Test-Path before Remove-Item — under $ErrorActionPreference='Stop'
  a missing identity variable aborted the try block before the child ran (Windows PS 5.1
  raised where pwsh on Unix did not).
- desktop-update/windows.ps1: `--force` precedes the target arguments (the hand-off contract
  test reads argv in that order).
- test_install_ps1_desktop_stage: assert the current contract — the shared completion tail
  (source_completion.py --desktop) builds the products and -IncludeDesktop selects the desktop
  product inside `products` rather than adding a stage. The test predated the completion-tail
  refactor and had been red on the Windows lane since.
- test_windows_native_support: the restart watcher argv is `runtime_command` shaped
  ([python, -I, -c, bootstrap, pid, delay, ...]).
- test_mint_launchers: create the fixture repo's pm/ dir before copying pm/environments.py.
- test_browser_use_pm: console-script launchers report sys.argv[0] without `.exe`.
- test_update_stale_gateway_yield (from main): `_verify_fleet_after_update` has no
  `node_failures` here (PM owns node).
2026-09-21 06:03:05 -04:00

61 lines
2.5 KiB
Python

"""Cold setup consumes lock values before executing any downloaded tool."""
import json
import os
from pathlib import Path
import shutil
import subprocess
import pytest
from pm.store import current_target
ROOT = Path(__file__).resolve().parents[2]
@pytest.mark.platforms("windows", "posix")
@pytest.mark.parametrize("missing_target", [False, True])
def test_cold_setup_uses_exact_lock_values(tmp_path, missing_target, real_bash):
checkout = tmp_path / "checkout"
(checkout / "pm").mkdir(parents=True)
shutil.copy2(ROOT / "setup-hermes.sh", checkout / "setup-hermes.sh")
# The bootstrap reads the artifact mirror beside the lock before selecting a pin.
shutil.copy2(ROOT / "pm" / "artifact-mirror.json", checkout / "pm" / "artifact-mirror.json")
lock = json.loads((ROOT / "pm" / "lock.json").read_text(encoding="utf-8"))
target = current_target()
uv_pin = lock["packages"]["uv"]
artifact = uv_pin["artifacts"][target]
if missing_target:
del uv_pin["artifacts"][target]
(checkout / "pm" / "lock.json").write_text(json.dumps(lock, indent=2, sort_keys=True) + "\n", encoding="utf-8")
corrupt = tmp_path / "corrupt-download"
corrupt.write_bytes(b"intentional digest mismatch; this must never be executed\n")
args = tmp_path / "curl-args"
hook = tmp_path / "transport.sh"
hook.write_text('''curl() {
printf '%s\\n' "$@" > "$PROBE_ARGS"
while [ "$#" -gt 0 ]; do
if [ "$1" = -o ]; then
cp "$PROBE_DOWNLOAD" "$2"
return
fi
shift
done
return 37
}
''', encoding="utf-8")
env = dict(os.environ, HOME=tmp_path.as_posix(), HERMES_HOME=(tmp_path / "home").as_posix(),
HERMES_RUNTIME_DIR=(tmp_path / "tools").as_posix(), BASH_ENV=hook.as_posix(),
PROBE_ARGS=args.as_posix(), PROBE_DOWNLOAD=corrupt.as_posix())
result = subprocess.run([real_bash, str(checkout / "setup-hermes.sh")], cwd=tmp_path,
env=env, capture_output=True, text=True, encoding="utf-8", timeout=30)
assert result.returncode != 0, result.stdout + result.stderr
if missing_target:
assert not args.exists(), "a missing target must not select a sibling artifact"
assert f"no uv artifact for {target}" in result.stderr
else:
assert args.read_text(encoding="utf-8").splitlines()[-1] == artifact["url"]
assert f"pinned uv {uv_pin['version']} ({target})" in result.stdout
assert f"pinned {artifact['sha256']})" in result.stderr
assert not (checkout / ".env").exists()