Skip to content

Slack

O Ongrid se integra com Slack em dois modos distintos, configurados em painéis de Settings separados:

ModoUse paraTokens
NotificaçãoPush de alertas disparados para um canalApenas a URL do webhook
Socket Mode (IM)Falar com o agent do Slackxapp-… + xoxb-…

Você pode rodar ambos. Eles não compartilham nada.

Notificação (incoming webhook)

A integração mais simples. O Slack atribui uma URL específica do workspace no formato https://hooks.slack.com/services/T…/B…/…; o Ongrid faz POST do payload de alerta lá.

Como o payload se parece

O sender Slack renderiza um notify.Message no formato attachments (escolhido sobre Block Kit porque carrega o trilho de cor lateral que operadores leem como severity, e porque o schema é JSON-flat e universalmente suportado):

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

O campo text continua populado para que previews de push / email digest do Slack mostrem um one-liner útil mesmo quando o client retira attachments.

Severity → cor

SeverityHex
critical#d92f2f
warning#f2c037
info#36a64f
(unknown)#6f7a87

Hex fixado (não a sentinel danger / warning do Slack) para que o tom seja estável entre versões de client Slack.

Configuração

  1. No Slack: Apps → Incoming Webhooks → Add to Slack, escolha o canal.
  2. Copie a URL do webhook.
  3. No Ongrid: Settings → Channels → New → Provider = slack → cole a URL em Endpoint.

O campo Secret no form é ignorado para Slack incoming webhooks. A URL é a credencial; não há superfície separada de assinatura. O channel builder descarta o secret antes de construir NewSlackSender.

Teste o canal

O botão Test em Settings → Channels envia uma sintética notify.Message{Severity: "info", Subject: "Ongrid test", …}. Se o attachment aparece no canal alvo com o trilho verde, o canal está conectado.

Socket Mode (ponte IM)

Socket Mode é a integração two-way. Texto inbound de usuário é entregue por um WebSocket outbound (sem necessidade de ingress público — mesmo formato do Telegram getUpdates), e o manager responde usando a Web API padrão (chat.postMessage, chat.update).

Por que Socket Mode e não Events API

A Events API exige que o Slack alcance o manager inbound, o que significa um endpoint HTTPS público com um certificado válido. A maioria dos deployments Ongrid é privada. Socket Mode é a alternativa suportada onde o manager disca para fora — honra HTTPS_PROXY / NO_PROXY e funciona atrás de NATs e do GFW. O validator rejeita mode != stream para Slack:

slack only supports stream mode (Socket Mode)

Tokens obrigatórios

O Slack usa dois tokens para Socket Mode. Eles têm escopos diferentes:

TokenPrefixoUsado para
App-level tokenxapp-…apps.connections.open (obtém uma URL WebSocket).
Bot tokenxoxb-…chat.postMessage, chat.update, todas as outras chamadas da Web API.

O Ongrid os armazena como um objeto JSON dentro de im_apps.app_secret. A função ParseSecret valida os prefixos de cara para que um token mal colado apareça como um erro limpo em vez de um 401 no chat.postMessage.

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

Scopes de app obrigatórios

Na config do app Slack:

OAuth & Permissions → Bot Token Scopes

  • app_mentions:read — receber events app_mention.
  • channels:history — receber events message em canais públicos.
  • groups:history — idem para canais privados.
  • im:history — idem para DMs.
  • chat:writechat.postMessage / chat.update.

Socket Mode → Enable, então Basic Information → App-Level Tokens com scope connections:write para obter o token xapp-….

Event Subscriptions precisa estar habilitado (toggle on), com o bot inscrito em message.channels, message.groups, message.im, app_mention. O Slack distribui esses pelo Socket Mode da mesma forma que faria via webhook.

allow_from

Uma lista separada por vírgula de IDs de usuário Slack que podem conversar com o bot. IDs de usuário começam com U (ou W para Enterprise guests). Pelo menos um ID é obrigatório:

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

Encontre seu próprio ID no Slack: clique seu avatar → Profile → o menu Copy member ID.

Senders não-allowlisted são silenciosamente descartados em handleEvent. O bot não responde — não confirma que existe. O comportamento espelha allow_from do Telegram.

Comportamento de resposta em streaming

Quando um usuário allowlisted envia uma mensagem:

  1. A ponte chama chat.postMessage uma vez com um texto placeholder (Working on it…) e grava o ts retornado.
  2. O agent roda. Cada chunk de streaming dispara um chat.update no mesmo (channel, ts).
  3. O token terminal faz flush do texto final na mesma mensagem.

O Slack aceita um chat.update no-op (mesmo texto) silenciosamente — diferente do Telegram, que retorna 400. Não há tratamento especial do lado Slack. Veja senderAdapter em stream.go.

Loops de bot, edits, e IDs de thread

  • Mensagens com bot_id != "" são descartadas — são as próprias respostas do manager e criariam um feedback loop.
  • Mensagens com qualquer subtype não-vazio (message_changed, channel_join, …) são descartadas.
  • thread_ts é armazenado como ImThread.ImThreadID para que uma resposta dentro de uma thread continue a mesma sessão de conversa.
  • Marcação de menção Slack <@U…> é reescrita para um token cru @U… por stripMentions para que o modelo veja uma referência estável sem um round-trip users.info por mensagem.

Configuração

  1. Crie um app Slack: api.slack.com → Create New App → from scratch, escolha o workspace.
  2. Habilite Socket Mode, gere um app-level token com connections:write. Copie o valor xapp-….
  3. Configure os Bot Token Scopes listados acima.
  4. Instale o app no workspace. Copie o Bot User OAuth Token xoxb-….
  5. Habilite Event Subscriptions, inscreva o bot nos events listados acima.
  6. No Ongrid: Settings → IM bridge → New → Provider = slack → Mode = stream → cole app_id (o handle do bot, ex.: ongrid-bot), o JSON de dois tokens em App secret, e pelo menos um Slack user ID em allow_from.

Reinstale o app após adicionar scopes

O Slack não concede scopes retroativamente a bots já instalados. Se chat.postMessage retornar missing_scope após você ter adicionado chat:write, reinstale o app no workspace.

Keep-alive

O loop de stream pinga a cada 20s (pingInterval). O Slack fecha conexões Socket Mode ociosas após ~30s. O ping roda em uma goroutine para que o loop de leitura nunca esteja bloqueado atrás de uma escrita. Um envelope disconnect iniciado pelo Slack fecha limpamente e o supervisor reconecta imediatamente (sem sleep de backoff) com uma URL apps.connections.open fresca.