"""Shared task→permission map for resolver and tool gates (#69). ``gitea_resolve_task_capability`` and issue-mutating MCP tools must agree on which profile operation each task requires. This module is the single source of truth; regression tests assert tool gates cannot drift from it. """ from __future__ import annotations TASK_CAPABILITY_MAP: dict[str, dict[str, str]] = { "create_issue": { "permission": "gitea.issue.create", "role": "author", }, "comment_issue": { "permission": "gitea.issue.comment", "role": "author", }, "close_issue": { "permission": "gitea.issue.close", "role": "author", }, "claim_issue": { "permission": "gitea.issue.comment", "role": "author", }, "mark_issue": { "permission": "gitea.issue.comment", "role": "author", }, "set_issue_labels": { "permission": "gitea.issue.comment", "role": "author", }, "create_branch": { "permission": "gitea.branch.create", "role": "author", }, "push_branch": { "permission": "gitea.branch.push", "role": "author", }, "create_pr": { "permission": "gitea.pr.create", "role": "author", }, "comment_pr": { "permission": "gitea.pr.comment", "role": "author", }, "close_pr": { "permission": "gitea.pr.close", "role": "author", }, "address_pr_change_requests": { "permission": "gitea.branch.push", "role": "author", }, "review_pr": { "permission": "gitea.pr.review", "role": "reviewer", }, "merge_pr": { "permission": "gitea.pr.merge", "role": "reviewer", }, "blind_pr_queue_review": { "permission": "gitea.pr.review", "role": "reviewer", }, "request_changes_pr": { "permission": "gitea.pr.request_changes", "role": "reviewer", }, "approve_pr": { "permission": "gitea.pr.approve", "role": "reviewer", }, "delete_branch": { "permission": "gitea.branch.delete", "role": "author", }, "commit_files": { "permission": "gitea.repo.commit", "role": "author", }, "gitea_commit_files": { "permission": "gitea.repo.commit", "role": "author", }, } # Issue-mutating MCP tools and their resolver task keys. ISSUE_MUTATION_TOOL_TASKS: dict[str, str] = { "gitea_create_issue": "create_issue", "gitea_close_issue": "close_issue", "gitea_create_issue_comment": "comment_issue", "gitea_mark_issue": "mark_issue", "gitea_set_issue_labels": "set_issue_labels", "gitea_commit_files": "commit_files", } def required_permission(task: str) -> str: """Return the canonical operation a *task* requires (fail closed).""" try: return TASK_CAPABILITY_MAP[task]["permission"] except KeyError as exc: raise KeyError(f"Unknown task/action: {task!r} (fail closed)") from exc def required_role(task: str) -> str: """Return author/reviewer role kind for *task* (fail closed).""" try: return TASK_CAPABILITY_MAP[task]["role"] except KeyError as exc: raise KeyError(f"Unknown task/action: {task!r} (fail closed)") from exc def tool_required_permission(tool_name: str) -> str: """Return the operation an issue-mutating tool must gate on.""" return required_permission(ISSUE_MUTATION_TOOL_TASKS[tool_name])