"""Tests for scripts/verify-bootstrap-version-stamp.py. The bootstrap installers stamp ``.hermes-bootstrap-complete`` with the commit/branch they pinned; this script reads the stamp back and cross-checks it against the installed checkout. Tests build a real temp git repo, write stamps by hand, and verify the honest and lying cases. """ from __future__ import annotations import importlib.util import json import os import shutil import subprocess import sys from pathlib import Path import pytest def _git_exe() -> str: """A git CreateProcess can start. conftest blanks SystemRoot/ComSpec and this host's PATH can resolve `git` to the MSIX payload copy under ``C:\\Program Files\\WindowsApps\\...`` — WinError 5 outside its package context. Prefer a conventional install.""" candidates = [hit for hit in (shutil.which("git"),) if hit] if sys.platform == "win32": base = Path(os.environ.get("ProgramFiles", r"C:\Program Files")) / "Git" for rel in (("cmd", "git.exe"), ("bin", "git.exe")): p = base.joinpath(*rel) if p.exists(): candidates.append(str(p)) for cand in candidates: if "windowsapps" not in cand.lower(): return cand return candidates[0] _GIT = _git_exe() def _git(repo: Path, *args: str) -> str: env = os.environ.copy() if sys.platform == "win32": env.setdefault("SystemRoot", r"C:\Windows") env.setdefault("ComSpec", r"C:\Windows\system32\cmd.exe") out = subprocess.run( [_GIT, *args], cwd=repo, capture_output=True, text=True, check=True, env=env ) return out.stdout.strip() _SCRIPT = Path(__file__).resolve().parents[2] / "scripts" / "verify-bootstrap-version-stamp.py" def _install_repo(tmp_path: Path) -> Path: """A minimal 'installed checkout': git repo + the source identity stamp.""" repo = tmp_path / "install" repo.mkdir() _git(repo, "init", "-b", "main") _git(repo, "config", "user.email", "ci@example.com") _git(repo, "config", "user.name", "ci") (repo / "hermes_cli").mkdir() (repo / "hermes_cli" / "__init__.py").write_text( '"""Hermes CLI."""\n', encoding="utf-8") _git(repo, "add", "-A") _git(repo, "commit", "-m", "seed") (repo / "install-stamp.json").write_text(json.dumps({ "schemaVersion": 2, "commit": _git(repo, "rev-parse", "HEAD"), "baseVersion": "0.1.2", "updateMechanism": "self", }), encoding="utf-8") return repo @pytest.mark.parametrize("changes,expect,error", [ ({}, [], None), ({"pinnedCommit": "a" * 40}, [], "installed HEAD"), ({}, ["--expect-commit", "b" * 40], "expected"), ({}, ["--expect-branch", "release"], "pinnedBranch"), ({"schemaVersion": 2}, [], "schemaVersion"), ({"pinnedCommit": "deadbeef"}, [], "40-char"), ({"completedAt": "not-a-time"}, [], "ISO-8601"), ({"completedAt": "2026-08-30T12:00:00+01:00"}, [], "not UTC"), ({"missing": "stamp"}, [], "cannot read stamp"), ({"missing": "version"}, [], "no source identity stamp"), ({"canonicalCommit": "c" * 40}, [], "canonical"), # A checkout with no reachable release tag honestly stamps a null base. ({"canonicalBase": None}, [], None), # The protocol lane never runs the products stage that writes the stamp. ({"missing": "version"}, ["--no-source-stamp"], None), ]) def test_verifier_cli(tmp_path, changes, expect, error): repo = _install_repo(tmp_path) stamp = {"schemaVersion": 1, "pinnedCommit": _git(repo, "rev-parse", "HEAD"), "pinnedBranch": "main", "completedAt": "2026-08-30T12:00:00.000Z", **changes} path = repo / ".hermes-bootstrap-complete" if changes.get("missing") != "stamp": path.write_text(json.dumps(stamp), encoding="utf-8") if changes.get("missing") == "version": (repo / "install-stamp.json").unlink() if "canonicalCommit" in changes or "canonicalBase" in changes: canonical = json.loads((repo / "install-stamp.json").read_text(encoding="utf-8")) canonical["commit"] = changes.get("canonicalCommit", canonical["commit"]) canonical["baseVersion"] = changes.get("canonicalBase", canonical["baseVersion"]) (repo / "install-stamp.json").write_text(json.dumps(canonical), encoding="utf-8") if not error: expect = ["--expect-commit", stamp["pinnedCommit"], "--expect-branch", "main", *expect] env = dict(os.environ) if os.name == "nt": env.setdefault("SystemRoot", r"C:\Windows") env.setdefault("ComSpec", r"C:\Windows\system32\cmd.exe") result = subprocess.run([sys.executable, str(_SCRIPT), "--repo", str(repo), "--stamp", str(path), *expect], env=env, capture_output=True, text=True, timeout=30) assert result.returncode == (1 if error else 0), result.stderr assert error in result.stderr if error else "stamp verified" in result.stdout