feat: block direct MCP imports and unsanctioned keychain access (Closes #558)

Require a sanctioned MCP daemon (or pytest) before get_auth_header and
keychain credential fill so raw shell imports cannot bypass preflight gates.
This commit is contained in:
2026-07-08 22:49:03 -04:00
parent 9a2e585a9e
commit 8ff1924047
7 changed files with 209 additions and 0 deletions
+8
View File
@@ -408,6 +408,14 @@ The guard blocks when the **control checkout** (repository root) is:
`branches/...` directories are disposable role worktrees; the root checkout is
the stable orchestration surface only.
## No direct-import mutation path (#558)
Never `import gitea_mcp_server` or call `gitea_auth.get_auth_header` /
keychain fill from a raw shell to bypass MCP preflight.
Use the official MCP daemon only. See [`docs/mcp-daemon-import-guard.md`](mcp-daemon-import-guard.md).
## Shell Spawn Hard-Stop Rule
Symptom: a shell tool call returns `exit_code: -1` with empty stdout/stderr.
+23
View File
@@ -0,0 +1,23 @@
# MCP daemon import and keychain guard (#558)
## Problem
During deadlock debugging, agents imported `gitea_mcp_server` / ran credential
helpers from a raw shell, bypassing preflight purity and role gates.
## Rule
Mutation auth and keychain fill require a **sanctioned MCP daemon** process.
| Context | Allowed |
|---------|---------|
| Official MCP entrypoint (`mcp_server.py` / `gitea_mcp_server` `__main__`) sets `GITEA_MCP_SANCTIONED_DAEMON=1` | yes |
| pytest | yes |
| `GITEA_ALLOW_DIRECT_MCP_IMPORT=1` (operator/tests only) | yes |
| bare `python -c 'import gitea_auth; get_auth_header(...)'` | **no** |
| keychain fill without daemon | **no** unless `GITEA_ALLOW_KEYCHAIN_CLI=1` |
## Operator note
LLM sessions must never set the allow-direct-import or allow-keychain-cli
overrides. Those are human-only escape hatches.