Slack
Ongrid は 2 つの異なるモード で Slack と連携し、別々の Settings パネルで設定します:
| モード | 用途 | トークン |
|---|---|---|
| 通知 | 発火アラートをチャネルに push | webhook URL のみ |
| Socket Mode (IM) | Slack からエージェントと対話 | xapp-… + xoxb-… |
両方運用できます。両者は何も共有しません。
通知(incoming webhook)
最もシンプルな統合。Slack は https://hooks.slack.com/services/T…/B…/… 形式のワークスペース固有 URL を割り当て、 Ongrid がそこにアラートペイロードを POST します。
ペイロードの見え方
Slack sender は notify.Message 1 つを attachments 形式 に描画します (Block Kit でなくこれを選んだ理由は、オペレーターが severity として読むカラーサイドレールを運び、 スキーマが 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 フィールドを残しているので、Slack の push / メールダイジェストプレビューは クライアントが attachments を剥がしても有用な 1 行を表示します。
Severity → 色
| Severity | Hex |
|---|---|
| critical | #d92f2f |
| warning | #f2c037 |
| info | #36a64f |
| (unknown) | #6f7a87 |
ピン留めされた hex(Slack の danger / warning sentinel ではなく)—— Slack クライアントの バージョン間で陰影が安定するように。
セットアップ
- Slack で:Apps → Incoming Webhooks → Add to Slack、チャネルを選択。
- webhook URL をコピー。
- Ongrid で:Settings → Channels → New → Provider =
slack→ Endpoint に URL を貼り付け。
フォームの 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 で配信され (パブリック ingress 不要 —— 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)
必要なトークン
Slack は Socket Mode で 2 つのトークンを使用。スコープが異なります:
| トークン | プレフィックス | 用途 |
|---|---|---|
| App レベルトークン | xapp-… | apps.connections.open(WebSocket URL を取得)。 |
| Bot トークン | xoxb-… | chat.postMessage、chat.update、その他全 Web API 呼び出し。 |
Ongrid は im_apps.app_secret 内に JSON オブジェクトとして保存します。 ParseSecret 関数がプレフィックスを事前に検証するので、貼り間違いが chat.postMessage 401 ではなくきれいなエラーとして浮上します。
{
"app_token": "xapp-1-A0…",
"bot_token": "xoxb-1234567890-1234567890-…"
}必要なアプリスコープ
Slack アプリ設定で:
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 で connections:write スコープ付きの xapp-… トークンを取得。
Event Subscriptions を有効化(トグル ON)、bot を message.channels、 message.groups、message.im、app_mention にサブスクライブ。 Slack は webhook 経由と同じものを Socket Mode で配信します。
allow_from
bot と会話できる Slack ユーザー ID のカンマ区切りリスト。ユーザー ID は U で始まります (Enterprise ゲストは W)。少なくとも 1 つの ID が必須:
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 で 静かにドロップ。bot は返信しない —— 存在を確認しない。 振る舞いは Telegram allow_from と同様。
ストリーミング返信の振る舞い
許可リストユーザーがメッセージを送ると:
- ブリッジが
chat.postMessageを 1 回呼び、プレースホルダーテキスト (Working on it…)を投稿し、返ってきたtsを記録。 - エージェントが動作。各ストリーミングチャンクが同じ
(channel, ts)へのchat.updateをトリガー。 - ターミナルトークンが最終テキストを同じメッセージにフラッシュ。
Slack は no-op chat.update(同じテキスト)を静かに受け入れます —— 400 を返す Telegram と違って。 Slack 側に特別な吞み込みはありません。 stream.go の senderAdapter を参照。
bot ループ、編集、スレッド ID
bot_id != ""のメッセージはドロップ —— manager 自身の返信であり、フィードバックループを生むため。- 任意の非空
subtype(message_changed、channel_join、…)のメッセージはドロップ。 thread_tsはImThread.ImThreadIDとして保存され、スレッド内の返信は同じ会話セッションを継続。- Slack の
<@U…>メンション markup はstripMentionsでベアな@U…トークンに書き換え —— モデルが安定した参照を見るように、メッセージごとにusers.infoラウンドトリップしません。
セットアップ
- Slack アプリ作成:api.slack.com → Create New App → from scratch、ワークスペース選択。
- Socket Mode を有効化、
connections:write付き app レベルトークン生成。xapp-…値をコピー。 - 上記の Bot Token Scopes を設定。
- ワークスペースにアプリをインストール。
xoxb-…Bot User OAuth Token をコピー。 - Event Subscriptions を有効化、bot を上記イベントにサブスクライブ。
- Ongrid で:Settings → IM bridge → New → Provider =
slack→ Mode =stream→ app_id(bot のハンドル、例ongrid-bot)、二トークン JSON を App secret に、 少なくとも 1 つの Slack ユーザー ID を allow_from に貼り付け。
スコープ追加後はアプリを再インストール
Slack は既インストール bot にスコープを遡及付与しません。chat:write を追加した後に chat.postMessage が missing_scope を返したら、ワークスペースにアプリを再インストール。
keep-alive
stream ループは 20 秒ごとに ping (pingInterval)。 Slack はアイドル Socket Mode 接続を約 30 秒で閉じます。ping は goroutine で動くので、 読み取りループが書き込み待ちでブロックされません。Slack 起動の disconnect 封筒が クリーンにクローズし、スーパーバイザーが即時再接続(バックオフ sleep なし) 新しい apps.connections.open URL で。