diff --git a/docs/architecture/glitchtip-readonly-tools-design.md b/docs/architecture/glitchtip-readonly-tools-design.md new file mode 100644 index 0000000..9de264d --- /dev/null +++ b/docs/architecture/glitchtip-readonly-tools-design.md @@ -0,0 +1,174 @@ +# GlitchTip Read-Only Error/Event Tools — Design Notes + +- **Status:** Design (implementation-ready notes; **no implementation in this repo**) +- **Issue:** #73 (umbrella: #75; boundary decision: ADR-0001, #71) +- **Related:** #74 (GlitchTip→Gitea filing workflow — composes these read tools), + #78 (dedup/linking, child of #74), #76 (per-service profile schema) +- **Date:** 2026-07-02 + +## 1. Purpose and scope + +Define the minimum **read-only** GlitchTip MCP tool set that lets an LLM answer: +*"What unresolved errors does project X have (by environment/release), and what +is this specific error?"* — with privacy-safe output suitable for LLM context, +issue bodies, and audit logs. + +Strictly read-only, per ADR-0001: + +- **No mutation tools** — no resolving/ignoring/assigning issues, no comment + posting, no project/team/key administration, no deletes. +- **No automatic GlitchTip→Gitea filing** (that is #74's *orchestrated, + explicitly-invoked* workflow; it composes these read tools and Gitea write + tools — never one dual-credential server). +- **This server never holds Gitea write credentials.** + +## 2. Boundary placement (namespace pending) + +These tools belong to the GlitchTip observability boundary of the MCP Control +Plane — `glitchtip-mcp` (ADR-0001's recommendation), `observability-mcp`, or +folded into `ops-mcp`. **ADR-0001 open owner decision #2 picks the name; this +design does not assume it.** Tool names below use the `glitchtip_` prefix for +readability and rename mechanically with the decision. + +Fixed regardless of the name (per `tool-boundaries.md`, +`credential-isolation.md`): + +- Own server process, own `.env`, GlitchTip credentials only. +- No Gitea, Jenkins, or Ops tokens in this runtime; no GlitchTip token + anywhere else. + +## 3. API surface note (Sentry compatibility) + +GlitchTip implements a Sentry-compatible REST API (`/api/0/...` — organizations, +projects, issues, events). The design targets **GlitchTip's documented subset** +only; Sentry-only endpoints must not be assumed. The implementation should pin +against a tested GlitchTip version and treat missing endpoints/fields as +degraded-but-safe (omit field, never crash). + +## 4. Minimum read-only tool set + +| Tool | Purpose | +|---|---| +| `glitchtip_whoami` | Verify authenticated identity + active profile (mirror of `gitea_whoami`; fail-closed identity proof) | +| `glitchtip_list_projects` | Projects visible to the token (org-scoped), with pagination bounds | +| `glitchtip_list_unresolved` | Unresolved issues for a project, filterable (§6), sorted by last-seen | +| `glitchtip_get_issue` | Safe detail of one issue (fields §5) | +| `glitchtip_recent_events` | Recent events for an issue (summaries only, §5) | +| `glitchtip_search` | Issue search within a project (query + filters §6) | + +All tools are `GET`-only. No tool issues PUT/POST/DELETE. + +## 5. Privacy: field-level allowlist (the core rule) + +Error events routinely contain PII and secrets (request bodies, cookies, +headers, tokens, user emails/IPs, local variables). Therefore: **allowlist +projection only — raw event/issue payloads are never passed through.** + +### Issue-level safe fields (`glitchtip_list_unresolved`, `glitchtip_get_issue`, `glitchtip_search`) + +| Field | Notes | +|---|---| +| `issue_id` | GlitchTip issue ID (dedup key for #78) | +| `fingerprint` | When available (dedup key for #78) | +| `title` / `culprit` | Error type + short message/transaction — redactor-passed | +| `project` | Slug | +| `level` | error/warning/… | +| `status` | unresolved/… | +| `environment` | When filtered/available | +| `release` | Version string | +| `first_seen` / `last_seen` | ISO-8601 UTC | +| `event_count` / `user_count` | Numbers only — never user identities | +| `permalink` | GlitchTip web URL (the "link, not dump" principle) | + +### Event-level safe fields (`glitchtip_recent_events`) + +`event_id`, `timestamp`, `level`, `environment`, `release`, redactor-passed +`message`, and a **stack summary** only: top N (default 5) frames as +`module/filename:function:line` — in-app frames preferred. + +### Redact / omit — never returned + +Request headers; cookies; auth/session fields; user emails, usernames, IPs; +request/form bodies; query strings; local variables; full raw stack frames +(source context lines); SDK/device metadata beyond platform name; breadcrumbs; +any `extra`/`context` blobs. + +Full raw frames or request context require a **separate, explicitly approved** +operation (`glitchtip.event.read_raw`) that is absent from default profiles — +same pattern as `jenkins.console.read` in the #72 design. Even then, output +passes the shared secret redactor; redaction failure ⇒ error, never raw text. + +**Default output = fingerprint / release / summary + permalink.** The +permalink carries the human to the full data in GlitchTip's own UI, where its +access control applies — the MCP layer does not re-serve raw payloads. + +## 6. Filtering and pagination + +Filters (all optional, combinable): `project` (required for issue/event +queries), `environment`, `release`, `fingerprint`, free-text `query` +(GlitchTip search syntax, e.g. `is:unresolved`). + +Pagination: cursor-based per the API. Bounds: per-page cap 50; default overall +cap 100 items; hard cap `max_pages` (default 10) against runaway loops — +mirroring `gitea_auth.api_get_all`. Truncation is **explicit** in the return +(`"truncated": true`) — never silent. + +## 7. Credentials and profile requirements + +Per-service profile model (`gitea-execution-profiles.md`, extended by #76): + +- Env/config: `GLITCHTIP_URL`, `GLITCHTIP_ORG`, `GLITCHTIP_TOKEN_SOURCE_NAME` + (secret **name** only; value resolved at runtime, never logged/committed). +- Profile: e.g. `glitchtip-readonly` with namespaced + `allowed_operations: ["glitchtip.read", "glitchtip.event.read"]` + (+ `glitchtip.event.read_raw` only with explicit approval); + `forbidden_operations: ["glitchtip.issue.mutate", "glitchtip.admin"]` + belt-and-braces though no mutating tool exists. +- Missing URL/org/token/profile ⇒ **fail closed** before any network call. +- Read-only ⇒ no confirmation gates; identity (`glitchtip_whoami`) must work so + workflows can prove which account they read as. + +## 8. Failure behavior (fail closed, clear, safe) + +| Condition | Behavior | +|---|---| +| Unknown project/issue | Explicit `{"found": false, ...}` — no fuzzy matching | +| GlitchTip unreachable (DNS/timeout) | `"network error contacting GlitchTip: "` — mirror `gitea_auth.api_request` conversion | +| 502/503/504 | "GlitchTip upstream unavailable" | +| 401/403 | "GlitchTip auth failed / insufficient permissions" — no credential echo | +| 429 | Honor Retry-After with capped jittered backoff (as `gitea_auth`) | +| Malformed JSON | "malformed JSON response from GlitchTip" — no raw-body dump | +| Missing profile/creds | Fail closed before any network call (§7) | + +All error text passes the shared secret redactor. + +## 9. Testing strategy (mocked; for the implementing package) + +Mocked-GlitchTip unit tests only, per `docs/developer-testing-guidelines.md`: + +- Assert method is always `GET`; URL/filter/cursor shape correct. +- **Projection tests:** response fixtures containing emails, IPs, cookies, + headers, request bodies, locals, full frames ⇒ none appear in output + (explicit negative assertions per §5's redact list). +- Stack summary: top-N frame cap enforced; source-context lines absent. +- Pagination: per-page/overall/max-pages caps; explicit `truncated` flag. +- Filters: environment/release/fingerprint/query passed through correctly. +- Failure matrix of §8 incl. no-token-in-error assertions. +- Profile gate: missing/insufficient profile ⇒ no network call + (`mock_api.assert_not_called()` pattern). +- `read_raw` op absent ⇒ raw-frame request refused without an API call. + +## 10. Implementation-readiness checklist + +Ready to implement once: + +1. ADR-0001 owner decision #2 (namespace/placement) is made — mechanical + rename of the `glitchtip_` prefix if needed. +2. ADR-0001 owner decision #1 (repo home) is made. +3. #76 profile schema exists (or a minimal `glitchtip-readonly` profile is + hand-rolled to the same rules). +4. A pinned GlitchTip version is chosen for API-subset testing (§3). + +Explicitly **not** unlocked by this document: any GlitchTip mutation, any +automatic Gitea filing (#74 designs that as a gated, explicitly-invoked +orchestrated workflow), any Gitea credentials in this boundary. diff --git a/docs/architecture/multi-service-profile-model.md b/docs/architecture/multi-service-profile-model.md new file mode 100644 index 0000000..0e1c627 --- /dev/null +++ b/docs/architecture/multi-service-profile-model.md @@ -0,0 +1,68 @@ +# Multi-Service MCP Profile and Configuration Model + +- **Status:** Design (no implementation in this repo yet) +- **Issue:** #76 (parent umbrella: #75; boundary decision: ADR-0001, #71) +- **Date:** 2026-07-02 + +## 1. Purpose and Scope + +Extend the existing Gitea execution-profile model (`docs/gitea-execution-profiles.md`) into a generic **per-service** MCP profile/config model. This supports integrating Jenkins and GlitchTip into the MCP Control Plane while strictly preserving isolation and fail-closed safety. + +**Crucial Constraints:** +* The shared profile/config model is a **schema / library**, **not a shared credential pool**. +* Tokens remain **service-local**; profiles are **per service**. +* Orchestrators **must not** directly hold every service credential. + +## 2. Profile Schema (Per Service) + +The schema reuses the proven Gitea field model, adapted per service. + +```json +{ + "profile_name": "readonly-metrics", + "service": "glitchtip", + "token_source_name": "GLITCHTIP_API_TOKEN_READONLY", + "allowed_operations": [ + "glitchtip.event.read", + "glitchtip.issue.read" + ], + "forbidden_operations": [ + "glitchtip.issue.resolve", + "glitchtip.issue.delete" + ] +} +``` + +### Schema Rules + +* `allowed_operations` are **namespaced** (e.g., `gitea.issue.create`, `jenkins.build.read`, `glitchtip.event.read`). +* `forbidden_operations`, if present, **always override** `allowed_operations`. +* `token_source_name` records the source **name only, never the value**. Tokens must never be printed, logged, or included in telemetry. + +## 3. Fail-Closed Behavior + +The model enforces strict fail-closed constraints before any network call occurs: +* **Missing Profile:** If a requested profile is undefined for the target service, the operation fails immediately. +* **Missing Credentials:** If the `token_source_name` cannot be resolved to a valid token at runtime, the operation fails immediately without retrying or prompting. + +## 4. Environment Overrides + +Profiles can be dynamically overridden or injected via environment variables, following the established hierarchy: + +1. **Explicit Environment Variable:** (Highest precedence) e.g., `MCP_GLITCHTIP_TOKEN` overrides any JSON profile. +2. **Profile Mapping in JSON:** Resolved via `token_source_name` (e.g., `GLITCHTIP_API_TOKEN_READONLY`) mapping to an environment variable or secret store. +3. **No Auth:** Fails closed. + +## 5. Audit Logging + +To maintain accountability across multi-service workflows, all mutating actions must include the audit identity and source: +* The audit log must record the `profile_name`, the orchestrator source (e.g., `sysadmin`, `jenkins-mcp`), and the action taken. +* The audit system must sanitize all output to ensure tokens are stripped (see `safety-model.md`). + +## 6. Backward Compatibility + +The existing Gitea profile behavior (`gitea_whoami`, etc.) remains strictly backward compatible. The generic profile library will parse existing Gitea profile objects without requiring them to migrate their schemas, defaulting the `service` attribute to `gitea`. + +## 7. Implementation Boundary + +Per the namespace decisions in #71 and #75, this generic model belongs in the `common` package or library. It will be imported by `gitea-mcp` (this repo), `jenkins-mcp`, and `glitchtip-mcp` without forcing a monolithic architecture. diff --git a/docs/credential-isolation.md b/docs/credential-isolation.md index e8b34b8..0981aef 100644 --- a/docs/credential-isolation.md +++ b/docs/credential-isolation.md @@ -5,5 +5,5 @@ This document describes how credentials and sensitive environment variables are ## Separate Credentials Even though multiple MCP servers share the same monorepo, they **must** have separate credentials and runtimes. -- **No Shared Environments**: Each MCP server (`gitea-mcp`, `jenkins-mcp`, `ops-mcp`, etc.) must be instantiated as an independent service with its own dedicated `.env` configuration file. +- **No Shared Environments**: Each MCP server (`gitea-mcp`, `jenkins-mcp`, `glitchtip-mcp`, `ops-mcp`, etc.) must be instantiated as an independent service with its own dedicated `.env` configuration file. - **Strict Isolation**: A server will only have access to the credentials required for its specific trust boundary. For instance, `gitea-mcp` has no access to Jenkins or Ops authentication tokens. diff --git a/docs/label-taxonomy.md b/docs/label-taxonomy.md new file mode 100644 index 0000000..e3cf98b --- /dev/null +++ b/docs/label-taxonomy.md @@ -0,0 +1,34 @@ +# Label Taxonomy + +This document catalogs the issue labels used for MCP workflows, including Jenkins and GlitchTip (observability). + +> **Approval Required:** Do not create or apply new labels in `manage_labels.py` without explicit owner approval of this document. + +## Existing Labels + +* **`jenkins`** + * Description: Jenkins integration + * Color: `d93f0b` + * Use: Used to mark issues, PRs, or tasks that involve the `jenkins-mcp` boundaries, CI/CD designs, or build failures. + +* **`glitchtip`** + * Description: GlitchTip integration + * Color: `b60205` + * Use: Used to mark issues related to the `glitchtip-mcp` boundary and observability integration. + +## Proposed / Missing Labels + +* **`observability`** + * Proposed Description: Observability, metrics, and monitoring tasks + * Proposed Color: `5319e7` + * Use: Broader than GlitchTip alone; covers logging, metrics, traces, and general observability pipeline improvements. + +* **`source:glitchtip`** + * Proposed Description: Issue filed automatically by GlitchTip orchestration + * Proposed Color: `b60205` + * Use: Applied automatically by the orchestrator when a GlitchTip error event is converted into a Gitea issue. + +* **`status:triage`** + * Proposed Description: Issue needs human or orchestrator triage + * Proposed Color: `fbca04` + * Use: Used for incoming issues (especially automated ones like `source:glitchtip`) that have not yet been evaluated for priority or resolution. diff --git a/docs/safety-model.md b/docs/safety-model.md index bcc92a4..fd2549c 100644 --- a/docs/safety-model.md +++ b/docs/safety-model.md @@ -13,3 +13,11 @@ To maintain a secure environment, all secrets, tokens, passwords, and sensitive - System and application logs - Tool return values/outputs - Any form of persistent storage or console output + +## 4. Read-Only First Policy +By default, MCP servers (such as `jenkins-mcp` and `ops-mcp`) operate in a **read-only** mode. Mutation capabilities are deny-by-default and fail-closed. + +## 5. Mutation Gating +Any mutating action (e.g., Gitea issue creation from GlitchTip, or Jenkins builds) must be explicitly allowed by the execution profile. +- **Jenkins build triggers** are explicitly deferred for phase 1. +- **GlitchTip to Gitea issue filing** is documented as a gated, orchestrated workflow, not a direct unprompted automatic action. diff --git a/docs/tool-boundaries.md b/docs/tool-boundaries.md index d5c29cd..fd53346 100644 --- a/docs/tool-boundaries.md +++ b/docs/tool-boundaries.md @@ -2,7 +2,7 @@ This document defines the strict boundaries between the different MCP server packages within the monorepo. -The project is named **MCP Control Plane** and lives in the `mcp-control-plane` repository. It groups the following packages: `common`, `gitea-mcp`, `jenkins-mcp`, `ops-mcp`, and `release-mcp`. +The project is named **MCP Control Plane** and lives in the `mcp-control-plane` repository. It groups the following packages: `common`, `gitea-mcp`, `jenkins-mcp`, `glitchtip-mcp`, `ops-mcp`, and `release-mcp`. ## 1. Architectural Philosophy - **One MCP Server per Trust Boundary**: While the packages share a monorepo, their runtime services must remain entirely separate. There is no single "everything" server. @@ -10,4 +10,5 @@ The project is named **MCP Control Plane** and lives in the `mcp-control-plane` ## 2. Package-Specific Boundaries - **gitea-mcp**: Restricted to source-control and work-item capabilities (issues, PRs, comments). This package **must not** have Jenkins or Ops credentials, nor can it execute deploy operations. - **jenkins-mcp**: Focused on CI/CD capabilities. This package **must not** have Ops credentials unless explicitly configured for a specific, isolated pipeline later. +- **glitchtip-mcp**: Dedicated to observability and error reporting. This package **must not** have Gitea write credentials or Jenkins deploy capabilities. - **ops-mcp**: Dedicated to live environment and host checks. In its initial state, this package starts as strictly read-only (e.g., health checks, status checks, log reading).