Slack
Ongrid интегрируется со Slack в двух различных режимах, настраиваемых на отдельных Settings-панелях:
| Режим | Используйте для | Токены |
|---|---|---|
| Notification | Пушить сработавшие алерты в канал | Только webhook URL |
| Socket Mode (IM) | Разговаривать с агентом из Slack | xapp-… + xoxb-… |
Вы можете запускать оба. Они ничем не делятся.
Notification (incoming webhook)
Самая простая интеграция. Slack назначает workspace-specific URL вида https://hooks.slack.com/services/T…/B…/…; Ongrid POST-ит туда payload алерта.
Как выглядит payload
Slack sender рендерит один notify.Message в attachments-формат (выбран поверх Block Kit, потому что он несёт цветной боковой рельс, который операторы читают как severity, и потому что схема — JSON-flat и универсально поддерживается):
{
"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 / email-digest preview показывают полезный one-liner, даже когда клиент срезает attachments.
Severity → цвет
| Severity | Hex |
|---|---|
| critical | #d92f2f |
| warning | #f2c037 |
| info | #36a64f |
| (unknown) | #6f7a87 |
Закреплённый hex (не sentinel danger / warning Slack), так что оттенок стабилен между версиями Slack-клиента.
Настройка
- В Slack: Apps → Incoming Webhooks → Add to Slack, выберите канал.
- Скопируйте webhook URL.
- В Ongrid: Settings → Channels → New → Provider =
slack→ вставьте URL в Endpoint.
Поле Secret в форме игнорируется для Slack incoming webhook. URL — это credential; нет отдельной поверхности подписи. Channel builder отбрасывает secret до конструирования NewSlackSender.
Протестируйте канал
Кнопка Test на Settings → Channels отправляет синтетический 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. Валидатор отвергает mode != stream для Slack:
slack only supports stream mode (Socket Mode)
Требуемые токены
Slack использует два токена для Socket Mode. Они имеют разные scope:
| Токен | Префикс | Используется для |
|---|---|---|
| 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 валидирует префиксы заранее, так что неправильно вставленный токен всплывает как чистая ошибка, а не как 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-….
Event Subscriptions должны быть включены (toggle on), с ботом, подписанным на message.channels, message.groups, message.im, app_mention. Slack отгружает их через Socket Mode так же, как отгружал бы через webhook.
allow_from
Список Slack user ID через запятую, которые могут разговаривать с ботом. User ID начинаются с U (или W для Enterprise guests). Минимум один 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.
Не-allowlisted отправители молча отбрасываются в handleEvent. Бот не отвечает — он не подтверждает, что существует. Поведение зеркалит Telegram allow_from.
Поведение streaming-ответа
Когда allowlisted-пользователь отправляет сообщение:
- Bridge вызывает
chat.postMessageодин раз с placeholder-текстом (Working on it…) и записывает возвращённыйts. - Агент запускается. Каждый streaming-чанк триггерит
chat.updateна том же(channel, ts). - Терминальный токен флашит финальный текст в то же сообщение.
Slack принимает no-op chat.update (тот же текст) молча — в отличие от Telegram, который возвращает 400. Нет специального swallow на Slack-стороне. См. senderAdapter в stream.go.
Bot-петли, edits и thread ID
- Сообщения с
bot_id != ""отбрасываются — это собственные ответы manager и они создали бы feedback-петлю. - Сообщения с любым непустым
subtype(message_changed,channel_join, …) отбрасываются. thread_tsсохраняется какImThread.ImThreadID, так что ответ внутри треда продолжает ту же сессию разговора.- Slack
<@U…>mention-разметка переписывается в голый@U…токенstripMentions, так что модель видит стабильную ссылку без round-trip кusers.infoна каждое сообщение.
Настройка
- Создайте Slack app: api.slack.com → Create New App → from scratch, выберите workspace.
- Включите Socket Mode, сгенерируйте app-level token с
connections:write. Скопируйте значениеxapp-…. - Установите Bot Token Scopes, перечисленные выше.
- Установите app в workspace. Скопируйте
xoxb-…Bot User OAuth Token. - Включите Event Subscriptions, подпишите бота на события, перечисленные выше.
- В Ongrid: Settings → IM bridge → New → Provider =
slack→ Mode =stream→ вставьте app_id (handle бота, например,ongrid-bot), two-token JSON в App secret и как минимум один Slack user ID в allow_from.
Переустановите app после добавления scope
Slack ретроактивно не выдаёт scope уже установленным ботам. Если chat.postMessage возвращает missing_scope после того, как вы добавили chat:write, переустановите app в workspace.
Keep-alive
Stream-цикл пингует каждые 20с (pingInterval). Slack закрывает idle Socket Mode-соединения после ~30с. Ping работает в горутине, так что read-цикл никогда не блокирован за write. Slack- initiated envelope disconnect чисто закрывает, и supervisor переподключается немедленно (без backoff-sleep) со свежим URL apps.connections.open.