#!/usr/bin/env python3 """Functional tests for linear Gitea audit-branch receipt writeback.""" from __future__ import annotations import json import os import subprocess import tempfile import unittest from pathlib import Path ROOT = Path(__file__).resolve().parents[3] SCRIPT = ROOT / "scripts/ci/write-gitea-audit-receipts.sh" CONTROLLER_TARGET = ( "docs/operations/external-mcp-replays/fixture-controller.snapshot.json" ) VERIFIER_TARGET = ( "docs/operations/external-mcp-replays/fixture-verifier.snapshot.json" ) def _run(command: list[str], *, cwd: Path, env: dict[str, str] | None = None) -> str: completed = subprocess.run( command, cwd=cwd, env=env, check=False, capture_output=True, text=True, timeout=30, ) if completed.returncode != 0: raise AssertionError( f"command failed: {command}\nstdout={completed.stdout}\nstderr={completed.stderr}" ) return completed.stdout.strip() def _receipt(schema: str, run_id: str) -> dict: return { "schema_version": schema, "run_id": run_id, "trace_id": f"mcp-replay-{run_id}", "work_item_id": "MCP-REPLAY-PLAYWRIGHT-001", "status": "fixture_verified", } def _write_receipts(directory: Path, run_id: str) -> tuple[Path, Path]: controller = directory / "controller.json" verifier = directory / "verifier.json" controller.write_text( json.dumps( _receipt("awoooi_external_mcp_replay_receipt_v1", run_id), sort_keys=True, ) + "\n", encoding="utf-8", ) verifier.write_text( json.dumps( _receipt("awoooi_external_mcp_replay_verifier_receipt_v1", run_id), sort_keys=True, ) + "\n", encoding="utf-8", ) return controller, verifier class AuditReceiptWritebackTests(unittest.TestCase): def setUp(self) -> None: self.temp = tempfile.TemporaryDirectory() self.root = Path(self.temp.name) self.remote = self.root / "remote.git" self.seed = self.root / "seed" _run(["git", "init", "--bare", str(self.remote)], cwd=self.root) self.seed.mkdir() _run(["git", "init"], cwd=self.seed) _run(["git", "config", "user.email", "fixture@awoooi.internal"], cwd=self.seed) _run(["git", "config", "user.name", "Fixture"], cwd=self.seed) (self.seed / "base.txt").write_text("base\n", encoding="utf-8") _run(["git", "add", "base.txt"], cwd=self.seed) _run(["git", "commit", "-m", "base"], cwd=self.seed) _run(["git", "branch", "-M", "main"], cwd=self.seed) _run(["git", "remote", "add", "origin", f"file://{self.remote}"], cwd=self.seed) _run(["git", "push", "origin", "main"], cwd=self.seed) _run(["git", "checkout", "-b", "mcp-replay-receipts"], cwd=self.seed) initial_controller, initial_verifier = _write_receipts( self.seed, "00000000-0000-4000-8000-000000000000" ) (self.seed / CONTROLLER_TARGET).parent.mkdir(parents=True) (self.seed / CONTROLLER_TARGET).write_bytes(initial_controller.read_bytes()) (self.seed / VERIFIER_TARGET).write_bytes(initial_verifier.read_bytes()) _run(["git", "add", "docs"], cwd=self.seed) _run(["git", "commit", "-m", "initial audit receipt"], cwd=self.seed) _run(["git", "push", "origin", "mcp-replay-receipts"], cwd=self.seed) self.initial_audit_sha = _run(["git", "rev-parse", "HEAD"], cwd=self.seed) _run(["git", "checkout", "main"], cwd=self.seed) (self.seed / "main-only.txt").write_text("new main\n", encoding="utf-8") _run(["git", "add", "main-only.txt"], cwd=self.seed) _run(["git", "commit", "-m", "advance main"], cwd=self.seed) _run(["git", "push", "origin", "main"], cwd=self.seed) def tearDown(self) -> None: self.temp.cleanup() def _fresh_main_clone(self, name: str) -> Path: clone = self.root / name _run( [ "git", "clone", "--depth=1", "--branch", "main", f"file://{self.remote}", str(clone), ], cwd=self.root, ) _run(["git", "config", "user.email", "fixture@awoooi.internal"], cwd=clone) _run(["git", "config", "user.name", "Fixture"], cwd=clone) return clone def _apply(self, clone: Path, run_id: str) -> str: source_dir = self.root / f"source-{run_id}" source_dir.mkdir() controller, verifier = _write_receipts(source_dir, run_id) env = { **os.environ, "GIT_TERMINAL_PROMPT": "0", "GITEA_AUDIT_TEST_FILE_REMOTE": "1", "GITEA_AUDIT_REMOTE_URL": f"file://{self.remote}", "GITEA_AUDIT_BRANCH": "mcp-replay-receipts", "GITEA_AUDIT_CONTROLLER_SOURCE": str(controller), "GITEA_AUDIT_VERIFIER_SOURCE": str(verifier), "GITEA_AUDIT_CONTROLLER_TARGET": CONTROLLER_TARGET, "GITEA_AUDIT_VERIFIER_TARGET": VERIFIER_TARGET, "GITEA_AUDIT_COMMIT_MESSAGE": "fixture audit receipt", } return _run(["bash", str(SCRIPT)], cwd=clone, env=env) def test_second_and_third_writebacks_are_linear_normal_pushes(self) -> None: first_clone = self._fresh_main_clone("clone-one") first_output = self._apply( first_clone, "11111111-1111-4111-8111-111111111111" ) self.assertIn("receipt_writeback=verified_audit_branch_normal_push", first_output) first_sha = _run( ["git", "--git-dir", str(self.remote), "rev-parse", "mcp-replay-receipts"], cwd=self.root, ) first_parent = _run( ["git", "--git-dir", str(self.remote), "rev-parse", f"{first_sha}^"], cwd=self.root, ) self.assertEqual(first_parent, self.initial_audit_sha) second_clone = self._fresh_main_clone("clone-two") second_output = self._apply( second_clone, "22222222-2222-4222-8222-222222222222" ) self.assertIn("receipt_writeback=verified_audit_branch_normal_push", second_output) second_sha = _run( ["git", "--git-dir", str(self.remote), "rev-parse", "mcp-replay-receipts"], cwd=self.root, ) second_parent = _run( ["git", "--git-dir", str(self.remote), "rev-parse", f"{second_sha}^"], cwd=self.root, ) self.assertEqual(second_parent, first_sha) latest = _run( [ "git", "--git-dir", str(self.remote), "show", f"mcp-replay-receipts:{CONTROLLER_TARGET}", ], cwd=self.root, ) self.assertEqual( json.loads(latest)["run_id"], "22222222-2222-4222-8222-222222222222", ) def test_non_allowlisted_branch_is_rejected_without_push(self) -> None: clone = self._fresh_main_clone("clone-rejected") source_dir = self.root / "source-rejected" source_dir.mkdir() controller, verifier = _write_receipts( source_dir, "33333333-3333-4333-8333-333333333333" ) env = { **os.environ, "GITEA_AUDIT_TEST_FILE_REMOTE": "1", "GITEA_AUDIT_REMOTE_URL": f"file://{self.remote}", "GITEA_AUDIT_BRANCH": "main", "GITEA_AUDIT_CONTROLLER_SOURCE": str(controller), "GITEA_AUDIT_VERIFIER_SOURCE": str(verifier), "GITEA_AUDIT_CONTROLLER_TARGET": CONTROLLER_TARGET, "GITEA_AUDIT_VERIFIER_TARGET": VERIFIER_TARGET, "GITEA_AUDIT_COMMIT_MESSAGE": "must not commit", } completed = subprocess.run( ["bash", str(SCRIPT)], cwd=clone, env=env, check=False, capture_output=True, text=True, timeout=30, ) self.assertEqual(completed.returncode, 2) self.assertIn("audit_writeback_branch_not_allowlisted", completed.stdout) def test_branch_and_receipt_directory_must_match(self) -> None: clone = self._fresh_main_clone("clone-mismatched-target") source_dir = self.root / "source-mismatched-target" source_dir.mkdir() controller, verifier = _write_receipts( source_dir, "44444444-4444-4444-8444-444444444444" ) env = { **os.environ, "GITEA_AUDIT_TEST_FILE_REMOTE": "1", "GITEA_AUDIT_REMOTE_URL": f"file://{self.remote}", "GITEA_AUDIT_BRANCH": "mcp-artifact-receipts", "GITEA_AUDIT_CONTROLLER_SOURCE": str(controller), "GITEA_AUDIT_VERIFIER_SOURCE": str(verifier), "GITEA_AUDIT_CONTROLLER_TARGET": CONTROLLER_TARGET, "GITEA_AUDIT_VERIFIER_TARGET": VERIFIER_TARGET, "GITEA_AUDIT_COMMIT_MESSAGE": "must not commit", } completed = subprocess.run( ["bash", str(SCRIPT)], cwd=clone, env=env, check=False, capture_output=True, text=True, timeout=30, ) self.assertEqual(completed.returncode, 2) self.assertIn("audit_writeback_branch_target_mismatch", completed.stdout) def test_controller_and_verifier_identity_must_match(self) -> None: clone = self._fresh_main_clone("clone-mismatched-identity") source_dir = self.root / "source-mismatched-identity" source_dir.mkdir() controller, verifier = _write_receipts( source_dir, "55555555-5555-4555-8555-555555555555" ) verifier_payload = json.loads(verifier.read_text(encoding="utf-8")) verifier_payload["run_id"] = "66666666-6666-4666-8666-666666666666" verifier.write_text( json.dumps(verifier_payload, sort_keys=True) + "\n", encoding="utf-8" ) env = { **os.environ, "GITEA_AUDIT_TEST_FILE_REMOTE": "1", "GITEA_AUDIT_REMOTE_URL": f"file://{self.remote}", "GITEA_AUDIT_BRANCH": "mcp-replay-receipts", "GITEA_AUDIT_CONTROLLER_SOURCE": str(controller), "GITEA_AUDIT_VERIFIER_SOURCE": str(verifier), "GITEA_AUDIT_CONTROLLER_TARGET": CONTROLLER_TARGET, "GITEA_AUDIT_VERIFIER_TARGET": VERIFIER_TARGET, "GITEA_AUDIT_COMMIT_MESSAGE": "must not commit", } completed = subprocess.run( ["bash", str(SCRIPT)], cwd=clone, env=env, check=False, capture_output=True, text=True, timeout=30, ) self.assertEqual(completed.returncode, 2) self.assertIn("audit_writeback_receipt_identity_mismatch", completed.stdout) if __name__ == "__main__": unittest.main()