Enforce issue-write tool gates to match task capability resolver (Issue #69)
Extract TASK_CAPABILITY_MAP into task_capability_map.py as the single source of truth shared by gitea_resolve_task_capability and issue-mutating tools. Gate gitea_create_issue, gitea_close_issue, gitea_mark_issue, and gitea_set_issue_labels with structured #142 permission reports. Add regression tests proving resolver-denied tasks fail closed at the raw tool layer. Implements mcp-control-plane #69. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
+6
-2
@@ -162,7 +162,8 @@ class _AuditWiringBase(unittest.TestCase):
|
||||
def _env(self, **extra):
|
||||
env = {"GITEA_AUDIT_LOG": self.audit_path,
|
||||
"GITEA_PROFILE_NAME": "gitea-author",
|
||||
"GITEA_ALLOWED_OPERATIONS": "read,merge"}
|
||||
"GITEA_ALLOWED_OPERATIONS": (
|
||||
"read,merge,gitea.issue.create,gitea.issue.close")}
|
||||
env.update(extra)
|
||||
return env
|
||||
|
||||
@@ -237,7 +238,10 @@ class TestSimpleToolAudit(_AuditWiringBase):
|
||||
def test_disabled_writes_nothing_and_no_extra_call(self, _auth, _get_all, mock_api, _role):
|
||||
# No GITEA_AUDIT_LOG -> audit is a no-op: one create POST, no file.
|
||||
mock_api.return_value = {"number": 1, "html_url": "http://x/1"}
|
||||
with patch.dict(os.environ, {"GITEA_PROFILE_NAME": "gitea-author"}, clear=True):
|
||||
with patch.dict(os.environ, {
|
||||
"GITEA_PROFILE_NAME": "gitea-author",
|
||||
"GITEA_ALLOWED_OPERATIONS": "gitea.issue.create",
|
||||
}, clear=True):
|
||||
gitea_create_issue(title="x", remote="prgs")
|
||||
issue_posts = [
|
||||
c for c in mock_api.call_args_list if c.args[0] == "POST"
|
||||
|
||||
Reference in New Issue
Block a user