Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """Verify deterministic source-build equivalence without requiring Docker. | |
| Two isolated copies are created from the same source tree, compiled, subjected | |
| to a focused startup/build smoke suite, and compared using normalized manifests. | |
| Container-image equivalence remains a separate Desktop/CI check. | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import hashlib | |
| import json | |
| import os | |
| import shutil | |
| import subprocess | |
| import sys | |
| import tempfile | |
| from pathlib import Path | |
| ROOT = Path(__file__).resolve().parents[1] | |
| SKIP_NAMES = { | |
| ".git", ".pytest_cache", "__pycache__", ".coverage", "coverage.json", "coverage.xml", | |
| "node_modules", ".venv", "venv", "dist", "build", "evidence_package", | |
| } | |
| SMOKE_TESTS = ( | |
| "hermes_overlay/tests/test_build_reproducibility.py", | |
| "hermes_overlay/tests/test_config_validation.py", | |
| "hermes_overlay/tests/test_upstream_integration_preflight.py", | |
| "hermes_overlay/tests/test_repository_build_metadata.py", | |
| ) | |
| def _ignore(_directory: str, names: list[str]) -> set[str]: | |
| return {name for name in names if name in SKIP_NAMES or name.endswith((".pyc", ".pyo"))} | |
| def _sha256_lines(lines: list[str]) -> str: | |
| return hashlib.sha256(("\n".join(lines) + "\n").encode("utf-8")).hexdigest() | |
| def _manifest(root: Path) -> list[str]: | |
| lines: list[str] = [] | |
| for path in sorted(root.rglob("*")): | |
| if not path.is_file() or any(part in SKIP_NAMES for part in path.relative_to(root).parts): | |
| continue | |
| if path.suffix in {".pyc", ".pyo"}: | |
| continue | |
| digest = hashlib.sha256(path.read_bytes()).hexdigest() | |
| lines.append(f"{digest} {path.relative_to(root).as_posix()}") | |
| return lines | |
| def _run(command: list[str], cwd: Path) -> dict[str, object]: | |
| env = os.environ.copy() | |
| env["PYTHONPATH"] = str(cwd / "hermes_overlay") | |
| env["TRADING_MODE"] = "paper" | |
| env["HERMES_EXECUTION_ENABLED"] = "false" | |
| env["HERMES_NONPAPER_EXECUTION_ENABLED"] = "false" | |
| result = subprocess.run(command, cwd=cwd, env=env, text=True, capture_output=True) | |
| return { | |
| "command": command, | |
| "returncode": result.returncode, | |
| "stdout": result.stdout[-4000:], | |
| "stderr": result.stderr[-4000:], | |
| } | |
| def verify(root: Path = ROOT, *, run_smoke: bool = True) -> dict[str, object]: | |
| root = root.resolve() | |
| with tempfile.TemporaryDirectory(prefix="hermes-clean-build-") as tmp: | |
| base = Path(tmp) | |
| copies = [base / "build-a", base / "build-b"] | |
| results: list[dict[str, object]] = [] | |
| manifests: list[list[str]] = [] | |
| for copy in copies: | |
| shutil.copytree(root, copy, ignore=_ignore) | |
| commands = [ | |
| [sys.executable, "-m", "compileall", "-q", "app.py", "hermes_overlay", "scripts"], | |
| ] | |
| if run_smoke: | |
| commands.append([sys.executable, "-m", "pytest", "-q", *SMOKE_TESTS]) | |
| command_results = [_run(command, copy) for command in commands] | |
| failed = [item for item in command_results if item["returncode"] != 0] | |
| if failed: | |
| raise RuntimeError(f"clean build smoke failed in {copy.name}: {failed[0]}") | |
| manifests.append(_manifest(copy)) | |
| results.append({"copy": copy.name, "commands": command_results}) | |
| equivalent = manifests[0] == manifests[1] | |
| if not equivalent: | |
| only_a = sorted(set(manifests[0]) - set(manifests[1]))[:20] | |
| only_b = sorted(set(manifests[1]) - set(manifests[0]))[:20] | |
| raise RuntimeError(f"clean build manifests diverged: only_a={only_a}, only_b={only_b}") | |
| return { | |
| "schemaVersion": 1, | |
| "equivalent": True, | |
| "manifestEntries": len(manifests[0]), | |
| "manifestSha256": _sha256_lines(manifests[0]), | |
| "python": sys.version.split()[0], | |
| "smokeTests": list(SMOKE_TESTS) if run_smoke else [], | |
| "builds": results, | |
| "allowedNondeterminism": [ | |
| "temporary directory paths", | |
| "pytest timing output", | |
| "Python bytecode/cache files excluded from normalized manifest", | |
| "container layer timestamps verified separately in Docker-capable CI", | |
| ], | |
| } | |
| def main(argv: list[str] | None = None) -> int: | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--root", default=str(ROOT)) | |
| parser.add_argument("--output", default="evidence_package/clean_build_equivalence.json") | |
| parser.add_argument("--no-smoke", action="store_true") | |
| args = parser.parse_args(argv) | |
| try: | |
| result = verify(Path(args.root), run_smoke=not args.no_smoke) | |
| except (OSError, RuntimeError, subprocess.SubprocessError) as exc: | |
| print(f"ERROR: {exc}", file=sys.stderr) | |
| return 1 | |
| output = Path(args.output) | |
| if not output.is_absolute(): | |
| output = Path(args.root) / output | |
| output.parent.mkdir(parents=True, exist_ok=True) | |
| output.write_text(json.dumps(result, indent=2, sort_keys=True) + "\n", encoding="utf-8") | |
| print(f"clean_build_equivalence=PASS entries={result['manifestEntries']} sha256={result['manifestSha256']}") | |
| return 0 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |