feat: interactive setup menu for canonical Gitea MCP profiles (#31) #32
Reference in New Issue
Block a user
Delete Branch "feat/gitea-config-menu"
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 #31. Refs #10, #19.
⚠️ Stacked PR
Base branch is
feat/json-runtime-profiles(PR #30), notmaster— this builds on the canonical runtime-profiles code that isn't on master yet. Merge #30 first, then this PR's diff reduces to just the menu additions. (If Gitea shows #30's commits here, that's the stack; the net-new files aregitea_config_menu.py,tests/test_config_menu.py, plus additions togitea_config.pyandREADME.md.)What
Interactive utility so users create/edit/validate canonical profiles and generate safe LLM launcher snippets without hand-editing JSON or pasting tokens into Claude/Gemini/Codex configs.
Menu: list / add / edit / remove profiles · validate config · test profile auth · show authenticated user · generate launcher snippets (Claude/Gemini/Codex) · check reviewer eligibility for a PR.
Profile creation
Prompts for name, base URL, username, default owner/repo, execution profile, and auth type:
security add-generic-passwordunder an id likeprgs-reviewer-token; profile records only{ "type": "keychain", "id": ... }.{ "type": "env", "name": "GITEA_TOKEN_PRGS_REVIEWER" }; user sets the env var themselves.Token safety (core requirement)
profiles.json, launcher snippets, logs, or errors — only keychain ids / env var names are stored.securityas an argument only.command,args,GITEA_MCP_CONFIG,GITEA_MCP_PROFILE.Config output
Writes one canonical file (default
~/.config/gitea-tools/profiles.json): creates parent dirs, atomic temp-then-os.replace, pretty JSON, preserves existing profiles.Auth test / eligibility (read-only, on demand)
/api/v1/user, prints the username.ELIGIBLE/INELIGIBLE(open PR AND reviewer ≠ author). Never approves or merges.Backwards compatibility
Menu is optional; env-only mode and MCP server startup are unchanged.
Tests / checks
tests/test_config_menu.py— 21 cases: name validation, preserve-on-add, dup/invalid/missing-field rejection, atomic write (+ replace-failure leaves original intact, no temp debris),keychain_setstores-without-printing, launcher snippets secret-free, eligibility eligible/self-author/closed, and a full menu add→list→quit flow asserting the token value never reaches disk or stdout.py_compileclean;python gitea_config.py menusmoke-tested (menu renders, quits cleanly; no-arg prints usage). Every side effect (stdin/secret/stdout/keychain/HTTP) is injectable — tests use no real keychain or network.Files changed
gitea_config.py(+authoring helpers,menudispatch),gitea_config_menu.py(new),tests/test_config_menu.py(new),README.md.⚠️ Authored by me — do not self-merge. Needs review by another author, after PR #30 merges.
Let one MCP server select among named Gitea runtime profiles from a JSON file instead of editing code or juggling many .env files: GITEA_MCP_CONFIG=/path/to/gitea-mcp.json GITEA_MCP_PROFILE=dev - New gitea_config.py: load/validate the JSON, select the named profile, and resolve its token by env-var reference. Profiles supply base_url, profile_name, token_env, owner/repo, allowed/forbidden operations, and audit label. - gitea_auth.get_profile() now overlays env over the selected JSON profile: explicit env vars win, the JSON profile fills only what env leaves unset. - gitea_auth.get_auth_header() gains a JSON token_env fallback after explicit env tokens (env still wins). Security / safety: - Tokens are referenced by env-var NAME (token_env); an inline "token" is rejected and never echoed. The value is never stored in or returned as profile metadata. - Fail-safe errors: missing file / invalid JSON / unknown or unset selected profile raise a clear ConfigError that never prints file contents or tokens (JSONDecodeError context is suppressed so the raw file text can't surface). - No network calls during config parsing. - Real config files are gitignored (gitea-mcp*.json), example kept. Backwards compatible: with GITEA_MCP_CONFIG unset, behaviour is exactly the prior env-only behaviour (all existing get_profile/get_auth_header tests pass unchanged). Docs: README JSON-profiles section + env table rows, .env.example placeholders, gitea-mcp.example.json. Tests: tests/test_config.py (22 cases) — env-only, selection, multiple profiles, env-override precedence, missing file, invalid JSON, missing/unset profile, inline-token rejection + redaction, and no-network-during-parse. Refs #10. Note: issue #19 (env-based profiles) was already implemented and closed; this JSON-file capability is adjacent new scope tracked under the roadmap rather than reopening #19. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Reopened. Was auto-closed when its base branch
feat/json-runtime-profileswas deleted; the menu work never reachedmaster. Base branch re-pushed and PR reopened. Merge after #30, then re-point this base tomaster(or rebase) if needed.Pull request closed