Slack
Ongrid integriert mit Slack in zwei unterschiedlichen Modi, konfiguriert auf separaten Settings-Panels:
| Modus | Verwenden für | Tokens |
|---|---|---|
| Notification | Gefeuerte Alarme in einen Channel pushen | Nur die Webhook-URL |
| Socket Mode (IM) | Mit dem Agenten von Slack aus reden | xapp-… + xoxb-… |
Sie können beide betreiben. Sie teilen nichts.
Notification (Incoming Webhook)
Die einfachste Integration. Slack weist eine workspace-spezifische URL der Form https://hooks.slack.com/services/T…/B…/… zu; Ongrid POSTet das Alarm-Payload dorthin.
Wie das Payload aussieht
Der Slack-Sender rendert eine notify.Message in das Attachments-Format (gewählt gegenüber Block Kit, weil es die farbige Seitenschiene trägt, die Operatoren als Severity lesen, und weil das Schema JSON-flach und universell unterstützt ist):
{
"text": "[CRITICAL] node-01 swap_high",
"attachments": [
{
"color": "#d92f2f",
"fallback": "[CRITICAL] node-01 swap_high",
"title": "node-01 swap_high",
"text": "swap_in_pages > 1000 for 5m",
"mrkdwn_in": ["text"],
"fields": [
{"title": "Severity", "value": "CRITICAL", "short": true},
{"title": "Source", "value": "alert", "short": true},
{"title": "Rule", "value": "swap_high","short": true},
{"title": "Incident", "value": "#1234", "short": true},
{"title": "Device", "value": "#7", "short": true},
{"title": "Dedupe key", "value": "alert:swap_high:device=7", "short": false}
],
"footer": "ongrid",
"ts": 1717012345
}
]
}Das text-Feld bleibt gefüllt, sodass Slack-Push- / E-Mail-Digest-Vorschauen einen nützlichen Einzeiler zeigen, auch wenn der Client Attachments strippt.
Severity → Farbe
| Severity | Hex |
|---|---|
| critical | #d92f2f |
| warning | #f2c037 |
| info | #36a64f |
| (unbekannt) | #6f7a87 |
Festgepinnter Hex (nicht Slacks danger / warning-Sentinel), sodass die Tönung über Slack-Client-Versionen stabil ist.
Setup
- In Slack: Apps → Incoming Webhooks → Add to Slack, Channel auswählen.
- Webhook-URL kopieren.
- In Ongrid: Settings → Channels → New → Provider =
slack→ URL in Endpoint einfügen.
Das Secret-Feld auf dem Formular wird für Slack-Incoming-Webhooks ignoriert. Die URL ist die Credential; es gibt keine separate Signaturoberfläche. Der Channel-Builder droppt das Secret, bevor er NewSlackSender konstruiert.
Den Kanal testen
Der Test-Button auf Settings → Channels sendet eine synthetische notify.Message{Severity: "info", Subject: "Ongrid test", …}. Wenn das Attachment im Ziel-Channel mit der grünen Schiene erscheint, ist der Kanal verdrahtet.
Socket Mode (IM Bridge)
Socket Mode ist die zweiseitige Integration. Eingehender User-Text wird über eine ausgehende WebSocket-Verbindung zugestellt (kein öffentliches Ingress erforderlich — gleiche Form wie Telegram getUpdates), und der Manager antwortet über die Standard-Web-API (chat.postMessage, chat.update).
Warum Socket Mode und nicht Events API
Events API erfordert, dass Slack den Manager eingehend erreicht, was bedeutet: ein öffentlicher HTTPS-Endpunkt mit gültigem Zertifikat. Die meisten Ongrid-Bereitstellungen sind privat. Socket Mode ist die unterstützte Alternative, wo der Manager nach außen wählt — er ehrt HTTPS_PROXY / NO_PROXY und funktioniert hinter NATs und der GFW. Der Validator lehnt mode != stream für Slack ab:
slack only supports stream mode (Socket Mode)
Erforderliche Tokens
Slack verwendet zwei Tokens für Socket Mode. Sie haben verschiedene Scopes:
| Token | Präfix | Verwendet für |
|---|---|---|
| App-Level-Token | xapp-… | apps.connections.open (holt eine WebSocket-URL). |
| Bot-Token | xoxb-… | chat.postMessage, chat.update, alle anderen Web-API-Aufrufe. |
Ongrid speichert sie als JSON-Objekt innerhalb im_apps.app_secret. Die ParseSecret-Funktion validiert die Präfixe vorne, sodass ein falsch eingefügtes Token als sauberer Fehler auftaucht statt als chat.postMessage 401.
{
"app_token": "xapp-1-A0…",
"bot_token": "xoxb-1234567890-1234567890-…"
}Erforderliche App-Scopes
In der Slack-App-Konfiguration:
OAuth & Permissions → Bot Token Scopes
app_mentions:read—app_mention-Events empfangen.channels:history—message-Events in öffentlichen Channels empfangen.groups:history— dasselbe für private Channels.im:history— dasselbe für DMs.chat:write—chat.postMessage/chat.update.
Socket Mode → Enable, dann Basic Information → App-Level Tokens mit Scope connections:write, um das xapp-…-Token zu bekommen.
Event Subscriptions müssen aktiviert sein (Toggle an), mit dem Bot abonniert auf message.channels, message.groups, message.im, app_mention. Slack liefert diese über Socket Mode dieselben wie über Webhook.
allow_from
Eine komma-getrennte Liste von Slack-User-IDs, die mit dem Bot konversieren dürfen. User-IDs beginnen mit U (oder W für Enterprise-Gäste). Mindestens eine ID ist erforderlich:
slack requires allow_from — at least one Slack user ID (e.g. UABC123, find via Profile → ⋯ → Copy member ID). Without it any workspace member could command a tool-equipped agent
Finden Sie Ihre eigene ID in Slack: Avatar anklicken → Profile → ⋯-Menü → Copy member ID.
Nicht in der Allowlist befindliche Sender werden stillschweigend bei handleEvent gedroppt. Der Bot antwortet nicht — er bestätigt nicht, dass er existiert. Das Verhalten spiegelt Telegram allow_from.
Streaming-Antwortverhalten
Wenn ein in der Allowlist befindlicher Benutzer eine Nachricht sendet:
- Der Bridge ruft
chat.postMessageeinmal mit einem Platzhalter-Text (Working on it…) auf und zeichnet das zurückgegebenetsauf. - Der Agent läuft. Jeder Streaming-Chunk triggert ein
chat.updateauf demselben(channel, ts). - Das terminale Token flusht den finalen Text in dieselbe Nachricht.
Slack akzeptiert ein No-Op chat.update (gleicher Text) stillschweigend — anders als Telegram, das ein 400 zurückgibt. Es gibt kein spezielles Swallow auf der Slack-Seite. Siehe senderAdapter in stream.go.
Bot-Loops, Edits und Thread-IDs
- Nachrichten mit
bot_id != ""werden gedroppt — sie sind die eigenen Antworten des Managers und würden eine Feedback-Loop erzeugen. - Nachrichten mit irgendeinem nicht-leeren
subtype(message_changed,channel_join, …) werden gedroppt. thread_tswird alsImThread.ImThreadIDgespeichert, sodass eine Antwort innerhalb eines Threads dieselbe Konversations-Session fortsetzt.- Slack
<@U…>-Mention-Markup wird durchstripMentionszu einem bloßen@U…-Token umgeschrieben, sodass das Modell eine stabile Referenz ohneusers.info-Round-Trip pro Nachricht sieht.
Setup
- Eine Slack-App erstellen: api.slack.com → Create New App → from scratch, Workspace auswählen.
- Socket Mode aktivieren, ein App-Level-Token mit
connections:writegenerieren. Denxapp-…-Wert kopieren. - Die oben aufgelisteten Bot Token Scopes setzen.
- Die App in den Workspace installieren. Das
xoxb-…Bot User OAuth Token kopieren. - Event Subscriptions aktivieren, den Bot auf die oben aufgelisteten Events abonnieren.
- In Ongrid: Settings → IM bridge → New → Provider =
slack→ Mode =stream→ app_id einfügen (das Bot-Handle, z. B.ongrid-bot), das Zwei-Token-JSON in App secret, und mindestens eine Slack-User-ID in allow_from.
App nach Hinzufügen von Scopes neu installieren
Slack gewährt bereits installierten Bots Scopes nicht rückwirkend. Wenn chat.postMessage missing_scope zurückgibt, nachdem Sie chat:write hinzugefügt haben, installieren Sie die App im Workspace neu.
Keep-Alive
Die Stream-Loop pingt alle 20s (pingInterval). Slack schließt idle Socket-Mode-Verbindungen nach ~30s. Der Ping läuft in einer Goroutine, sodass die Read-Loop nie hinter einem Write blockiert ist. Eine Slack-initiierte disconnect-Hülle schließt sauber und der Supervisor reconnectet sofort (kein Backoff-Sleep) mit einer frischen apps.connections.open-URL.