Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """P11-T07: Produce final technical evidence package (file-based artifacts).""" | |
| from __future__ import annotations | |
| import datetime | |
| import hashlib | |
| import os | |
| import subprocess | |
| import sys | |
| import tempfile | |
| from pathlib import Path | |
| def sha256_file(path: Path) -> str: | |
| h = hashlib.sha256() | |
| with open(path, "rb") as f: | |
| for chunk in iter(lambda: f.read(65536), b""): | |
| h.update(chunk) | |
| return h.hexdigest() | |
| def main() -> int: | |
| root = Path(__file__).resolve().parents[1] | |
| out_dir = root / "evidence_package" | |
| out_dir.mkdir(exist_ok=True) | |
| ts = datetime.datetime.now(datetime.timezone.utc).strftime("%Y%m%dT%H%M%SZ") | |
| lines = [ | |
| f"# Technical Evidence Package", | |
| f"Generated (UTC): {ts}", | |
| f"Project root: {root}", | |
| "", | |
| "## Safety posture", | |
| "- TRADING_MODE default paper", | |
| "- HERMES_EXECUTION_ENABLED default false", | |
| "- Agent mutation tools unregistered", | |
| "- GAP-001 kill switch closed", | |
| "", | |
| "## Automated checks (full local suite)", | |
| ] | |
| env = os.environ.copy() | |
| env["PYTHONPATH"] = str(root / "hermes_overlay") | |
| # Write test output to a real file rather than a PIPE. Some integration | |
| # subprocesses can inherit pipe descriptors and delay EOF even after the | |
| # pytest parent exits; a temporary file keeps evidence generation bounded. | |
| with tempfile.TemporaryFile(mode="w+t", encoding="utf-8") as test_output: | |
| try: | |
| r = subprocess.run( | |
| [sys.executable, "-m", "pytest", "hermes_overlay/tests", "-vv"], | |
| cwd=str(root), env=env, stdout=test_output, stderr=subprocess.STDOUT, | |
| text=True, timeout=300, | |
| ) | |
| returncode = r.returncode | |
| except subprocess.TimeoutExpired: | |
| returncode = 124 | |
| test_output.write("\nERROR: full local suite exceeded 300 seconds\n") | |
| test_output.seek(0) | |
| captured = test_output.read() | |
| lines.append("```") | |
| lines.append(captured[-2500:] if captured else "") | |
| lines.append(f"exit={returncode}") | |
| lines.append("```") | |
| lines.append("") | |
| # runbook validator | |
| v = subprocess.run([sys.executable, "scripts/validate_runbook_consistency.py", "--skip-evidence-hashes"], | |
| cwd=str(root), capture_output=True, text=True) | |
| lines.append("## Runbook consistency") | |
| lines.append("```") | |
| lines.append(v.stdout) | |
| lines.append("```") | |
| lines.append("") | |
| lines.append("## Key artifact hashes") | |
| for rel in [ | |
| "hermes_overlay/trading/futures_execution.py", | |
| "hermes_overlay/trading/domain/execution_service.py", | |
| "scripts/backup_allowlist.py", | |
| "HERMES_V5_CLOUD_DESKTOP_MASTER_RUNBOOK.md", | |
| ]: | |
| path = root / rel | |
| if path.is_file(): | |
| lines.append(f"- `{rel}`: `{sha256_file(path)}`") | |
| lines.append("") | |
| lines.append("## Deferred (require operator / external)") | |
| lines.append("- OP-P0-01 credential rotation") | |
| lines.append("- OP-P1-01 upstream approval") | |
| lines.append("- P11-T05 Testnet lifecycle") | |
| lines.append("- P11-T06 independent human audit") | |
| lines.append("- P11-T08 program sign-off") | |
| lines.append("- S1-T05/T06 strategy Testnet comparison and approval") | |
| lines.append("") | |
| lines.append("## Release gates") | |
| lines.append("All gates A–F remain NOT_REVIEWED. This package does not approve Testnet or Live.") | |
| report = out_dir / f"evidence_{ts}.md" | |
| report.write_text("\n".join(lines), encoding="utf-8") | |
| latest = out_dir / "EVIDENCE_LATEST.md" | |
| latest.write_text(report.read_text(encoding="utf-8"), encoding="utf-8") | |
| print(f"wrote {report}") | |
| return 0 if returncode == 0 else 1 | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |