Add durable, opt-in audit logging for every mutating Gitea MCP action so an
operator can see which execution profile and authenticated Gitea user
performed (or was blocked from / failed) each mutation.
- New gitea_audit.py: pure, no-network module — recursive secret redaction
(token/password/authorization keys; token/Basic/Bearer value runs),
build_event (timestamp, action, result, profile, audit label, authenticated
username, repo, issue/PR, target branch, head SHA, redacted request
metadata), and an append-only JSON Lines sink.
- mcp_server.py: _audit helper + _audited context manager (simple mutations)
and an _audit_pr_result decorator (gated review/merge tools, reading their
own result dict) wired into create_issue, create_pr, edit_pr, close_issue,
commit_files, delete_branch, create_label, set_issue_labels, mark_issue
(label/unlabel), gitea_submit_pr_review, and gitea_merge_pr.
- Outcomes recorded as allowed/blocked/failed/succeeded; blocked and failed
eligibility checks are logged, not just successes.
Off by default: records are written only when GITEA_AUDIT_LOG is set. When it
is unset every audit path short-circuits — no records, no extra API calls — so
existing tool behaviour and API call sequences are unchanged. Auditing never
raises; sink writes are best-effort. Tokens are never written.
Docs: README env table + audit note, .env.example placeholder.
Tests: tests/test_audit.py (19 cases) — redaction, event build, sink writes,
per-tool success/failure/blocked records, secret-free output, off-by-default
no-op, and audit-failure-never-breaks-action.
Closes#18
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a read-only MCP tool that reports the active runtime execution
profile so an LLM can inspect what the current process is configured to
do before deciding whether to attempt an action later.
- gitea_get_profile: returns profile_name, allowed/forbidden operation
categories, audit_label, token_source_name (a NAME, never a value),
base_url, remote, resolved server, and — optionally — the verified
authenticated username. Identity resolution fails soft and marks
identity_status (verified/unknown/unavailable/not_resolved); the
profile config is always returned. Never mutates Gitea.
- gitea_auth.get_profile(): extended with forbidden_operations,
audit_label, token_source_name from env (non-secret metadata).
- .env.example / README: document the new optional metadata vars and
the discovery tool.
- tests: metadata parsing, verified/unavailable/unknown identity paths,
skip-identity, and secret-redaction.
Read-only. No token exposure. No multi-token switching. No PR
eligibility, review, or merge workflow. No Jenkins/Ops/GlitchTip/
Release/deploy behavior.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Allow the same MCP server to run as separate MCP entries, each with its
own token and profile name, so roles stay task-scoped (the profile is
the role, not the LLM).
- gitea_auth.get_profile(): reads GITEA_PROFILE_NAME,
GITEA_ALLOWED_OPERATIONS, GITEA_BASE_URL as non-secret metadata.
Never reads/returns/logs the token.
- gitea_whoami now surfaces the safe profile metadata (name + allowed
operations) alongside identity; token still never exposed.
- .env.example: placeholder-only template for a runtime profile.
- .gitignore: track .env.example while keeping real .env* ignored.
- README: document multiple env-configured MCP entries.
- tests: profile defaults/parsing, token-never-included, whoami surfaces
profile without leaking token.
One token + one profile per process. No multi-token switching in a
single runtime. No approve/merge/eligibility workflow. No
Jenkins/Ops/GlitchTip/Release/deploy behavior. No real secrets.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>