Block author mutations from reviewer MCP namespace (Issue #209)

Add role_namespace_gate to fail closed when reviewer-bound sessions attempt
author mutations (create_pr always blocked; create_issue only when profile
explicitly grants gitea.issue.create). Extend mutation audit records with
mcp_namespace, task_role, and operation fields. Add handoff parity checks in
review_proofs for author role vs reviewer namespace mismatches.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
2026-07-05 21:12:33 -04:00
co-authored by Claude Opus 4.8
parent 00394d43b7
commit cbce6cb2e7
5 changed files with 424 additions and 6 deletions
+35
View File
@@ -1139,6 +1139,41 @@ def assess_role_route_handoff(report_text, route_result=None):
}
def assess_mutation_namespace_handoff(
*,
declared_role: str | None = None,
namespaces_used: list[str] | None = None,
capability_profile: str | None = None,
):
"""Issue #209: handoff role and capability proof must match mutation namespace."""
reasons = []
role = (declared_role or "").strip().lower()
namespaces = list(namespaces_used or [])
reviewer_namespaces = [
ns for ns in namespaces if "reviewer" in (ns or "").lower()
]
if role == "author" and reviewer_namespaces:
reasons.append(
"author handoff reported reviewer MCP namespace for mutations")
cap = (capability_profile or "").strip().lower()
if cap and "author" in cap and reviewer_namespaces:
reasons.append(
"capability proof profile does not match mutation namespace "
f"(profile={capability_profile}, namespaces={reviewer_namespaces})")
blocked = bool(reasons)
return {
"valid": not blocked,
"blocked": blocked,
"complete": not blocked,
"downgraded": blocked,
"reasons": reasons,
"missing_fields": [] if not blocked else ["namespace parity"],
}
def assess_capability_stop_terminal_report(
report_text,
*,