Skip to content

Slack

Ongrid 集成 Slack 有两种独立模式,在 Settings 的不同面板上配置:

模式用于Token
Notification把触发的告警推到频道只要 webhook URL
Socket Mode(IM)在 Slack 里和 Agent 对话xapp-… + xoxb-…

两者可以同时跑。它们什么状态都不共享。

Notification(incoming webhook)

最简单的集成。Slack 分配给工作区一个形如 https://hooks.slack.com/services/T…/B…/… 的 URL;Ongrid 把告警载荷 POST 上去。

载荷长什么样

Slack sender 把单个 notify.Message 渲染成 attachments 格式(之所以不用 Block Kit,是因为 attachments 自带按 severity 染色的侧栏 —— 运维一眼就能看出严重程度,而且 schema 是 JSON 扁平的,普适性最好):

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

text 字段保持填充,这样即使客户端剥掉 attachments,Slack 的推送/邮件摘要预览也能有一条可读的一句话。

Severity → 颜色

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

写死的 hex(不用 Slack 的 danger / warning 哨兵值),保证不同 Slack 客户端版本下色调稳定。

配置

  1. 在 Slack:Apps → Incoming Webhooks → Add to Slack,挑频道。
  2. 复制 webhook URL。
  3. 在 Ongrid:Settings → Channels → New → Provider = slack → 把 URL 粘进 Endpoint

表单上的 Secret 字段对 Slack incoming webhook 是无视的。URL 就是凭据,没有独立签名面。通道构造器会在创建 NewSlackSender 之前把 secret 丢掉。

测试通道

Settings → Channels 上的 Test 按钮会发一条合成 notify.Message{Severity: "info", Subject: "Ongrid test", …}。目标频道里出现带绿色侧栏的 attachment,就说明通道接通了。

Socket Mode(IM bridge)

Socket Mode 是双向集成。入站用户文本通过出站 WebSocket 传过来(不需要任何公网入口 —— 形态和 Telegram getUpdates 类似),manager 用标准 Web API(chat.postMessagechat.update)回复。

为什么用 Socket Mode 不用 Events API

Events API 要求 Slack 入站到达 manager,意味着要有一个公网 HTTPS 端点 + 有效证书。大多数 Ongrid 部署是私有的。Socket Mode 是受支持的备选 —— manager 主动外联,遵守 HTTPS_PROXY / NO_PROXY,在 NAT 和 GFW 后面都能跑。校验器拒绝 Slack 上 mode != stream

slack only supports stream mode (Socket Mode)

必填 token

Slack Socket Mode 用两个 token,权限范围不同:

Token前缀用途
App-level tokenxapp-…apps.connections.open(拿 WebSocket URL)。
Bot tokenxoxb-…chat.postMessagechat.update,以及所有其他 Web API。

Ongrid 把它们以 JSON 对象的形式存到 im_apps.app_secretParseSecret 会预先校验前缀,所以贴错 token 会以一个清晰的错误冒出来,而不是后面 chat.postMessage 返回 401。

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

必需的 app scope

在 Slack app 配置里:

OAuth & Permissions → Bot Token Scopes

  • app_mentions:read —— 接收 app_mention 事件。
  • channels:history —— 接收公开频道的 message 事件。
  • groups:history —— 同上,私有频道。
  • im:history —— 同上,DM。
  • chat:write —— chat.postMessage / chat.update

Socket Mode → Enable,然后 Basic Information → App-Level Tokens,scope 选 connections:write,拿到 xapp-… token。

Event Subscriptions 必须开启(toggle on),机器人订阅 message.channelsmessage.groupsmessage.imapp_mention。Slack 通过 Socket Mode 推这些事件,方式和 webhook 一致。

allow_from

允许跟机器人对话的 Slack user ID 逗号分隔列表。user ID 以 U 开头(Enterprise guest 是 W)。至少一个:

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

怎么找自己的 ID:Slack 里点头像 → Profile 菜单 → Copy member ID

非白名单发送者在 handleEvent 处被静默丢弃。机器人不回复 —— 它甚至不会确认自己存在。行为和 Telegram allow_from 一致。

流式回复行为

白名单用户发消息后:

  1. bridge 用占位文本(Working on it…)调一次 chat.postMessage,记下返回的 ts
  2. Agent 开跑。每个流式 chunk 触发一次对 (channel, ts)chat.update
  3. 终止 token 把最终文本刷到同一条消息。

Slack 对 no-op 的 chat.update(同文本)会静默接受 —— Telegram 会返 400。所以 Slack 这边不需要特殊吞错。见 stream.go 里的 senderAdapter

机器人回环、编辑事件、thread ID

  • bot_id != "" 的消息直接丢 —— 那是 manager 自己的回复,留下会产生反馈环。
  • subtype 非空(message_changedchannel_join…)的消息也丢。
  • thread_ts 存到 ImThread.ImThreadID,这样 thread 内回复延续同一个会话。
  • Slack 的 <@U…> mention 标记由 stripMentions 改写成纯 @U… token,模型看到稳定的引用,不需要每条消息都 users.info 一次。

配置步骤

  1. 建一个 Slack app:api.slack.com → Create New App → from scratch,选工作区。
  2. 启用 Socket Mode,生成带 connections:write 的 app-level token。复制 xapp-…
  3. 配上面那些 Bot Token Scopes
  4. 把 app 安装到工作区。复制 xoxb-…(Bot User OAuth Token)。
  5. 启用 Event Subscriptions,订阅上面列的事件。
  6. 在 Ongrid:Settings → IM bridge → New → Provider = slack → Mode = stream → 粘 app_id(机器人 handle,比如 ongrid-bot)、两 token 的 JSON 粘到 App secret、至少一个 Slack user ID 粘到 allow_from

加完 scope 之后要重新安装 app

Slack 不会自动把新 scope 追加给已安装机器人。如果加了 chat:write 之后 chat.postMessage 返回 missing_scope,重新装一次 app 到工作区。

保活

stream 循环每 20 秒 ping 一次(pingInterval)。Slack 大约 30 秒后会关掉空闲 Socket Mode 连接。ping 跑在独立 goroutine 里,读循环不会被写阻塞。Slack 主动发的 disconnect envelope 会干净关闭,supervisor 立刻用新的 apps.connections.open URL 重连(不退避)。