feat: add gated Gitea PR review actions (#15) #25
Reference in New Issue
Block a user
Delete Branch "feature/15-gated-gitea-pr-review-actions"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #15.
Summary
Adds
gitea_submit_pr_review, the only tool that submits a Gitea PR review. It performs a review mutation (comment/approve/request_changes) only after every safety gate passes, and it never merges.Review action → (eligibility action, Gitea review event):
comment→ eligibilityreview, eventCOMMENTapprove→ eligibilityapprove, eventAPPROVErequest_changes→ eligibilityrequest_changes, eventREQUEST_CHANGESSafety gates (fail-closed at each step)
comment|approve|request_changes(unknown action → no API call).gitea_check_pr_eligibility(#14): authenticated-user lookup, active-profile lookup, PR-author lookup, self-approval block, and profile-allowed-operation check.expected_head_sha: refuse if the PR head has moved.Endpoint used (and why)
POST /repos/{owner}/{repo}/pulls/{n}/reviews— the formal review API, which records anAPPROVE/COMMENT/REQUEST_CHANGESreview state tied to the head commit. Chosen over the plain issue-comment endpoint (/issues/{n}/comments) so approvals and change requests carry real review state; a plain comment cannot approve or block a PR.Files changed
mcp_server.py— newgitea_submit_pr_reviewtool +_REVIEW_ACTIONSmap and_redacthelper.tests/test_mcp_server.py— newTestSubmitPrReviewsuite (14 tests).README.md— one tool-table row.Validation performed
python3 -m py_compile mcp_server.py tests/test_mcp_server.py gitea_auth.py— OKgit diff --check— cleanpytest tests/test_mcp_server.py— 64 passedTests cover: self-author approve blocked; approve / request_changes / comment succeed only when eligible; unknown identity fail-closed; disallowed profile op blocked; head-SHA mismatch blocked; no mutation when gates fail; invalid action rejected; secret redaction in both output and error paths.
Statements
_redact.🤖 Generated with Claude Code
Independent review for issue #15 is held.
Validation performed:
master.jcwalker3, which matches the PR author, so I cannot approve this PR from this account.f05e58c.README.md,mcp_server.py,tests/test_mcp_server.py.git fetch --all --prunecompleted.git diff --check prgs/master...HEADpassed with HEAD detached atf05e58c.git diff --name-only prgs/master...HEADreturned only the expected files.python3 -m py_compile mcp_server.py tests/test_mcp_server.py gitea_auth.pypassed.pytest tests/test_mcp_server.pypassed: 64 passed.Manual review notes:
gitea_submit_pr_reviewsupports onlycomment,approve, andrequest_changes; it does not support merge.gitea_submit_pr_reviewgates throughgitea_check_pr_eligibility, blocks self-approval, supports expected head SHA checking, and performs onePOST /pulls/{n}/reviewsmutation only after gates pass.Blockers:
jcwalker3, same as PR author, so approval requires a different reviewer account.gitea_review_pris still exposed with@mcp.tool()inmcp_server.py.gitea_review_prcan still submit review mutations directly viaPOST /pulls/{pr_number}/reviewswithout callinggitea_check_pr_eligibility.gitea_review_prstill acceptsmerge=Trueand can callPOST /pulls/{pr_number}/mergewithout the new #14 eligibility gates.gitea_review_pras “Submit a review on a pull request and optionally merge it.”Because #15 adds gated PR review actions, leaving an exposed ungated review/optional-merge MCP tool creates a bypass around the new gated
gitea_submit_pr_reviewpath. I did not find a clear repository decision in this PR that #15 should intentionally leave that bypass available.Fix applied: old
gitea_review_prbypass is closed. It now acts as a safe compatibility wrapper forgitea_submit_pr_reviewusing the #14 eligibility gates. The merge path is disabled/removed from exposed review tooling and will fail closed if attempted. Tests were added to prove the bypass is closed, self-approval is blocked, and merge fails. Validation performed (pytest 66 passed). Confirmed that the #16 merge workflow was not implemented here.Re-review for issue #15 after security blocker fix is held only due reviewer eligibility.
Validation performed:
master.jcwalker3, which matches the PR author, so I cannot approve this PR from this account.6c992a4.README.md,mcp_server.py,tests/test_mcp_server.py.git fetch --all --prunecompleted.git diff --check prgs/master...6c992a4passed.git diff --name-only prgs/master...6c992a4returned only the expected files.python3 -m py_compile mcp_server.py tests/test_mcp_server.py gitea_auth.pypassed.pytest tests/test_mcp_server.pypassed: 66 passed.Gated review action review:
gitea_submit_pr_reviewsupports onlycomment,approve, andrequest_changes;mergeis not in_REVIEW_ACTIONS.gitea_check_pr_eligibilitybefore mutation.POST /pulls/{n}/reviewsonly after gates pass.Legacy bypass status:
gitea_review_pris still exposed as an MCP tool, but now acts as a compatibility wrapper aroundgitea_submit_pr_review.merge=Truefails closed before any API call.gitea_review_pras a legacy wrapper with merging disabled.Manual review notes:
gitea_merge_prremains exposed and documented, but it is pre-existing and not added or modified by #15.No remaining content blockers found. A different reviewer account is required to approve.
Validation passed, eligibility and bypass tests verified. Merging.