feat: add read-only gitea_check_pr_eligibility (#14) #24

Merged
jcwalker3 merged 2 commits from feature/14-gitea-pr-eligibility-checks into master 2026-07-01 13:20:31 -05:00
Owner

Closes #14
Roadmap parent: #10

Summary

Adds a read-only MCP tool gitea_check_pr_eligibility(pr_number, action, remote, …) that decides whether the current authenticated identity + active runtime profile is eligible to perform an action on a specific PR. Evaluation only — it never reviews, approves, requests changes, merges, or mutates anything.

Inspects:

  • authenticated username (GET /api/v1/user)
  • active profile metadata (get_profile: allowed/forbidden operations)
  • PR facts (GET /pulls/{n}: author, state, head SHA, mergeability)

Returns:

{
  "eligible": false,
  "requested_action": "merge",
  "authenticated_user": "jcwalker3",
  "profile_name": "gitea-merger",
  "allowed_operations": ["read", "merge"],
  "pr_author": "jcwalker3",
  "pr_number": 8,
  "pr_state": "open",
  "head_sha": "abc123",
  "mergeable": true,
  "reasons": ["authenticated user is PR author"]
}

Fail-closed rules

  • Unknown action / unknown remote → not eligible.
  • Action not in profile's allowed_operations, or listed in forbidden_operations → not eligible.
  • Authenticated identity cannot be determined → not eligible.
  • Authenticated user == PR author → cannot approve or merge (the PR #8 dogfooding blocker, now machine-checkable).
  • PR not open → not eligible.
  • merge requires a positive mergeable signal (mergeable is False or None → not eligible).
  • eligible is true only when there are zero blocking reasons.

Files changed (3, +246)

File Change
mcp_server.py new gitea_check_pr_eligibility tool + _ELIGIBILITY_ACTIONS (+143)
tests/test_mcp_server.py TestPrEligibility (8 tests) (+102)
README.md tool-table row (+1)

Validation

  • git diff --check → clean.
  • python3 -m py_compile mcp_server.py tests/test_mcp_server.py gitea_auth.py → OK.
  • pytest tests/test_mcp_server.py49 passed (was 41; +8 new).
  • Secret scan on additions → no real tokens (test synthetic super-secret-token asserted absent from output).
  • Manual: no auth headers in output, no raw env dump, no credential paths, no unrelated files.

Explicit statements

  • No PR review/approval/request-changes mutation added — eligibility evaluation only (#15 owns the real actions).
  • No merge mutation added#16 owns the real merge workflow.
  • No real secrets added.
  • No multi-token switching inside one runtime.
  • No Jenkins/Ops/GlitchTip/Release/deploy behavior added.

Scoped to #14 only. Does not touch #15–#18. Do not merge — awaiting independent review.

Closes #14 Roadmap parent: #10 ## Summary Adds a **read-only** MCP tool `gitea_check_pr_eligibility(pr_number, action, remote, …)` that decides whether the current authenticated identity + active runtime profile is eligible to perform an action on a specific PR. **Evaluation only — it never reviews, approves, requests changes, merges, or mutates anything.** Inspects: - authenticated username (`GET /api/v1/user`) - active profile metadata (`get_profile`: allowed/forbidden operations) - PR facts (`GET /pulls/{n}`: author, state, head SHA, mergeability) Returns: ```json { "eligible": false, "requested_action": "merge", "authenticated_user": "jcwalker3", "profile_name": "gitea-merger", "allowed_operations": ["read", "merge"], "pr_author": "jcwalker3", "pr_number": 8, "pr_state": "open", "head_sha": "abc123", "mergeable": true, "reasons": ["authenticated user is PR author"] } ``` ## Fail-closed rules - Unknown action / unknown remote → not eligible. - Action not in profile's `allowed_operations`, or listed in `forbidden_operations` → not eligible. - Authenticated identity cannot be determined → not eligible. - **Authenticated user == PR author → cannot `approve` or `merge`** (the PR #8 dogfooding blocker, now machine-checkable). - PR not open → not eligible. - `merge` requires a positive mergeable signal (`mergeable is False` or `None` → not eligible). - `eligible` is true only when there are zero blocking reasons. ## Files changed (3, +246) | File | Change | |------|--------| | `mcp_server.py` | new `gitea_check_pr_eligibility` tool + `_ELIGIBILITY_ACTIONS` (+143) | | `tests/test_mcp_server.py` | `TestPrEligibility` (8 tests) (+102) | | `README.md` | tool-table row (+1) | ## Validation - `git diff --check` → clean. - `python3 -m py_compile mcp_server.py tests/test_mcp_server.py gitea_auth.py` → OK. - `pytest tests/test_mcp_server.py` → **49 passed** (was 41; +8 new). - Secret scan on additions → no real tokens (test synthetic `super-secret-token` asserted **absent** from output). - Manual: no auth headers in output, no raw env dump, no credential paths, no unrelated files. ## Explicit statements - **No PR review/approval/request-changes mutation added** — eligibility evaluation only (#15 owns the real actions). - **No merge mutation added** — #16 owns the real merge workflow. - **No real secrets added.** - **No multi-token switching** inside one runtime. - **No Jenkins/Ops/GlitchTip/Release/deploy behavior added.** Scoped to #14 only. Does not touch #15–#18. **Do not merge** — awaiting independent review.
jcwalker3 added 1 commit 2026-07-01 12:55:12 -05:00
Add a read-only MCP tool that decides whether the current authenticated
identity + active runtime profile is eligible to review, approve,
request_changes, or merge a specific PR. Evaluation only — it never
reviews, approves, requests changes, merges, or mutates anything.

Inspects: authenticated username (/user), active profile metadata
(allowed/forbidden operations), and PR facts (author, state, head SHA,
mergeability). Returns {eligible, requested_action, authenticated_user,
profile_name, pr_author, pr_state, head_sha, mergeable, reasons}.

Fail-closed rules:
- unknown action / unknown remote -> not eligible
- action not in allowed ops, or in forbidden ops -> not eligible
- identity undetermined -> not eligible
- authenticated user == PR author -> cannot approve/merge
- PR not open -> not eligible
- merge requires a positive mergeable signal

No token/auth-header exposure. No review/approve/request-changes
mutation. No merge mutation. No multi-token switching. No
Jenkins/Ops/GlitchTip/Release/deploy behavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author
Owner

Independent review for issue #14 is held.

Validation performed:

  • PR #24 is open and targets master.
  • Authenticated Gitea account is jcwalker3, which matches the PR author, so I cannot approve this PR from this account.
  • Head reviewed: fbbbd53.
  • Changed files verified exactly: README.md, mcp_server.py, tests/test_mcp_server.py.
  • git fetch --all --prune completed.
  • git diff --check prgs/master...fbbbd53 passed.
  • git diff --name-only prgs/master...fbbbd53 returned only the expected files.
  • python3 -m py_compile mcp_server.py tests/test_mcp_server.py gitea_auth.py passed.
  • pytest tests/test_mcp_server.py passed: 49 passed.

Manual review notes:

  • gitea_check_pr_eligibility is read-only: it uses GETs for authenticated user and PR details and does not submit reviews, approvals, request-changes, merges, comments, labels, branch writes, deploys, rollbacks, restarts, or migrations.
  • The tool inspects requested action, authenticated username, active profile metadata, PR author, PR state, head SHA, mergeability, self-author status, and profile allow/forbid metadata.
  • Fail-closed implementation is present for unknown action/remote, no allowed operations, forbidden/not-allowed actions, missing identity, missing PR details/state, non-open PRs, self-author approve/merge, and unknown/not-mergeable mergeability.
  • Output includes safe/useful fields and does not return token values, authorization headers, passwords, raw environment dumps, credential paths, or secret material.
  • No unrelated #15-#18 implementation, review/approve/request-changes mutation, merge mutation, Jenkins/Ops/GlitchTip/Release/deploy/rollback/migration/restart/production behavior found.

Blockers:

  • Reviewer eligibility: current authenticated Gitea account is jcwalker3, same as PR author, so approval requires a different reviewer account.
  • Test coverage checklist is not fully satisfied: there is no explicit test for mergeability unknown fail-closed behavior (mergeable is None for merge).
  • Test coverage checklist is not fully satisfied: self-author blocking is tested for merge, but not explicitly for approve.
Independent review for issue #14 is held. Validation performed: - PR #24 is open and targets `master`. - Authenticated Gitea account is `jcwalker3`, which matches the PR author, so I cannot approve this PR from this account. - Head reviewed: `fbbbd53`. - Changed files verified exactly: `README.md`, `mcp_server.py`, `tests/test_mcp_server.py`. - `git fetch --all --prune` completed. - `git diff --check prgs/master...fbbbd53` passed. - `git diff --name-only prgs/master...fbbbd53` returned only the expected files. - `python3 -m py_compile mcp_server.py tests/test_mcp_server.py gitea_auth.py` passed. - `pytest tests/test_mcp_server.py` passed: 49 passed. Manual review notes: - `gitea_check_pr_eligibility` is read-only: it uses GETs for authenticated user and PR details and does not submit reviews, approvals, request-changes, merges, comments, labels, branch writes, deploys, rollbacks, restarts, or migrations. - The tool inspects requested action, authenticated username, active profile metadata, PR author, PR state, head SHA, mergeability, self-author status, and profile allow/forbid metadata. - Fail-closed implementation is present for unknown action/remote, no allowed operations, forbidden/not-allowed actions, missing identity, missing PR details/state, non-open PRs, self-author approve/merge, and unknown/not-mergeable mergeability. - Output includes safe/useful fields and does not return token values, authorization headers, passwords, raw environment dumps, credential paths, or secret material. - No unrelated #15-#18 implementation, review/approve/request-changes mutation, merge mutation, Jenkins/Ops/GlitchTip/Release/deploy/rollback/migration/restart/production behavior found. Blockers: - Reviewer eligibility: current authenticated Gitea account is `jcwalker3`, same as PR author, so approval requires a different reviewer account. - Test coverage checklist is not fully satisfied: there is no explicit test for mergeability unknown fail-closed behavior (`mergeable is None` for `merge`). - Test coverage checklist is not fully satisfied: self-author blocking is tested for `merge`, but not explicitly for `approve`.
jcwalker3 added 1 commit 2026-07-01 13:02:51 -05:00
Add two explicit eligibility tests requested in review of PR #24:
- self-author blocked from 'approve' (eligible=false, reason
  "authenticated user is PR author").
- 'merge' fails closed when Gitea reports mergeable=None (eligible=false,
  reason "PR mergeability unknown").

Tests only; no implementation change. Behavior already enforced by
gitea_check_pr_eligibility.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author
Owner

Review blockers addressed — commit baf4eae

Both requested test-coverage blockers are now covered. Tests only — no implementation change (behavior was already enforced by gitea_check_pr_eligibility).

  • Self-author blocked from approvetest_self_author_cannot_approve: authenticated user == PR author, action approveeligible == false, reason "authenticated user is PR author".
  • Merge fails closed when mergeability unknowntest_merge_fails_closed_when_mergeability_unknown: action merge, Gitea returns mergeable = Noneeligible == false, mergeable null, reason "PR mergeability unknown".

Validation performed

  • git diff --check → clean
  • python3 -m py_compile mcp_server.py tests/test_mcp_server.py gitea_auth.py → OK
  • pytest tests/test_mcp_server.py51 passed (was 49; +2 new)
  • Scope: only tests/test_mcp_server.py changed this round.

Confirmations

  • No mutation actions added; no approve/merge/request-changes implementation added.
  • Eligibility remains read-only (two GETs: /user, /pulls/{n}).
  • No secrets, tokens, auth headers, raw env, or credential paths exposed (test synthetic super-secret-token asserted absent from output).
  • No unrelated files changed.

Scoped to #14 only. Did not start #15–#18. Not merging — awaiting reviewer.

## Review blockers addressed — commit `baf4eae` Both requested test-coverage blockers are now covered. **Tests only — no implementation change** (behavior was already enforced by `gitea_check_pr_eligibility`). - **Self-author blocked from `approve`** — `test_self_author_cannot_approve`: authenticated user == PR author, action `approve` → `eligible == false`, reason `"authenticated user is PR author"`. - **Merge fails closed when mergeability unknown** — `test_merge_fails_closed_when_mergeability_unknown`: action `merge`, Gitea returns `mergeable = None` → `eligible == false`, `mergeable` null, reason `"PR mergeability unknown"`. ### Validation performed - `git diff --check` → clean - `python3 -m py_compile mcp_server.py tests/test_mcp_server.py gitea_auth.py` → OK - `pytest tests/test_mcp_server.py` → **51 passed** (was 49; +2 new) - Scope: only `tests/test_mcp_server.py` changed this round. ### Confirmations - No mutation actions added; no approve/merge/request-changes implementation added. - Eligibility remains **read-only** (two GETs: `/user`, `/pulls/{n}`). - No secrets, tokens, auth headers, raw env, or credential paths exposed (test synthetic `super-secret-token` asserted **absent** from output). - No unrelated files changed. Scoped to #14 only. Did not start #15–#18. **Not merging** — awaiting reviewer.
Author
Owner

Issue #14 test-coverage blockers fixed on feature/14-gitea-pr-eligibility-checks.

  • Added explicit self-author approve test: authenticated user matching PR author is ineligible and reports authenticated user is PR author.
  • Added explicit mergeability-unknown fail-closed test: mergeable: None for merge returns eligible: false with PR mergeability unknown.
  • Validation performed: git diff --check, python3 -m py_compile mcp_server.py tests/test_mcp_server.py gitea_auth.py, and pytest tests/test_mcp_server.py (51 passed).
  • Manual confirmation: no mutation actions, review/approve/request-changes implementation, merge implementation, Jenkins/Ops/GlitchTip/Release/deploy behavior, secrets, tokens, auth headers, raw env, or credential paths were added. Change is limited to tests/test_mcp_server.py.
Issue #14 test-coverage blockers fixed on `feature/14-gitea-pr-eligibility-checks`. - Added explicit self-author `approve` test: authenticated user matching PR author is ineligible and reports `authenticated user is PR author`. - Added explicit mergeability-unknown fail-closed test: `mergeable: None` for `merge` returns `eligible: false` with `PR mergeability unknown`. - Validation performed: `git diff --check`, `python3 -m py_compile mcp_server.py tests/test_mcp_server.py gitea_auth.py`, and `pytest tests/test_mcp_server.py` (51 passed). - Manual confirmation: no mutation actions, review/approve/request-changes implementation, merge implementation, Jenkins/Ops/GlitchTip/Release/deploy behavior, secrets, tokens, auth headers, raw env, or credential paths were added. Change is limited to `tests/test_mcp_server.py`.
jcwalker3 reviewed 2026-07-01 13:10:18 -05:00
jcwalker3 left a comment
Author
Owner

Content, scope, and validation passed. Confirmed explicit tests for self-author approval block and unknown-mergeability fail-closed are present. 51 tests passed. All checks pass.

Content, scope, and validation passed. Confirmed explicit tests for self-author approval block and unknown-mergeability fail-closed are present. 51 tests passed. All checks pass.
Author
Owner

Re-review for issue #14 after test-coverage fix is held only due reviewer eligibility.

Validation performed:

  • PR #24 is open and targets master.
  • Authenticated Gitea account is jcwalker3, which matches the PR author, so I cannot approve this PR from this account.
  • Latest commit reviewed: baf4eae.
  • Changed files verified exactly: README.md, mcp_server.py, tests/test_mcp_server.py.
  • git fetch --all --prune completed.
  • git diff --check prgs/master...baf4eae passed.
  • git diff --name-only prgs/master...baf4eae returned only the expected files.
  • python3 -m py_compile mcp_server.py tests/test_mcp_server.py gitea_auth.py passed.
  • pytest tests/test_mcp_server.py passed: 51 passed.

Previous blockers verified fixed:

  • Explicit self-author approve test is present: test_self_author_cannot_approve.
  • Explicit mergeability-unknown fail-closed test is present: test_merge_fails_closed_when_mergeability_unknown.

Manual review notes:

  • gitea_check_pr_eligibility remains read-only and uses GETs for authenticated user and PR details.
  • No PR review submission, approval mutation, request-changes mutation, merge mutation, issue/PR comment mutation, branch writes, Jenkins/Ops/GlitchTip/Release/deploy behavior, secrets, auth headers, raw env leakage, or credential path exposure found.
  • Eligibility behavior remains fail-closed for unknown identity, no configured allowed operations/profile metadata, operation not allowed/forbidden, self-author approve/merge, mergeability unknown for merge, and non-open PR.

No remaining content blockers found. A different reviewer account is required to approve.

Re-review for issue #14 after test-coverage fix is held only due reviewer eligibility. Validation performed: - PR #24 is open and targets `master`. - Authenticated Gitea account is `jcwalker3`, which matches the PR author, so I cannot approve this PR from this account. - Latest commit reviewed: `baf4eae`. - Changed files verified exactly: `README.md`, `mcp_server.py`, `tests/test_mcp_server.py`. - `git fetch --all --prune` completed. - `git diff --check prgs/master...baf4eae` passed. - `git diff --name-only prgs/master...baf4eae` returned only the expected files. - `python3 -m py_compile mcp_server.py tests/test_mcp_server.py gitea_auth.py` passed. - `pytest tests/test_mcp_server.py` passed: 51 passed. Previous blockers verified fixed: - Explicit self-author `approve` test is present: `test_self_author_cannot_approve`. - Explicit mergeability-unknown fail-closed test is present: `test_merge_fails_closed_when_mergeability_unknown`. Manual review notes: - `gitea_check_pr_eligibility` remains read-only and uses GETs for authenticated user and PR details. - No PR review submission, approval mutation, request-changes mutation, merge mutation, issue/PR comment mutation, branch writes, Jenkins/Ops/GlitchTip/Release/deploy behavior, secrets, auth headers, raw env leakage, or credential path exposure found. - Eligibility behavior remains fail-closed for unknown identity, no configured allowed operations/profile metadata, operation not allowed/forbidden, self-author approve/merge, mergeability unknown for merge, and non-open PR. No remaining content blockers found. A different reviewer account is required to approve.
Author
Owner

Final review — content PASSES, merge HELD on identity

Read-only verification at head baf4eae:

  • PR head = baf4eae30ba6c0092867f6dd546874e2423f03ef — unchanged since review ✓
  • PR state = open, mergeable: true
  • Changed files = exactly README.md, mcp_server.py, tests/test_mcp_server.py
  • git diff --check (master...head) → clean ✓
  • Prior blockers fixed — both test_self_author_cannot_approve and test_merge_fails_closed_when_mergeability_unknown present ✓

Blocker (unchanged): reviewer identity == author. The gitea-tools MCP is authenticated as jcwalker3, which is the PR author. Per policy (and the very self-approval/self-merge rule this PR implements), the author must not approve or merge their own PR. No non-author Gitea identity is configured for this runtime, so I cannot perform an eligible merge.

Action required: a genuinely separate Gitea account must approve + merge PR #24. Content and scope have no blockers. Issue #14 stays open until an eligible account merges.

## Final review — content PASSES, merge HELD on identity Read-only verification at head `baf4eae`: - **PR head** = `baf4eae30ba6c0092867f6dd546874e2423f03ef` — unchanged since review ✓ - **PR state** = open, `mergeable: true` ✓ - **Changed files** = exactly `README.md`, `mcp_server.py`, `tests/test_mcp_server.py` ✓ - **`git diff --check`** (master...head) → clean ✓ - **Prior blockers fixed** — both `test_self_author_cannot_approve` and `test_merge_fails_closed_when_mergeability_unknown` present ✓ **Blocker (unchanged): reviewer identity == author.** The gitea-tools MCP is authenticated as `jcwalker3`, which is the PR author. Per policy (and the very self-approval/self-merge rule this PR implements), the author must not approve or merge their own PR. No non-author Gitea identity is configured for this runtime, so I cannot perform an eligible merge. **Action required:** a genuinely separate Gitea account must approve + merge PR #24. Content and scope have **no** blockers. Issue #14 stays open until an eligible account merges.
jcwalker3 reviewed 2026-07-01 13:20:30 -05:00
jcwalker3 left a comment
Author
Owner

Final review complete, merging PR #24.

Final review complete, merging PR #24.
jcwalker3 merged commit ca51fba44d into master 2026-07-01 13:20:31 -05:00
Sign in to join this conversation.