feat: structured permission failure reports on gated tools (#142) #161

Merged
sysadmin merged 1 commits from feat/issue-142-structured-permission-failures into master 2026-07-05 10:24:33 -05:00
Owner

Summary

Adds a structured, LLM-safe permission_report to every gated-tool denial, so a blocked call explains exactly what was missing and what the safe next action is — instead of only a short reason string.

  • New fail-soft helper _permission_block_report(required_operation, identity=None): requested/missing/required operation, active profile + identity (when already resolved), the profile's allowed operations, matching configured profiles (names only — never auth references, tokens, endpoints, or keychain IDs), runtime_switching_supported, different_mcp_namespace_required, and exact_safe_next_action. Read-only, no network I/O, never raises; degrades to a minimal fail-closed report when the profile itself cannot be resolved.
  • Wired into gitea_check_pr_eligibility (missing-permission denials) and propagated through gitea_submit_pr_review, gitea_merge_pr, and the legacy gitea_review_pr wrapper; also into the issue-comment gate consumers gitea_list_issue_comments and gitea_create_issue_comment.
  • Purely additive: every prior denial still denies identically with unchanged reasons; input errors (e.g. empty comment body) are not permission failures and carry no report. No permission broadening anywhere.
  • Fixes a latent phantom-op bug found during subagent review: the eligibility review action previously mapped to gitea.review instead of the canonical gitea.pr.review, which would have produced wrong guidance (role misclassified as author, no matching profiles) on the review-comment path.

Tests (12 new, synthetic, no network)

Missing gitea.issue.comment; author attempting review and merge; review-comment path names canonical gitea.pr.review; reviewer attempting an authoring operation (names the author namespace); unknown/missing profile fails closed with a safe degraded report; switching-enabled guidance points to gitea_activate_profile; eligible calls carry no report; empty-body input error carries no report; profile with an un-normalizable forbidden entry is never advertised as matching; no secret/URL material in any report (asserted).

Validation

  • New tests: 12 passed (core 8 watched fail RED first; review-fix test watched fail RED before the fix).
  • Full suite: 547 passed. py_compile OK. git diff --check clean. Secret/provenance sweep clean.
  • Subagent review: 1 finding fixed (phantom gitea.review op), 1 hardening test added, duplication of the matching-profile scan vs the #141 resolver noted as an acceptable follow-up extraction.

Closes #142

## Summary Adds a structured, LLM-safe `permission_report` to every gated-tool denial, so a blocked call explains exactly what was missing and what the safe next action is — instead of only a short reason string. - New fail-soft helper `_permission_block_report(required_operation, identity=None)`: requested/missing/required operation, active profile + identity (when already resolved), the profile's allowed operations, matching configured profiles (**names only** — never auth references, tokens, endpoints, or keychain IDs), `runtime_switching_supported`, `different_mcp_namespace_required`, and `exact_safe_next_action`. Read-only, no network I/O, never raises; degrades to a minimal fail-closed report when the profile itself cannot be resolved. - Wired into `gitea_check_pr_eligibility` (missing-permission denials) and propagated through `gitea_submit_pr_review`, `gitea_merge_pr`, and the legacy `gitea_review_pr` wrapper; also into the issue-comment gate consumers `gitea_list_issue_comments` and `gitea_create_issue_comment`. - Purely additive: every prior denial still denies identically with unchanged `reasons`; input errors (e.g. empty comment body) are not permission failures and carry no report. No permission broadening anywhere. - Fixes a latent phantom-op bug found during subagent review: the eligibility `review` action previously mapped to `gitea.review` instead of the canonical `gitea.pr.review`, which would have produced wrong guidance (role misclassified as author, no matching profiles) on the review-comment path. ## Tests (12 new, synthetic, no network) Missing `gitea.issue.comment`; author attempting review and merge; review-comment path names canonical `gitea.pr.review`; reviewer attempting an authoring operation (names the author namespace); unknown/missing profile fails closed with a safe degraded report; switching-enabled guidance points to `gitea_activate_profile`; eligible calls carry no report; empty-body input error carries no report; profile with an un-normalizable forbidden entry is never advertised as matching; no secret/URL material in any report (asserted). ## Validation - New tests: 12 passed (core 8 watched fail RED first; review-fix test watched fail RED before the fix). - Full suite: 547 passed. `py_compile` OK. `git diff --check` clean. Secret/provenance sweep clean. - Subagent review: 1 finding fixed (phantom `gitea.review` op), 1 hardening test added, duplication of the matching-profile scan vs the #141 resolver noted as an acceptable follow-up extraction. Closes #142
jcwalker3 added 1 commit 2026-07-05 02:45:05 -05:00
Every gated denial now carries a 'permission_report' explaining itself:
requested/missing/required operation, active profile and identity (when
already resolved), the profile's allowed operations, which configured
profiles could perform the operation (names only), whether runtime
switching is supported, whether a different MCP namespace/session is
required, and the exact safe next action.

New fail-soft helper _permission_block_report builds the report only
after a gate has refused — it adds guidance to denials, never widens a
permission, performs no network I/O, and degrades to a minimal
fail-closed report if the profile itself cannot be resolved. Wired into
gitea_check_pr_eligibility (and via it gitea_submit_pr_review,
gitea_merge_pr, and the legacy gitea_review_pr wrapper) and into the
issue-comment gate consumers gitea_list_issue_comments and
gitea_create_issue_comment. Input errors (e.g. empty comment body) are
not permission failures and get no report.

Tests cover: missing gitea.issue.comment, author attempting review and
merge, reviewer attempting an authoring operation, unknown/missing
profile fail-closed, switching-enabled guidance, eligible calls carry
no report, and no secret/URL material in any report.

Closes #142

Co-Authored-By: Claude Fable 5 <[email protected]>
sysadmin reviewed 2026-07-05 10:24:16 -05:00
sysadmin left a comment
Owner

Approved after independent review.

Validated scope against #142: structured permission reports are additive on gated denials, preserve existing fail-closed behavior, keep review/merge gates intact, and do not expose real secrets, endpoint URLs, keychain IDs, or provenance markers. Targeted and full test suites pass.

Approved after independent review. Validated scope against #142: structured permission reports are additive on gated denials, preserve existing fail-closed behavior, keep review/merge gates intact, and do not expose real secrets, endpoint URLs, keychain IDs, or provenance markers. Targeted and full test suites pass.
sysadmin merged commit e7556f5177 into master 2026-07-05 10:24:33 -05:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Scaled-Tech-Consulting/Gitea-Tools#161