feat: Sentry/GlitchTip incident bridge via incident_links (Closes #612)

Add phase-1 observability bridge that turns provider observations into
normal Gitea issues and control-plane incident_links rows. Dry-run is
default; apply creates/links through sanctioned Gitea issue paths only.
Raw incidents remain non-assignable; the #600 allocator sees bridge work
only as ordinary Gitea issues. Builds on #613 substrate and #600 allocator.

Closes #612
This commit is contained in:
2026-07-10 03:18:54 -04:00
parent f20c8436aa
commit 6a179aeb85
6 changed files with 1418 additions and 13 deletions
+28
View File
@@ -1149,3 +1149,31 @@ class ControlPlaneDB:
(gitea_org, gitea_repo, int(gitea_issue_number)),
).fetchone()
return dict(row) if row else None
def get_incident_link_by_provider(
self,
*,
provider: str,
provider_issue_id: str,
provider_base_url: str | None = None,
provider_org: str | None = None,
provider_project: str | None = None,
) -> dict[str, Any] | None:
"""Lookup canonical incident_links row by provider key (#612 / #613)."""
base_url = _norm_scope(provider_base_url)
p_org = _norm_scope(provider_org)
p_project = _norm_scope(provider_project)
with self._tx(immediate=False) as conn:
row = conn.execute(
"""
SELECT * FROM incident_links
WHERE provider = ?
AND provider_base_url = ?
AND provider_org = ?
AND provider_project = ?
AND provider_issue_id = ?
LIMIT 1
""",
(provider, base_url, p_org, p_project, str(provider_issue_id)),
).fetchone()
return dict(row) if row else None