Add explicit close_pr capability resolution and gated PR close path (Issue #216)
PR closure had no first-class capability: agents could close PRs through gitea_edit_pr(state=closed) with no close-specific capability proof, and gitea_resolve_task_capability(close_pr) failed as unknown, leaving the broad edit path as an untracked close fallback. Add close_pr to the resolver TASK_MAP (gitea.pr.close, author-side) and gate gitea_edit_pr(state=closed) on the same operation: without it the close fails closed before any auth or API call, with reasons and a structured permission_report; with it the close proceeds and is audited as a distinct close_pr action carrying the required capability. Reject invalid state values outright so case variants cannot bypass the gate. Generalize the profile gate helper (_profile_operation_gate) and document the PR comment / PR edit / PR close capability split. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
@@ -1621,7 +1621,8 @@ class TestTrackerHygieneCleanup(unittest.TestCase):
|
||||
self.mock_auth = patch("mcp_server.get_auth_header", return_value=FAKE_AUTH).start()
|
||||
patch("gitea_audit.audit_enabled", return_value=True).start()
|
||||
self.mock_audit = patch("gitea_audit.write_event").start()
|
||||
patch("mcp_server.get_profile", return_value={"profile_name": "test", "allowed_operations": ["merge", "edit", "close"], "audit_label": "test", "forbidden_operations": []}).start()
|
||||
# gitea.pr.close: closing a PR via gitea_edit_pr is capability-gated (#216).
|
||||
patch("mcp_server.get_profile", return_value={"profile_name": "test", "allowed_operations": ["merge", "edit", "close", "gitea.pr.close"], "audit_label": "test", "forbidden_operations": []}).start()
|
||||
|
||||
def tearDown(self):
|
||||
patch.stopall()
|
||||
|
||||
Reference in New Issue
Block a user