From 5aad2e62d99c7ef71777e4aa8c96b73444d55839 Mon Sep 17 00:00:00 2001 From: Jason Walker <913443@dadeschools.net> Date: Wed, 1 Jul 2026 13:03:24 -0400 Subject: [PATCH] docs: define task-scoped Gitea MCP execution profile model (#12) Add docs/gitea-execution-profiles.md defining the execution profile model for gitea-mcp: profile metadata shape, five reference profiles (gitea-issue-manager, gitea-author, gitea-reviewer, gitea-merger, gitea-owner), allowed/forbidden operation model, identity + fail-closed rules, and self-review/self-merge prevention. Model/documentation only. No runtime profile switching, no multi-token loading, no approve/merge/eligibility workflow, no secrets. Runtime config (#19), discovery (#13), eligibility (#14), review (#15), merge (#16), and audit logging (#18) are explicitly deferred. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/gitea-execution-profiles.md | 215 +++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 docs/gitea-execution-profiles.md diff --git a/docs/gitea-execution-profiles.md b/docs/gitea-execution-profiles.md new file mode 100644 index 0000000..b2c0497 --- /dev/null +++ b/docs/gitea-execution-profiles.md @@ -0,0 +1,215 @@ +# Gitea MCP Execution Profiles + +## Purpose + +This document defines the **task-scoped execution profile model** for the +`gitea-mcp` package of the MCP Control Plane. It describes *what a profile is*, +the metadata each profile carries, and the safety rules that govern which +profile may perform which Gitea operation. + +This issue defines the **model only**. It does not implement runtime profile +loading, profile switching, or any review/merge behavior — see +[Relationship to roadmap issues](#relationship-to-roadmap-issues). + +## Principle: LLMs are not roles + +The central rule of this model: + +```text +The LLM is not the role. +The MCP credential/profile used for the task is the role. +``` + +An LLM session is not permanently an "author," a "reviewer," or a "merger." +Any LLM session may perform any of these roles — but only while operating +through a **task-appropriate execution profile** whose authenticated Gitea +identity and allowed operations fit the task. + +Consequences: + +- A task selects a profile; a profile is not assigned to a model. +- The same LLM may act as author for one task and reviewer for another, by + using different profiles — never by escalating a single profile. +- Two roles that must not be held by one identity (e.g. author and merger of + the same PR) are separated by using **different authenticated identities**, + not by trusting the LLM to behave. + +## Profile model + +A Gitea MCP execution profile is a named, declarative description of an +authenticated capability set. Each profile defines the following fields: + +| Field | Type | Meaning | +|-------|------|---------| +| `profile_name` | string | Stable identifier, e.g. `gitea-reviewer`. | +| `authenticated_username` | string | The Gitea login this profile authenticates as (verified at runtime via `gitea_whoami`, not trusted from config). | +| `allowed_operations` | list | Operation categories this profile may perform. | +| `forbidden_operations` | list | Operation categories this profile must never perform. | +| `token_source_name` | string | The *name* of the secret source (e.g. env var name or secret key). **Never the token value.** | +| `audit_label` | string | Short label attached to audit records for actions by this profile. | +| `can_approve_prs` | bool | May submit an approving PR review. | +| `can_merge_prs` | bool | May merge a PR. | +| `can_push_branches` | bool | May push branches / create commits. | +| `can_mutate_issues` | bool | May create/edit/label/close issues and comment. | +| `can_author_impl_prs` | bool | May author implementation PRs (branch + commit + open PR). | + +`token_source_name` records **where** a token comes from (a variable or key +name), never the token itself. Token values are never part of a profile object, +never logged, never returned by a tool, and never committed. + +## Example profiles + +The following are the reference profiles. Booleans express intended capability +boundaries; they are the model, not a runtime enforcement mechanism yet. + +### `gitea-issue-manager` + +- **allowed:** `read`, `issue.create`, `issue.comment`, `issue.label`, `issue.close` +- **forbidden:** `pr.approve`, `pr.merge`, `branch.push` +- `can_approve_prs`: `false` +- `can_merge_prs`: `false` +- `can_push_branches`: `false` +- `can_mutate_issues`: `true` +- `can_author_impl_prs`: `false` + +### `gitea-author` + +- **allowed:** `read`, `branch.push`, `pr.create`, `pr.comment`, `issue.comment` +- **forbidden:** `pr.approve`, `pr.merge` +- `can_approve_prs`: `false` +- `can_merge_prs`: `false` +- `can_push_branches`: `true` +- `can_mutate_issues`: `false` (may comment, may not manage) +- `can_author_impl_prs`: `true` + +### `gitea-reviewer` + +- **allowed:** `read`, `pr.comment`, `pr.review`, `pr.approve`, `pr.request_changes` +- **forbidden:** `pr.merge`, `branch.push` +- `can_approve_prs`: `true` +- `can_merge_prs`: `false` +- `can_push_branches`: `false` +- `can_mutate_issues`: `false` +- `can_author_impl_prs`: `false` + +### `gitea-merger` + +- **allowed:** `read`, `pr.merge` +- **forbidden:** `pr.approve`, `branch.push`, `pr.create` +- `can_approve_prs`: `false` (a merger must not also be the sole approver) +- `can_merge_prs`: `true` +- `can_push_branches`: `false` +- `can_mutate_issues`: `false` +- `can_author_impl_prs`: `false` + +### `gitea-owner` + +- **allowed:** broad administrative access; use sparingly and never for routine + LLM workflow tasks. +- **forbidden:** nothing structurally, which is exactly why it must not be the + default profile for automated work. +- `can_approve_prs`: `true` +- `can_merge_prs`: `true` +- `can_push_branches`: `true` +- `can_mutate_issues`: `true` +- `can_author_impl_prs`: `true` + +> `gitea-owner` exists for human/administrative use. Automated LLM workflows +> should prefer the narrowest sufficient profile. An all-powerful profile is a +> convenience, not a role, and it does not exempt a session from the +> self-review / self-merge rule below. + +## Allowed and forbidden operations + +Operations are grouped into coarse categories so profiles stay readable: + +- `read` — view issues, PRs, files, identity (`gitea_whoami`). +- `issue.*` — `create`, `comment`, `label`, `close`. +- `pr.*` — `create`, `comment`, `review`, `approve`, `request_changes`, `merge`. +- `branch.push` — push branches / create commits. + +Rules: + +- `forbidden_operations` always wins over `allowed_operations`. If an operation + appears in both, it is forbidden. +- An operation not present in `allowed_operations` is treated as **not + allowed** (deny by default). +- These categories are descriptive for this issue. Their runtime enforcement is + out of scope here (see roadmap links). + +## Identity and fail-closed rules + +Before **any** mutating action, a workflow must know both: + +1. **The active profile** — which profile is in effect for this task. +2. **The authenticated identity** — the real Gitea login, verified via + `gitea_whoami` (issue #11), not read from configuration and trusted. + +Fail-closed requirements: + +- If the active profile is unknown → **stop; do not mutate.** +- If the authenticated identity cannot be determined → **stop; do not mutate.** +- If the requested operation is not in the profile's `allowed_operations`, or is + in `forbidden_operations` → **stop; do not mutate.** +- Ambiguity is treated as denial. The safe default is always "do not act." + +Read-only actions may proceed without a resolved profile, but must still never +expose token or credential material. + +## Self-review and self-merge prevention + +A profile/session **must not approve or merge a PR authored by the same +authenticated Gitea user.** + +- The check compares the profile's *verified* `authenticated_username` + (from `gitea_whoami`) against the **PR author**. +- If they match, `pr.approve` and `pr.merge` fail closed, regardless of what the + profile's capability booleans say. +- This is why author and merger/reviewer roles are separated by **identity**, + not by prompt or by a single escalating profile. It is also why this was the + concrete blocker discovered while dogfooding PR #8 for issue #52. + +## Token and secret handling + +- Token **values** are never logged, never returned by any tool, and never + committed to the repository. +- Profiles reference a `token_source_name` (a variable/key *name*) only. +- `Authorization` headers and raw credentials must never appear in tool output, + audit records, or error messages. + +## Separation from other MCP boundaries + +`gitea-mcp` profile work stays within the Gitea trust boundary. It must **not** +add or absorb Jenkins, Ops, GlitchTip, Release, deploy, rollback, migration, +restart, or production behavior. Those belong to their own MCP packages under +the "one server per trust boundary" model described in +[`tool-boundaries.md`](tool-boundaries.md) and +[`credential-isolation.md`](credential-isolation.md). + +## Relationship to roadmap issues + +This document defines the **model only**. Related work is tracked separately +under roadmap [#10](https://gitea.prgs.cc/Scaled-Tech-Consulting/Gitea-Tools/issues/10): + +- **#11** — Authenticated-user identity lookup (`gitea_whoami`). *Complete; + this model depends on it for verified identity.* +- **#19** — Runtime profile configuration via environment (loading real + profiles/tokens). *Not this issue.* +- **#13** — Read-only profile discovery (exposing the active profile). *Not this + issue.* +- **#14** — PR author / reviewer eligibility checks. *Not this issue.* +- **#15** — Gated PR review/approve actions. *Not this issue.* +- **#16** — Gated PR merge workflow. *Not this issue.* +- **#18** — Audit logging of mutating actions with profile metadata. *Not this + issue.* + +## Non-goals + +- Do **not** implement runtime profile switching or selection here. +- Do **not** implement multi-token loading here. +- Do **not** implement approve, merge, or eligibility workflows here. +- Do **not** expose, log, or commit any token or secret. +- Do **not** add Jenkins, Ops, GlitchTip, Release, deploy, or production + behavior. +- Do **not** create an all-powerful server; `gitea-owner` is administrative, not + a default automation role. -- 2.43.7