Skip to content

Slack

Ongrid integriert mit Slack in zwei unterschiedlichen Modi, konfiguriert auf separaten Settings-Panels:

ModusVerwenden fürTokens
NotificationGefeuerte Alarme in einen Channel pushenNur die Webhook-URL
Socket Mode (IM)Mit dem Agenten von Slack aus redenxapp-… + 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):

json
{
  "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

SeverityHex
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

  1. In Slack: Apps → Incoming Webhooks → Add to Slack, Channel auswählen.
  2. Webhook-URL kopieren.
  3. 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:

TokenPräfixVerwendet für
App-Level-Tokenxapp-…apps.connections.open (holt eine WebSocket-URL).
Bot-Tokenxoxb-…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.

json
{
  "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:readapp_mention-Events empfangen.
  • channels:historymessage-Events in öffentlichen Channels empfangen.
  • groups:history — dasselbe für private Channels.
  • im:history — dasselbe für DMs.
  • chat:writechat.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:

  1. Der Bridge ruft chat.postMessage einmal mit einem Platzhalter-Text (Working on it…) auf und zeichnet das zurückgegebene ts auf.
  2. Der Agent läuft. Jeder Streaming-Chunk triggert ein chat.update auf demselben (channel, ts).
  3. 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_ts wird als ImThread.ImThreadID gespeichert, sodass eine Antwort innerhalb eines Threads dieselbe Konversations-Session fortsetzt.
  • Slack <@U…>-Mention-Markup wird durch stripMentions zu einem bloßen @U…-Token umgeschrieben, sodass das Modell eine stabile Referenz ohne users.info-Round-Trip pro Nachricht sieht.

Setup

  1. Eine Slack-App erstellen: api.slack.com → Create New App → from scratch, Workspace auswählen.
  2. Socket Mode aktivieren, ein App-Level-Token mit connections:write generieren. Den xapp-…-Wert kopieren.
  3. Die oben aufgelisteten Bot Token Scopes setzen.
  4. Die App in den Workspace installieren. Das xoxb-… Bot User OAuth Token kopieren.
  5. Event Subscriptions aktivieren, den Bot auf die oben aufgelisteten Events abonnieren.
  6. 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.