test_land_closeout_integrity.py python
106 lines 3.5 KB
Raw
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1 docs: MuseHub-first before ISR #74 — staging solidify NEXT Human 1 day ago
1 """Data integrity: land-closeout never writes; CI template never applies to main
2 (§PMHF.10 data-integrity)."""
3
4 from __future__ import annotations
5
6 import json
7 from pathlib import Path
8
9 from cli.kit_root import kit_root
10 from tests.support import (
11 KIT_ROOT,
12 git_status_runner,
13 make_runner,
14 ok,
15 run_cli,
16 seed_land_repo,
17 )
18
19 CI_TEMPLATE = KIT_ROOT / "templates" / "ci" / "governance-closeout-github-actions.yml"
20
21
22 def _doc_bytes(tmp_path: Path) -> dict[str, bytes]:
23 docs = tmp_path / "docs"
24 return {p.name: p.read_bytes() for p in sorted(docs.glob("*.md"))}
25
26
27 def test_status_and_land_closeout_never_write_docs(tmp_path: Path, capsys) -> None:
28 seed_land_repo(tmp_path, claim="deadbeef") # drifted → both surfaces report failure
29 before = _doc_bytes(tmp_path)
30 marker_before = (tmp_path / ".overseer" / "last_governance_sync").read_bytes()
31
32 assert (
33 run_cli(
34 ["status", "--json", "--exit-code"],
35 cwd=tmp_path,
36 runner=git_status_runner(tip="cafebabe"),
37 json_mode=True,
38 )
39 == 2
40 )
41 assert (
42 run_cli(
43 ["land-closeout", "--json"],
44 cwd=tmp_path,
45 runner=git_status_runner(tip="cafebabe"),
46 json_mode=True,
47 )
48 == 2
49 )
50 capsys.readouterr()
51
52 assert _doc_bytes(tmp_path) == before
53 assert (tmp_path / ".overseer" / "last_governance_sync").read_bytes() == marker_before
54
55
56 def test_land_closeout_idempotent(tmp_path: Path, capsys) -> None:
57 seed_land_repo(tmp_path, claim="deadbeef")
58 outputs = []
59 for _ in range(2):
60 capsys.readouterr()
61 code = run_cli(
62 ["land-closeout", "--json"],
63 cwd=tmp_path,
64 runner=git_status_runner(tip="cafebabe"),
65 json_mode=True,
66 )
67 assert code == 2
68 outputs.append(json.loads(capsys.readouterr().out))
69 assert outputs[0] == outputs[1]
70
71
72 def test_ci_template_has_no_apply_to_main_step() -> None:
73 text = CI_TEMPLATE.read_text(encoding="utf-8")
74 active_lines = [
75 line for line in text.splitlines() if line.strip() and not line.strip().startswith("#")
76 ]
77 active = "\n".join(active_lines)
78 assert "git push" not in active # frozen ban: never pushes from the workflow
79 assert "--write" not in active # governance-sync stays dry-run in CI
80 assert "governance-sync --dry-run" in active
81 assert "land-closeout --probe-merged-pr" in active
82 assert "workflow_dispatch" in active
83 assert "contents: read" in active # read-only checkout — cannot write main
84
85
86 def test_dry_run_governance_sync_still_only_stamps_marker(tmp_path: Path) -> None:
87 # GFG carve-out unchanged: aligned dry-run stamps the local marker only.
88 seed_land_repo(tmp_path, claim="cafebabe", marker_tip=None)
89 before = _doc_bytes(tmp_path)
90 runner = make_runner(
91 {
92 "git rev-parse --abbrev-ref HEAD": ok("main"),
93 "git status --porcelain": ok(""),
94 "git rev-parse origin/main": ok("cafebabe"),
95 "gh pr list --state merged --limit 5 --json number,title,mergeCommit,mergedAt": ok(
96 "[]"
97 ),
98 "git remote get-url origin": ok("[email protected]:owner/repo.git"),
99 }
100 )
101 code = run_cli(["governance-sync"], cwd=tmp_path, runner=runner, kit=kit_root())
102 assert code == 0
103 assert _doc_bytes(tmp_path) == before # no governance-doc writes on dry-run
104 marker = tmp_path / ".overseer" / "last_governance_sync"
105 assert marker.is_file()
106 assert "r1=cafebabe" in marker.read_text(encoding="utf-8")
File History 1 commit
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1 docs: MuseHub-first before ISR #74 — staging solidify NEXT Human 1 day ago