feat(preflight): block workspace edits before identity/capability verification (Closes #210)
This commit is contained in:
@@ -2296,3 +2296,88 @@ class TestIssueCommentPermissionSeparation(unittest.TestCase):
|
||||
"gitea.issue.comment", reviewer["allowed_operations"],
|
||||
reviewer.get("forbidden_operations", []))
|
||||
self.assertTrue(ok)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pre-flight ordering and workspace edit block (#210)
|
||||
# ---------------------------------------------------------------------------
|
||||
class TestPreflightVerification(unittest.TestCase):
|
||||
"""Assert that pre-flight verification gates order correctly."""
|
||||
|
||||
def setUp(self):
|
||||
# Save real global variables
|
||||
import mcp_server
|
||||
self.orig_whoami_called = mcp_server._preflight_whoami_called
|
||||
self.orig_capability_called = mcp_server._preflight_capability_called
|
||||
self.orig_whoami_violation = mcp_server._preflight_whoami_violation
|
||||
self.orig_capability_violation = mcp_server._preflight_capability_violation
|
||||
self.orig_resolved_role = mcp_server._preflight_resolved_role
|
||||
|
||||
# Reset state for each test
|
||||
mcp_server._preflight_whoami_called = False
|
||||
mcp_server._preflight_capability_called = False
|
||||
mcp_server._preflight_whoami_violation = False
|
||||
mcp_server._preflight_capability_violation = False
|
||||
mcp_server._preflight_resolved_role = None
|
||||
|
||||
def tearDown(self):
|
||||
# Restore real global variables
|
||||
import mcp_server
|
||||
mcp_server._preflight_whoami_called = self.orig_whoami_called
|
||||
mcp_server._preflight_capability_called = self.orig_capability_called
|
||||
mcp_server._preflight_whoami_violation = self.orig_whoami_violation
|
||||
mcp_server._preflight_capability_violation = self.orig_capability_violation
|
||||
mcp_server._preflight_resolved_role = self.orig_resolved_role
|
||||
if "GITEA_TEST_FORCE_DIRTY" in os.environ:
|
||||
del os.environ["GITEA_TEST_FORCE_DIRTY"]
|
||||
|
||||
def test_preflight_whoami_violation(self):
|
||||
import mcp_server
|
||||
os.environ["GITEA_TEST_FORCE_DIRTY"] = "1"
|
||||
mcp_server._preflight_capability_called = True
|
||||
mcp_server.record_preflight_check("whoami")
|
||||
self.assertTrue(mcp_server._preflight_whoami_violation)
|
||||
|
||||
with self.assertRaises(RuntimeError) as ctx:
|
||||
mcp_server.verify_preflight_purity()
|
||||
self.assertIn("Workspace file edits occurred before gitea_whoami verification", str(ctx.exception))
|
||||
|
||||
def test_preflight_capability_violation(self):
|
||||
import mcp_server
|
||||
os.environ["GITEA_TEST_FORCE_DIRTY"] = "1"
|
||||
mcp_server._preflight_whoami_called = True
|
||||
mcp_server.record_preflight_check("capability", resolved_role="author")
|
||||
self.assertTrue(mcp_server._preflight_capability_violation)
|
||||
|
||||
with self.assertRaises(RuntimeError) as ctx:
|
||||
mcp_server.verify_preflight_purity()
|
||||
self.assertIn("Workspace file edits occurred before gitea_resolve_task_capability verification", str(ctx.exception))
|
||||
|
||||
def test_preflight_not_called_fails_closed(self):
|
||||
import mcp_server
|
||||
os.environ["GITEA_TEST_FORCE_DIRTY"] = "1"
|
||||
with self.assertRaises(RuntimeError) as ctx:
|
||||
mcp_server.verify_preflight_purity()
|
||||
self.assertIn("Identity (gitea_whoami) has not been verified", str(ctx.exception))
|
||||
|
||||
mcp_server._preflight_whoami_called = True
|
||||
with self.assertRaises(RuntimeError) as ctx2:
|
||||
mcp_server.verify_preflight_purity()
|
||||
self.assertIn("Task capability (gitea_resolve_task_capability) has not been resolved", str(ctx2.exception))
|
||||
|
||||
def test_preflight_reviewer_mutation_violation(self):
|
||||
import mcp_server
|
||||
mcp_server._preflight_whoami_called = True
|
||||
mcp_server._preflight_capability_called = True
|
||||
mcp_server._preflight_resolved_role = "reviewer"
|
||||
|
||||
# When dirty, reviewer edits are blocked
|
||||
os.environ["GITEA_TEST_FORCE_DIRTY"] = "1"
|
||||
with self.assertRaises(RuntimeError) as ctx:
|
||||
mcp_server.verify_preflight_purity()
|
||||
self.assertIn("Reviewer profile is forbidden from modifying tracked workspace files", str(ctx.exception))
|
||||
|
||||
# When clean, reviewer is allowed
|
||||
del os.environ["GITEA_TEST_FORCE_DIRTY"]
|
||||
mcp_server.verify_preflight_purity()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user