Skip to content

Slack

Ongrid s'intègre à Slack selon deux modes distincts, configurés sur des panneaux Settings séparés :

ModeÀ utiliser pourTokens
NotificationPousser les alertes déclenchées dans un canalJuste l'URL du webhook
Socket Mode (IM)Parler à l'agent depuis Slackxapp-… + xoxb-…

Vous pouvez exécuter les deux. Ils ne partagent rien.

Notification (webhook entrant)

L'intégration la plus simple. Slack assigne une URL spécifique au workspace de la forme https://hooks.slack.com/services/T…/B…/… ; Ongrid POST le payload d'alerte à cette adresse.

À quoi ressemble le payload

Le sender Slack rend un notify.Message dans le format attachments (choisi plutôt que Block Kit parce qu'il porte le rail coloré latéral que les opérateurs lisent comme sévérité, et parce que le schéma est JSON à plat et universellement supporté) :

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
    }
  ]
}

Le champ text reste rempli pour que les aperçus push / digest email de Slack montrent une ligne utile même quand le client supprime les attachments.

Sévérité → couleur

SévéritéHex
critical#d92f2f
warning#f2c037
info#36a64f
(unknown)#6f7a87

Hex épinglé (et non les sentinelles danger / warning de Slack) pour que la teinte soit stable à travers les versions de client Slack.

Configuration

  1. Dans Slack : Apps → Incoming Webhooks → Add to Slack, choisissez le canal.
  2. Copiez l'URL du webhook.
  3. Dans Ongrid : Settings → Channels → New → Provider = slack → collez l'URL dans Endpoint.

Le champ Secret du formulaire est ignoré pour les webhooks entrants Slack. L'URL est le credential ; il n'y a pas de surface de signature séparée. Le constructeur de canal supprime le secret avant de construire NewSlackSender.

Tester le canal

Le bouton Test sur Settings → Channels envoie un notify.Message{Severity: "info", Subject: "Ongrid test", …} synthétique. Si l'attachment apparaît dans le canal cible avec le rail vert, le canal est câblé.

Socket Mode (pont IM)

Socket Mode est l'intégration bidirectionnelle. Le texte utilisateur entrant est délivré sur un WebSocket sortant (pas d'ingress public requis — même forme que Telegram getUpdates), et le manager répond en utilisant l'API Web standard (chat.postMessage, chat.update).

Pourquoi Socket Mode et pas Events API

Events API requiert que Slack atteigne le manager en entrant, ce qui signifie un endpoint HTTPS public avec un certificat valide. La plupart des déploiements Ongrid sont privés. Socket Mode est l'alternative supportée où le manager compose en sortant — il honore HTTPS_PROXY / NO_PROXY et fonctionne derrière les NAT et le GFW. Le validateur rejette mode != stream pour Slack :

slack only supports stream mode (Socket Mode)

Tokens requis

Slack utilise deux tokens pour Socket Mode. Ils ont des scopes différents :

TokenPréfixeUtilisé pour
Token app-levelxapp-…apps.connections.open (obtient une URL WebSocket).
Token botxoxb-…chat.postMessage, chat.update, tous les autres appels API Web.

Ongrid les stocke comme un objet JSON dans im_apps.app_secret. La fonction ParseSecret valide les préfixes d'avance pour qu'un token mal collé remonte comme une erreur propre au lieu d'un 401 de chat.postMessage.

json
{
  "app_token": "xapp-1-A0…",
  "bot_token": "xoxb-1234567890-1234567890-…"
}

Scopes d'app requis

Dans la config de l'app Slack :

OAuth & Permissions → Bot Token Scopes

  • app_mentions:read — recevoir les événements app_mention.
  • channels:history — recevoir les événements message dans les canaux publics.
  • groups:history — pareil pour les canaux privés.
  • im:history — pareil pour les DM.
  • chat:writechat.postMessage / chat.update.

Socket Mode → Enable, puis Basic Information → App-Level Tokens avec le scope connections:write pour obtenir le token xapp-….

Event Subscriptions doit être activé (toggle on), avec le bot abonné à message.channels, message.groups, message.im, app_mention. Slack les livre sur Socket Mode de la même façon qu'il le ferait sur webhook.

allow_from

Une liste séparée par virgules d'ID utilisateurs Slack qui peuvent converser avec le bot. Les ID utilisateurs commencent par U (ou W pour les invités Enterprise). Au moins un ID est requis :

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

Trouvez votre propre ID dans Slack : cliquez sur votre avatar → Profile → le menu Copy member ID.

Les expéditeurs non listés sont silencieusement supprimés à handleEvent. Le bot ne répond pas — il ne confirme pas qu'il existe. Le comportement reflète Telegram allow_from.

Comportement de réponse en streaming

Quand un utilisateur autorisé envoie un message :

  1. Le pont appelle chat.postMessage une fois avec un texte placeholder (Working on it…) et enregistre le ts retourné.
  2. L'agent s'exécute. Chaque chunk de streaming déclenche un chat.update sur le même (channel, ts).
  3. Le token terminal flush le texte final dans le même message.

Slack accepte un chat.update no-op (même texte) silencieusement — contrairement à Telegram, qui retourne un 400. Il n'y a pas d'avalement spécial côté Slack. Voir senderAdapter dans stream.go.

Boucles de bot, edits et ID de thread

  • Les messages avec bot_id != "" sont supprimés — ce sont les propres réponses du manager et créeraient une boucle de feedback.
  • Les messages avec un subtype non vide (message_changed, channel_join, …) sont supprimés.
  • thread_ts est stocké comme ImThread.ImThreadID pour qu'une réponse à l'intérieur d'un thread continue la même session de conversation.
  • Le markup de mention Slack <@U…> est réécrit en un token @U… nu par stripMentions pour que le modèle voie une référence stable sans un round-trip users.info par message.

Configuration

  1. Créez une app Slack : api.slack.com → Create New App → from scratch, choisissez le workspace.
  2. Activez Socket Mode, générez un token app-level avec connections:write. Copiez la valeur xapp-….
  3. Définissez les Bot Token Scopes listés ci-dessus.
  4. Installez l'app dans le workspace. Copiez le Bot User OAuth Token xoxb-….
  5. Activez Event Subscriptions, abonnez le bot aux événements listés ci-dessus.
  6. Dans Ongrid : Settings → IM bridge → New → Provider = slack → Mode = stream → collez l'app_id (le handle du bot, par ex. ongrid-bot), le JSON à deux tokens dans App secret, et au moins un ID utilisateur Slack dans allow_from.

Réinstallez l'app après avoir ajouté des scopes

Slack n'accorde pas rétroactivement de scopes aux bots déjà installés. Si chat.postMessage retourne missing_scope après que vous avez ajouté chat:write, réinstallez l'app dans le workspace.

Keep-alive

La boucle de stream ping toutes les 20s (pingInterval). Slack ferme les connexions Socket Mode inactives après ~30s. Le ping tourne dans une goroutine pour que la boucle de lecture ne soit jamais bloquée derrière une écriture. Une enveloppe disconnect initiée par Slack ferme proprement et le superviseur se reconnecte immédiatement (pas de sleep de backoff) avec une URL apps.connections.open fraîche.