From 35a7f4bec48fa84e3003e46ea80576f6aec101ec Mon Sep 17 00:00:00 2001 From: Ajay Surya Date: Wed, 1 Jul 2026 23:06:00 +0530 Subject: [PATCH] test: harden governance adapter release coverage Co-Authored-By: Claude Opus 4.8 (1M context) --- tests/test_governance_install.py | 60 ++++++++++++++++++++++++++++++++ tests/test_packaging.py | 29 +++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/tests/test_governance_install.py b/tests/test_governance_install.py index a01f490..a8a25b5 100644 --- a/tests/test_governance_install.py +++ b/tests/test_governance_install.py @@ -172,3 +172,63 @@ def test_veto_escalate_on_sensitive_path_blocks_even_when_attended(tmp_path): pkt = _fresh_packet(tmp_path, decision="escalate", sensitive=True) rc = _run_veto(tmp_path, packet=pkt, env={"DORIAN_POLICY": "assist", "DORIAN_BASE": "HEAD"}) assert rc == 2 + + +# --- Slice 0 release-hardening: pin the fail-closed veto contract at its boundaries ------- + + +def test_veto_strict_identity_mismatch_blocks(tmp_path): + # strict + fresh CONTINUE, but the packet's base_ref != DORIAN_BASE -> identity mismatch blocks + pkt = _fresh_packet(tmp_path, decision="continue", base="HEAD") + rc = _run_veto( + tmp_path, packet=pkt, env={"DORIAN_POLICY": "unattended", "DORIAN_BASE": "other-ref"} + ) + assert rc == 2 + + +def test_veto_godmode_escalate_blocks(tmp_path): + # DORIAN_EFFORT=godmode forces strict even under the default (attended) policy + pkt = _fresh_packet(tmp_path, decision="escalate") + rc = _run_veto(tmp_path, packet=pkt, env={"DORIAN_EFFORT": "godmode", "DORIAN_BASE": "HEAD"}) + assert rc == 2 + + +def test_veto_strict_fresh_at_899s_allowed(tmp_path): + # freshness boundary: 899s < FRESH_SECONDS(900) is still fresh. Use float, not int() — int() + # floors away the sub-second fraction and would eat the ~1s margin for subprocess spawn. + pkt = _fresh_packet(tmp_path, decision="continue") + pkt["created_at_epoch"] = time.time() - 899 + rc = _run_veto(tmp_path, packet=pkt, env={"DORIAN_POLICY": "unattended", "DORIAN_BASE": "HEAD"}) + assert rc == 0 + + +def test_veto_strict_stale_at_901s_blocks(tmp_path): + # freshness boundary: 901s > FRESH_SECONDS(900) is stale -> fails closed under strict + pkt = _fresh_packet(tmp_path, decision="continue") + pkt["created_at_epoch"] = time.time() - 901 + rc = _run_veto(tmp_path, packet=pkt, env={"DORIAN_POLICY": "unattended", "DORIAN_BASE": "HEAD"}) + assert rc == 2 + + +def test_veto_attended_escalate_empty_path_blocks(tmp_path): + # a standing escalate on a tool with no file_path is unreviewable -> blocks even when attended + pkt = _fresh_packet(tmp_path, decision="escalate", sensitive=False) + rc = _run_veto( + tmp_path, + tool='{"tool_input": {}}', + packet=pkt, + env={"DORIAN_POLICY": "assist", "DORIAN_BASE": "HEAD"}, + ) + assert rc == 2 + + +def test_veto_attended_malformed_stdin_allows(tmp_path): + # malformed tool JSON under an attended policy fails OPEN (a human is present) + rc = _run_veto(tmp_path, tool="{ not json", packet=None, env={"DORIAN_POLICY": "assist"}) + assert rc == 0 + + +def test_veto_strict_malformed_stdin_blocks(tmp_path): + # malformed tool JSON under a strict policy fails CLOSED (exit 2) + rc = _run_veto(tmp_path, tool="{ not json", packet=None, env={"DORIAN_POLICY": "unattended"}) + assert rc == 2 diff --git a/tests/test_packaging.py b/tests/test_packaging.py index 064fdc0..028f982 100644 --- a/tests/test_packaging.py +++ b/tests/test_packaging.py @@ -176,3 +176,32 @@ def test_installed_scaffolds_loop_guard_skill(installed_dorian: Path, tmp_path: text = (repo / ".claude/skills/dorian-loop-guard/SKILL.md").read_text(encoding="utf-8") for phrase in ("/dorian-loop-guard", "not a sandbox", "token-free"): assert phrase in text + + +def test_installed_scaffolds_governance_adapter(installed_dorian: Path, tmp_path: Path) -> None: + """The packaged binary scaffolds the Claude Code governance adapter from package data — + proving the two host hooks + settings + docs ship in the wheel, and that the installed + PreToolUse veto carries its exit-2 fail-closed path for a real `pip install dorian-vwp` user.""" + repo = tmp_path / "govrepo" + repo.mkdir() + subprocess.run(["git", "init", "-q"], cwd=repo, check=True, capture_output=True) + r = subprocess.run( + [str(installed_dorian), "--repo", str(repo), "governance", "install"], + capture_output=True, + text=True, + ) + assert r.returncode == 0, r.stderr + veto = repo / ".claude/hooks/dorian_preflight_veto.py" + stop = repo / ".claude/hooks/dorian_loop_preflight.py" + for f in ( + veto, + stop, + repo / ".claude/settings.dorian-governance.example.json", + repo / ".claude/dorian-governance/README.md", + repo / ".claude/dorian-governance/reference/enforcement-modes.md", + ): + assert f.is_file(), f + veto_text = veto.read_text(encoding="utf-8") + assert "return 2" in veto_text # the exit-2 tool-block veto ships in the installed hook + assert "FAIL CLOSED" in veto_text.upper() + assert "hookSpecificOutput" in stop.read_text(encoding="utf-8")