feat(controller): add per-flow Slack config for incident triage#46
Conversation
ProcessIncidentEvent spawns agent Jobs that inherit SLACK_CHANNEL_ID and SLACK_BOT_TOKEN from the first configured channel under config.notifications.channels — the same default that applies to ticketing runs. There is no way today to send an incident-triage agent's MCP-based Slack output to a different channel without affecting where ticketing notifications go, which forces operators to either co-mingle ticketing and incident-triage output in one channel, or reorder the notifications list and have ticketing posts go to the wrong place. Adds two optional fields to the IncidentTriage block: - slack_channel_id replaces SLACK_CHANNEL_ID on incident-triage agent Jobs only. - slack_token_secret replaces the SLACK_BOT_TOKEN SecretKeyRef on the same Jobs, with the same well-known-key probe used by slackSecretKeyRefs (SLACK_BOT_TOKEN, SLACK_TOKEN, then the literal "token" key as a fallback). The probe logic is extracted as resolveSlackTokenKey on the Reconciler so both call sites can share it without duplication. Layered on top of baseEngineConfig following the same pattern already used for AppendSystemPrompt. When both fields are empty, behaviour is unchanged. The use-case abstraction will eventually subsume both fields. Tests added (incident_test.go): - TestProcessIncidentEvent_SlackChannelOverride: an override sets the per-call SLACK_CHANNEL_ID. - TestProcessIncidentEvent_SlackChannelDefaultsToNotificationsChannel: with no override, the channel inherits from the first notifications channel (regression guard). - TestProcessIncidentEvent_SlackTokenOverride: an override sets the SLACK_BOT_TOKEN SecretKeyRef and probes the override Secret for the well-known key. - TestProcessIncidentEvent_SlackTokenOverrideFallsBackToTokenKey: override with no well-known key falls back to the literal "token". Docs updated: docs/api/webhooks.md gains two rows in the Dispatch configuration table and a slack_channel_id / slack_token_secret pair in the Example configuration. CHANGELOG entry added under Unreleased > Added. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (3)
WalkthroughThis PR adds per-incident-triage Slack routing overrides: optional config fields allow the incident-triage agent to post to a dedicated Slack channel and use a specified Kubernetes Secret for the bot token, with secret-key probing and fallback behavior. ChangesSlack Overrides for Incident Triage Routing
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Comment |
The previous commit introduced incident_triage.slack_channel_id and incident_triage.slack_token_secret using "override" language, which mis-modelled the change as a special-case workaround grafted onto a ticketing-default. They are not overrides — they are the natural place to configure the incident flow's Slack destination, just as notifications.channels is the natural place to configure the ticketing flow's. Both flows are first-class; a single Osmia deployment can run them side-by-side with separate channels and bot tokens. The behaviour is unchanged. This commit rewords the framing: - IncidentTriageConfig field docstrings describe the fields as the incident flow's Slack config, not as overrides of a default. - The dispatch-time comment in incident.go describes the two flows as peers reading from their respective YAML locations. - Tests renamed from _SlackChannelOverride to _PostsToConfiguredSlackChannel, _SlackChannelDefaultsToNotificationsChannel to _FallsBackToTicketingSlackChannel, _SlackTokenOverride to _UsesConfiguredSlackTokenSecret, and _SlackTokenOverrideFallsBackToTokenKey to _FallsBackToTokenKeyForUnnamedSlackSecret. Assertion messages updated to match. The shared helper is renamed from incidentTestConfigWithDefaultSlack to incidentTestConfigWithTicketingSlack to reflect that the configured channel is the ticketing flow's, not a generic "default". - docs/api/webhooks.md Dispatch-configuration rows reframe the fields as per-flow config. The example YAML in the Example configuration block now describes the two flows running side-by-side rather than overriding one with the other. - CHANGELOG entry under [Unreleased] > Added rewritten to lead with "Per-flow Slack config for incident triage" rather than "Per-use-case Slack overrides". The backward-compatibility behaviour is unchanged: when the IncidentTriage Slack fields are empty, the incident flow falls back to notifications.channels[0] (single-channel deployments keep working without changes). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
Add a per-flow `incident_triage.incident_io_api_key_secret` config field
that mounts `INCIDENT_IO_API_KEY` onto incident-triage agent Jobs via
SecretKeyRef. When the env var is present at job startup, setup-claude.sh
registers the incident.io remote MCP server (mcp.incident.io/mcp, HTTP
transport, Bearer-token auth) in the workspace mcp.json. When empty no
MCP server is registered — ticketing pods are unaffected.
The Bearer header is templated into mcp.json via `jq --arg` rather than
Claude Code's runtime `${VAR}` substitution, which has known bugs for
HTTP MCP headers (anthropics/claude-code#51581, #6204).
Mirrors the per-flow config precedent from #46.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
#50) Add a per-flow `incident_triage.incident_io_api_key_secret` config field that mounts `INCIDENT_IO_API_KEY` onto incident-triage agent Jobs via SecretKeyRef. When the env var is present at job startup, setup-claude.sh registers the incident.io remote MCP server (mcp.incident.io/mcp, HTTP transport, Bearer-token auth) in the workspace mcp.json. When empty no MCP server is registered — ticketing pods are unaffected. The Bearer header is templated into mcp.json via `jq --arg` rather than Claude Code's runtime `${VAR}` substitution, which has known bugs for HTTP MCP headers (anthropics/claude-code#51581, #6204). Mirrors the per-flow config precedent from #46. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Adds two fields under
config.incident_triageso the ticketing and incident-triage flows can post to their own Slack channels with their own bot tokens, side by side:slack_channel_id— the Slack channel for the incident-triage agent Job's MCP-based notifications.slack_token_secret— the Kubernetes Secret backingSLACK_BOT_TOKENfor the same Job. Probed for well-known keys (SLACK_BOT_TOKEN,SLACK_TOKEN) with a fallback to the literaltokenkey, matchingslackSecretKeyRefs.When both fields are empty, the incident flow falls back to the first configured channel under
notifications.channels— single-channel deployments keep working without changes.Why
The ticketing flow reads its Slack channel from the first entry under
notifications.channels. The incident-triage flow had nowhere to read its own channel from — every agent inherited the ticketing channel, so a deployment that wanted both flows live (ours, for example) had no way to separate their Slack output. Reordering the notifications list would just move the problem to ticketing.Both flows are first-class. Each reads its Slack channel from its own YAML location:
A single Osmia deployment can run both flows concurrently with separate channels and bot tokens — the two reconcilers (
ProcessTicket,ProcessIncidentEvent) build their per-callEngineConfigindependently, so each agent Job ends up with the rightSLACK_CHANNEL_IDandSLACK_BOT_TOKENSecretKeyRef for its flow.What's added
internal/config/config.go—IncidentTriageConfiggainsSlackChannelIDandSlackTokenSecret.internal/controller/controller.go— newresolveSlackTokenKey(ctx, tokenSecret)helper that probes a Secret forSLACK_BOT_TOKEN/SLACK_TOKENand falls back totoken, matchingslackSecretKeyRefs's default key resolution.internal/controller/incident.go—ProcessIncidentEventreads the per-flow Slack settings offIncidentTriageConfigand sets them on the per-callEngineConfig.EnvandEngineConfig.SecretKeyRefs, layered on top ofbaseEngineConfigexactly like the existingAppendSystemPromptfield.tokenkey when the Secret lacks a well-known name.docs/api/webhooks.md, plus a paired example in the Example configuration section showing both flows side by side.[Unreleased] > Added.Test plan
go build ./...clean.go test ./internal/controller/... -run TestProcessIncidentEvent -v— all 11 incident tests pass (7 existing + 4 new).go test ./...— full suite green, no regressions.gofmt -lclean on touched files.incident_triage.slack_channel_idto a separate channel fromnotifications.channels[0]and confirm the next agent run posts there.Summary by CodeRabbit
New Features
Documentation
Tests