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 扁平的,普适性最好):
{
"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 → 颜色
| Severity | Hex |
|---|---|
| critical | #d92f2f |
| warning | #f2c037 |
| info | #36a64f |
| (unknown) | #6f7a87 |
写死的 hex(不用 Slack 的 danger / warning 哨兵值),保证不同 Slack 客户端版本下色调稳定。
配置
- 在 Slack:Apps → Incoming Webhooks → Add to Slack,挑频道。
- 复制 webhook URL。
- 在 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.postMessage、chat.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 token | xapp-… | apps.connections.open(拿 WebSocket URL)。 |
| Bot token | xoxb-… | chat.postMessage、chat.update,以及所有其他 Web API。 |
Ongrid 把它们以 JSON 对象的形式存到 im_apps.app_secret。ParseSecret 会预先校验前缀,所以贴错 token 会以一个清晰的错误冒出来,而不是后面 chat.postMessage 返回 401。
{
"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.channels、message.groups、message.im、app_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 一致。
流式回复行为
白名单用户发消息后:
- bridge 用占位文本(
Working on it…)调一次chat.postMessage,记下返回的ts。 - Agent 开跑。每个流式 chunk 触发一次对
(channel, ts)的chat.update。 - 终止 token 把最终文本刷到同一条消息。
Slack 对 no-op 的 chat.update(同文本)会静默接受 —— Telegram 会返 400。所以 Slack 这边不需要特殊吞错。见 stream.go 里的 senderAdapter。
机器人回环、编辑事件、thread ID
bot_id != ""的消息直接丢 —— 那是 manager 自己的回复,留下会产生反馈环。subtype非空(message_changed、channel_join…)的消息也丢。thread_ts存到ImThread.ImThreadID,这样 thread 内回复延续同一个会话。- Slack 的
<@U…>mention 标记由stripMentions改写成纯@U…token,模型看到稳定的引用,不需要每条消息都users.info一次。
配置步骤
- 建一个 Slack app:api.slack.com → Create New App → from scratch,选工作区。
- 启用 Socket Mode,生成带
connections:write的 app-level token。复制xapp-…。 - 配上面那些 Bot Token Scopes。
- 把 app 安装到工作区。复制
xoxb-…(Bot User OAuth Token)。 - 启用 Event Subscriptions,订阅上面列的事件。
- 在 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 重连(不退避)。