test_gs_paste_security.py python
95 lines 3.3 KB
Raw
sha256:0e9549ec7b463911bc08b7d586dc320b1ac9b1f5c943ee7e3865dcc6cb0f6f83 chore(governance): sync handover+roadmap to 84db8c8 (drift:… Human 2 days ago
1 """Security tests for GS-PASTE NEXT regen (§GSP.10 security)."""
2
3 from __future__ import annotations
4
5 from pathlib import Path
6
7 from adapters.config import load_config
8 from tests.support import FIXTURES, make_runner, ok, run_cli, write_config
9 from tools.governance_hygiene.next_regen import discover_freeze_candidates
10 from tools.governance_hygiene.patch import build_handover_patches
11 from tools.governance_hygiene.types import DriftReport, VerifiedReads
12 from cli.kit_root import kit_root
13
14
15 def test_shell_metacharacters_only_in_markdown_text(tmp_path: Path) -> None:
16 config = load_config(FIXTURES / "config-git-only.yaml")
17 roadmap = (
18 "# Roadmap\n\n## Build queue\n\n"
19 "| Phase | Model | Status | Deliverable |\n"
20 "| --- | --- | --- | --- |\n"
21 "| **SAFE** | Auto | **NEXT** | `$(rm -rf /)` ; `touch /tmp/x` |\n"
22 )
23 handover = (FIXTURES / "gs-paste-handover.md").read_text(encoding="utf-8")
24 drift = DriftReport(
25 d1_handover_vs_git="drifted",
26 d2_anchor_vs_canonical="aligned",
27 d3_queue_vs_merged="aligned",
28 )
29 reads = VerifiedReads(
30 regime="git-only",
31 r1_github_main_sha="cafebabe",
32 r1_command="git",
33 r2_anchor_sha="cafebabe",
34 r2_source="origin/main",
35 r3_canonical_main_sha=None,
36 r3_command=None,
37 r4_merged_prs=(),
38 r5_branch="main",
39 r5_dirty=False,
40 r5_regime="git-only",
41 )
42 patched, sections, token = build_handover_patches(
43 handover,
44 reads,
45 drift,
46 realign_summary=None,
47 sync_date="2026-07-30",
48 config=config,
49 roadmap_text=roadmap,
50 repo_root=tmp_path,
51 )
52 assert token == "next_regen: regenerated"
53 assert "next-session" in sections
54 assert "$(rm -rf /)" in patched
55 # Never interpolated into a shell context — only markdown fence/body text.
56 assert "os.system" not in patched
57
58
59 def test_path_escape_outside_docs_rejected(tmp_path: Path) -> None:
60 outside = tmp_path / "secret.md"
61 outside.write_text("```yaml\nreview_stamp:\n verdict: pass\n```\n", encoding="utf-8")
62 docs = tmp_path / "docs"
63 docs.mkdir()
64 found = discover_freeze_candidates(
65 tmp_path,
66 "ESCAPE",
67 "`../secret.md` and `docs/../../../etc/passwd`",
68 )
69 assert found == []
70
71
72 def test_git_only_fixture_never_invokes_muse(tmp_path: Path) -> None:
73 write_config(tmp_path, "config-git-only.yaml")
74 docs = tmp_path / "docs"
75 docs.mkdir(parents=True, exist_ok=True)
76 (docs / "OVERSEER-HANDOVER.md").write_text(
77 (FIXTURES / "gs-paste-handover.md").read_text(encoding="utf-8"),
78 encoding="utf-8",
79 )
80 (docs / "ROADMAP.md").write_text(
81 (FIXTURES / "gs-paste-roadmap-one-open.md").read_text(encoding="utf-8"),
82 encoding="utf-8",
83 )
84 runner = make_runner(
85 {
86 "git rev-parse --abbrev-ref HEAD": ok("main"),
87 "git status --porcelain": ok(""),
88 "git rev-parse origin/main": ok("cafebabe"),
89 "gh pr list": ok("[]"),
90 "git remote get-url origin": ok("[email protected]:owner/repo.git"),
91 }
92 )
93 code = run_cli(["governance-sync"], cwd=tmp_path, runner=runner, kit=kit_root())
94 assert code == 0
95 assert not any("muse" in call[0].lower() for call in runner.calls)
File History 1 commit
sha256:6abcf1fa82a7a621ccbc945f19acdba5bc0db54569599404a1452fb4a096a199 fix(ISR): default require_independent_second_reviewer to require Human minor 2 days ago