feat: enforce capability stop terminal mode after reviewer denial (Issue #197)
Enter terminal mode when review_pr/merge_pr capability is denied. Block reviewer queue tools (list_prs, eligibility checks) and add report-purity validators for forbidden PR selection, fallback, and empty-queue claims. Closes #197 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
+45
-1
@@ -254,6 +254,7 @@ from gitea_auth import ( # noqa: E402
|
||||
)
|
||||
import gitea_audit # noqa: E402
|
||||
import gitea_config # noqa: E402
|
||||
import capability_stop_terminal # noqa: E402
|
||||
import issue_duplicate_gate # noqa: E402
|
||||
import role_session_router # noqa: E402
|
||||
|
||||
@@ -775,6 +776,11 @@ def gitea_list_prs(
|
||||
'mergeable', 'updated_at' ('url' only with the reveal opt-in).
|
||||
The additional 'updated_at' aids stale/conflicting queue detection.
|
||||
"""
|
||||
allowed, block_reasons = capability_stop_terminal.check_reviewer_queue_tool(
|
||||
"list_prs"
|
||||
)
|
||||
if not allowed:
|
||||
raise RuntimeError("; ".join(block_reasons))
|
||||
h, o, r = _resolve(remote, host, org, repo)
|
||||
auth = _auth(h)
|
||||
url = f"{repo_api_url(h, o, r)}/pulls?state={state}"
|
||||
@@ -886,6 +892,17 @@ def gitea_check_pr_eligibility(
|
||||
'permission_report' (#142).
|
||||
"""
|
||||
action = (action or "").strip().lower()
|
||||
if action in ("review", "approve", "request_changes", "merge"):
|
||||
allowed, block_reasons = capability_stop_terminal.check_reviewer_queue_tool(
|
||||
"check_pr_eligibility"
|
||||
)
|
||||
if not allowed:
|
||||
return {
|
||||
"eligible": False,
|
||||
"requested_action": action,
|
||||
"reasons": block_reasons,
|
||||
"terminal_mode": True,
|
||||
}
|
||||
profile = get_profile()
|
||||
result = {
|
||||
"eligible": False,
|
||||
@@ -4368,7 +4385,7 @@ def gitea_resolve_task_capability(
|
||||
|
||||
record_mutation_authority(profile["profile_name"], username, remote if remote in REMOTES else None, task)
|
||||
|
||||
return {
|
||||
result = {
|
||||
"requested_task": task,
|
||||
"required_operation_permission": required_permission,
|
||||
"required_role_kind": required_role,
|
||||
@@ -4383,6 +4400,33 @@ def gitea_resolve_task_capability(
|
||||
"different_mcp_namespace_required": different_namespace_required,
|
||||
"exact_safe_next_action": next_safe_action,
|
||||
}
|
||||
if stop_required:
|
||||
terminal = capability_stop_terminal.enter_from_capability_result(result)
|
||||
if terminal:
|
||||
result["terminal_mode"] = True
|
||||
result["terminal_report"] = (
|
||||
capability_stop_terminal.build_terminal_report(result)
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def gitea_capability_stop_terminal_report() -> dict:
|
||||
"""Read-only: terminal report template after reviewer capability denial (#197)."""
|
||||
record = capability_stop_terminal.active_record()
|
||||
if not record:
|
||||
return {
|
||||
"terminal_mode": False,
|
||||
"reasons": ["capability stop terminal mode is not active"],
|
||||
}
|
||||
return capability_stop_terminal.build_terminal_report({
|
||||
"requested_task": record.get("requested_task"),
|
||||
"required_role_kind": record.get("required_role_kind"),
|
||||
"active_profile": record.get("active_profile"),
|
||||
"active_identity": record.get("active_identity"),
|
||||
"stop_required": record.get("stop_required"),
|
||||
"exact_safe_next_action": record.get("exact_safe_next_action"),
|
||||
})
|
||||
|
||||
|
||||
# ── Entry point ───────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user