Files
rune/tests/test_p1_09_confirmation_semantics.py
T
Nick 8bb31cd035
local-review.yml (push) Invalid workflow file
Auto-version and Release / release (push) Successful in 10s
CI Pipeline / lint (push) Failing after 30s
CI Pipeline / go-surface (push) Failing after 19s
CI Pipeline / rust-surface (push) Successful in 4m15s
CI Pipeline / unit-tests (push) Failing after 5m23s
CI Pipeline / best-practices (push) Successful in 7s
CI Pipeline / documentation (push) Successful in 7s
CI Pipeline / canary (push) Failing after 59s
CI Pipeline / type-check (push) Failing after 34s
CI Pipeline / gitea-offline (push) Successful in 18s
deploy / deploy (push) Failing after 15m11s
CI Pipeline / required-checks (push) Failing after 1s
CI Pipeline / CI Pipeline / notify-event-bridge (push) Successful in 9s
test(p1): #31/#32/#33 VERIFIED — pin the already-holding states (contract BUILDER-2026-10-08T11:58:00Z-see-log)
- #31: no ambient scan (repo_map is tool-only, TUI mount performs no
  walk, operator performs no scan) — 3 pins
- #32: confirmation semantics (read-only executes, destructive
  requires, unknown fails closed, no TUI bypass) — 4 pins
- #33: outcome causality (receipts derive from the journal, REJECT is
  negative evidence) — 3 pins
- p1_02 mock updated to the #141 session_id signature

10/10 green. These issues' conditions hold in-tree; the tests pin them
so they can never silently regress.
2026-10-08 13:07:33 +01:00

61 lines
2.4 KiB
Python

"""test_p1_09_confirmation_semantics.py — #32: permission semantics.
- read-only tools execute without confirmation
- destructive/external tools require confirmation
- unknown tools FAIL CLOSED (never auto-approved)
- the TUI never auto-approves owner-required actions (no auto_approve
path that bypasses tool_requires_approval)
"""
import re
import sys
from pathlib import Path
import pytest
REPO = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(REPO / "src"))
sys.path.insert(0, str(REPO / "src" / "rune"))
import tool_protocol as tp # noqa: E402
class TestConfirmationSemantics:
def test_read_only_needs_no_approval(self):
args_by_tool = {
"read_file": {"path": "/tmp"},
"list_directory": {"path": "/tmp"},
"grep_files": {"pattern": "x"},
"git_diff": {}, "git_log": {}, "repo_map": {"path": "/tmp"},
}
for name, arguments in args_by_tool.items():
req = tp.ToolRequest(call_id="c", name=name,
arguments=arguments, source="test")
assert tp.tool_requires_approval(req) is False, name
def test_destructive_requires_approval(self):
args_by_tool = {
"write_file": {"path": "/tmp/x", "content": "y"},
"edit_file": {"path": "/tmp/x", "search": "a", "replace": "b"},
"run_command": {"command": "ls"},
"git_commit": {"message": "m"},
}
for name, arguments in args_by_tool.items():
req = tp.ToolRequest(call_id="c", name=name,
arguments=arguments, source="test")
assert tp.tool_requires_approval(req) is True, name
def test_unknown_fails_closed(self):
req = tp.ToolRequest(call_id="c", name="no_such_tool",
arguments={}, source="test")
with pytest.raises(ValueError, match="unknown tool"):
tp.tool_requires_approval(req)
def test_no_tui_auto_approve_bypass(self):
"""No auto_approve path in the TUI that bypasses the protocol."""
src = (REPO / "src" / "rune" / "rune_tui.py").read_text()
for m in re.finditer(r"auto_approve", src):
context = src[max(0, m.start()-200):m.end()+200]
assert "tool_requires_approval" in context or "requires-approval" in context or "confirm" in context.lower(), \
f"auto_approve without protocol check at {src.count(chr(10), 0, m.start())}"