cb6ae0ca50ea3fea3beae9c9544c257bf6c9949b
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e168978579 |
feat: add Sentry-to-Gitea incident bridge for MCP workflow failures (Closes #607)
Adds the read half of the inbound observability path: pull unresolved issues
and events from the self-hosted Sentry API, normalize them into #612
observations, and reconcile them into durable Gitea issues.
Design: the existing #612 incident_bridge already owns dedupe, linking,
redaction, and issue creation on the #613 incident_links substrate, so this
change adds only what was genuinely missing - a Sentry API read layer,
observation mapping, a policy gate, and a watchdog. No second linking store is
introduced, which is what makes the mapping survive restarts (AC6).
New module sentry_incident_bridge.py:
* list_issues() with Link-header cursor pagination and statsPeriod windowing
* get_issue_events() returning sanitized recent + latest event
* observation_from_issue() mapping onto the #612 observation contract
* should_bridge_issue() policy gate (unresolved + event-count threshold)
* watchdog() scanning and reconciling, dry-run by default
* HTTP access injected as http_fn so the surface is testable without Sentry
New MCP tools: gitea_sentry_list_issues, gitea_sentry_get_issue_events,
gitea_sentry_reconcile_issue, gitea_sentry_link_gitea_issue,
gitea_sentry_watchdog.
Safety:
* SENTRY_AUTH_TOKEN is read from the environment only and never returned,
logged, or stored; config projections cannot carry it by construction
* missing config fails closed as not_configured, and a missing token fails
closed as missing_token before any HTTP call is made
* apply=true requires both MCP_SENTRY_ISSUE_BRIDGE_ENABLED and issue-create
permission; Sentry outages create nothing
* secrets are redacted and absolute local paths reduced to a category token
before any value can reach a Gitea issue body
* raw Sentry incidents are never assignable control-plane work items
Tests: 38 new cases covering create, update/recurrence, dedupe, resolved-issue
non-reopen, redaction, pagination, missing token, unavailable server,
self-hosted base URL, restart persistence, policy gates, and the five tool
wrappers.
Full suite: 3733 passed, 6 skipped. The 2 remaining failures
(test_issue_702_review_findings_f1_f6, test_reconciler_supersession_close) were
verified to fail identically on unmodified master at
|
||
|
|
78cc37a977 |
feat(observability): optional self-hosted Sentry instrumentation for MCP workflow failures (Closes #606)
Add an env-var-gated, off-by-default Sentry SDK integration so MCP runtime errors, fail-closed workflow blockers, lease/terminal-lock/stale-runtime collisions, and recurring watchdog check-ins are visible in a self-hosted Sentry at https://sentry.prgs.cc/. Gitea stays the source of truth; Sentry is observe-only. New module `sentry_observability.py` mirrors the `gitea_audit` conventions (env-gated, best-effort, redacting): - Config from MCP_SENTRY_ENABLED / SENTRY_DSN / SENTRY_ENVIRONMENT / SENTRY_RELEASE / MCP_SENTRY_TRACES_SAMPLE_RATE / MCP_SENTRY_ENABLE_LOGS. Active only when enabled AND a DSN is present; otherwise a hard no-op. - Fail OPEN for observability (never blocks a tool success path) and fail CLOSED for redaction (drop a field rather than risk leaking it). - `scrub_event` before_send/before_send_log hook + allowlisted tags: no tokens/passwords/keychain ids/DSNs/cookies, no raw session-state or full prompt bodies (session_id -> 12-char hash), no full filesystem paths (worktree path -> coarse category). Reuses incident_bridge + gitea_audit scrubbers. - capture_exception, capture_workflow_blocker (with canonical next action), and monitor_checkin with six stable cron slugs (stale lease scan, terminal lock scan, allocator health, namespace health, dashboard freshness, reconciler cleanup). - `sentry_sdk` is a lazily-imported optional dependency; the module imports and no-ops cleanly when the package is absent. Wiring in gitea_mcp_server.py (additive, guarded, best-effort): - init_sentry() in __main__ before mcp.run. - capture_exception in the `_audited` failure path; capture_workflow_blocker in `_audit_pr_result` BLOCKED/FAILED path. - allocator + namespace-health watchdog check-ins at their MCP tool sites (domain modules left pure). Also: pin `sentry-sdk==2.20.0` (optional), document the six env vars in `.env.example`, and add `docs/observability/sentry-integration.md` covering project creation in https://sentry.prgs.cc/, DSN handling, local/dev/prod config, redaction guarantees, and coexistence with the #612 incident bridge. Tests: tests/test_sentry_observability.py (36 cases) cover disabled / enabled / missing-DSN / missing-SDK, redaction, exception capture, workflow-blocker capture, and cron check-in behaviour. Full suite: 2632 passed, 6 skipped. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]> |