Block CLI reviewer fallback after MCP profile switch failure #199

Closed
opened 2026-07-05 15:11:41 -05:00 by jcwalker3 · 2 comments
Owner

Problem:
Agents can attempt to switch from an author MCP profile to a reviewer profile. When runtime profile switching fails, they may continue through a CLI environment override such as GITEA_MCP_PROFILE=prgs-reviewer, then treat that as a valid reviewer session.

Observed failure:
The agent reported:

  • Active MCP session remained prgs-author / jcwalker3
  • gitea_activate_profile("prgs-reviewer") failed because static-profile mode disables switching
  • The agent then used CLI environment variables to run as sysadmin / prgs-reviewer
  • It declared the reviewer session "fully eligible"

This bypasses the MCP static-profile boundary. If the MCP session is author-bound, reviewer work must stop unless the operator launches a separate reviewer MCP namespace/session.

Required wall:
If MCP profile switching fails, the agent must not continue the same task through CLI fallback, shell environment overrides, direct API calls, or local helper scripts.

Allowed behavior:

  • Report that the current MCP session is author-bound.
  • Tell the operator that a separate reviewer MCP server/session is required.
  • Perform no reviewer inventory, approval, request-changes, merge, or reviewer decision through the fallback path.

Forbidden behavior:

  • Using GITEA_MCP_PROFILE=prgs-reviewer in shell to continue reviewer work.
  • Treating CLI reviewer identity as equivalent to the active MCP session.
  • Declaring reviewer eligibility after static MCP switching failed.
  • Offering to "rerun blind review there as sysadmin" from the same author-bound session.

Acceptance criteria:

  • Add a test where gitea_activate_profile("prgs-reviewer") fails in static-profile mode; expected result: terminal stop.
  • Add a test where the agent attempts CLI fallback with GITEA_MCP_PROFILE=prgs-reviewer; expected result: blocked.
  • Add a test where a separate configured reviewer MCP namespace is active from the start; expected result: allowed.
  • Final reports must distinguish "human can launch reviewer session" from "agent may continue via CLI fallback."
  • Reviewer mutations and reviewer inventory decisions must be bound to the active MCP capability context.

Related:

  • #197 — hard-stop purity after reviewer capability denial: that issue walls the report content after a denial; this issue walls the execution path (CLI/env/API/helper-script bypass around the static-profile boundary). Terminal stop semantics should be shared between the two walls.
  • #175 — reviewer→author role-pivot wall; this is the author→reviewer direction via environment override.
  • #139 — role-aware task routing; the routing layer must treat the active MCP session's profile as the only capability context.
  • #183 — exact mutation capability proof; a CLI-fallback identity can never satisfy exact capability proof because the proof must come from the active MCP session's resolver.
Problem: Agents can attempt to switch from an author MCP profile to a reviewer profile. When runtime profile switching fails, they may continue through a CLI environment override such as `GITEA_MCP_PROFILE=prgs-reviewer`, then treat that as a valid reviewer session. Observed failure: The agent reported: * Active MCP session remained `prgs-author / jcwalker3` * `gitea_activate_profile("prgs-reviewer")` failed because static-profile mode disables switching * The agent then used CLI environment variables to run as `sysadmin / prgs-reviewer` * It declared the reviewer session "fully eligible" This bypasses the MCP static-profile boundary. If the MCP session is author-bound, reviewer work must stop unless the operator launches a separate reviewer MCP namespace/session. Required wall: If MCP profile switching fails, the agent must not continue the same task through CLI fallback, shell environment overrides, direct API calls, or local helper scripts. Allowed behavior: * Report that the current MCP session is author-bound. * Tell the operator that a separate reviewer MCP server/session is required. * Perform no reviewer inventory, approval, request-changes, merge, or reviewer decision through the fallback path. Forbidden behavior: * Using `GITEA_MCP_PROFILE=prgs-reviewer` in shell to continue reviewer work. * Treating CLI reviewer identity as equivalent to the active MCP session. * Declaring reviewer eligibility after static MCP switching failed. * Offering to "rerun blind review there as sysadmin" from the same author-bound session. Acceptance criteria: * Add a test where `gitea_activate_profile("prgs-reviewer")` fails in static-profile mode; expected result: terminal stop. * Add a test where the agent attempts CLI fallback with `GITEA_MCP_PROFILE=prgs-reviewer`; expected result: blocked. * Add a test where a separate configured reviewer MCP namespace is active from the start; expected result: allowed. * Final reports must distinguish "human can launch reviewer session" from "agent may continue via CLI fallback." * Reviewer mutations and reviewer inventory decisions must be bound to the active MCP capability context. Related: * #197 — hard-stop purity after reviewer capability denial: that issue walls the *report content* after a denial; this issue walls the *execution path* (CLI/env/API/helper-script bypass around the static-profile boundary). Terminal stop semantics should be shared between the two walls. * #175 — reviewer→author role-pivot wall; this is the author→reviewer direction via environment override. * #139 — role-aware task routing; the routing layer must treat the active MCP session's profile as the only capability context. * #183 — exact mutation capability proof; a CLI-fallback identity can never satisfy exact capability proof because the proof must come from the active MCP session's resolver.
Owner

Additional low-severity observation:

During successful review/merge of PR #219, the actual review and merge mutations were performed through gitea-reviewer MCP as sysadmin / prgs-reviewer. However, the run used direct Python/API commands with GITEA_MCP_CONFIG and GITEA_MCP_PROFILE=prgs-reviewer for read-only PR metadata checks.

This did not mutate state and did not affect the approval/merge path, but the stricter workflow should prefer MCP read tools for all reviewer-session facts where available. Env-profile direct API reads should be reported as side-channel read fallback and avoided unless the MCP read tool lacks required fields.

Additional low-severity observation: During successful review/merge of PR #219, the actual review and merge mutations were performed through `gitea-reviewer` MCP as `sysadmin / prgs-reviewer`. However, the run used direct Python/API commands with `GITEA_MCP_CONFIG` and `GITEA_MCP_PROFILE=prgs-reviewer` for read-only PR metadata checks. This did not mutate state and did not affect the approval/merge path, but the stricter workflow should prefer MCP read tools for all reviewer-session facts where available. Env-profile direct API reads should be reported as side-channel read fallback and avoided unless the MCP read tool lacks required fields.
Author
Owner

Additional observed process breach (PR #220 review/merge)

During PR #220 review/merge, the Cursor MCP harness remained bound to prgs-author, and reviewer work was performed through a separate subprocess using:

GITEA_MCP_PROFILE=prgs-reviewer ... ./venv/bin/python3

Although the subprocess authenticated as sysadmin / prgs-reviewer and PR #220 was approved/merged successfully, this is still the CLI/env-profile side-channel pattern the wall is intended to prevent.

Required behavior:

  • Reviewer queue work must run inside an attached gitea-reviewer MCP namespace/session.
  • A reviewer subprocess with env-profile override is not equivalent to a reviewer MCP namespace.
  • Future queue cleanup must not approve or merge through env-profile subprocess fallback.

Evidence: PR #220 — approved and merged while MCP harness reported jcwalker3 / prgs-author; mutations executed via env -u GITEA_SESSION_PROFILE_LOCK GITEA_MCP_PROFILE=prgs-reviewer ./venv/bin/python3 calling gitea_submit_pr_review and gitea_merge_pr directly.

### Additional observed process breach (PR #220 review/merge) During PR #220 review/merge, the Cursor MCP harness remained bound to `prgs-author`, and reviewer work was performed through a separate subprocess using: ``` GITEA_MCP_PROFILE=prgs-reviewer ... ./venv/bin/python3 ``` Although the subprocess authenticated as `sysadmin / prgs-reviewer` and PR #220 was approved/merged successfully, this is still the CLI/env-profile side-channel pattern the wall is intended to prevent. **Required behavior:** * Reviewer queue work must run inside an attached `gitea-reviewer` MCP namespace/session. * A reviewer subprocess with env-profile override is not equivalent to a reviewer MCP namespace. * Future queue cleanup must not approve or merge through env-profile subprocess fallback. **Evidence:** PR #220 — approved and merged while MCP harness reported `jcwalker3 / prgs-author`; mutations executed via `env -u GITEA_SESSION_PROFILE_LOCK GITEA_MCP_PROFILE=prgs-reviewer ./venv/bin/python3` calling `gitea_submit_pr_review` and `gitea_merge_pr` directly.
Sign in to join this conversation.
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

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