Hive Hive
Sign in

feat(slack): add Slack OAuth integration with events, interactivity, and message shortcuts

GitHub issue · Closed

Metadata
Source
tuist/hive #44
Updated
Jun 24, 2026
Domains
Hive
Details

Summary

Adds a first-class Slack integration to Hive. Operators register a single Slack app per Hive deployment and enable Public Distribution; any workspace can then install Hive via OAuth at /slack/install without the Slack App Directory review (which would take weeks). Each workspace persists as a Hive.Slack.Installation row with its own bot token, and inbound events and interactions route by team_id.

Motivation

hive.tuist.dev (and any self-hoster) needs to be reachable from Slack: replying in threads when the bot is mentioned, posting notifications, and letting workspace members turn a Slack message into a Hive idea with one click. Atlas (../atlas/lib/atlas/slack/) already had a working Slack integration that I used as the architectural reference, but Atlas threads a slack_app: :community | :company enum through every module to support its two-bot setup. That distinction is bespoke to Tuist’s operating model and doesn’t belong in a generic Hive deployment. The first cut of this plan was actually built around a single static bot token per deployment, but enabling Slack across multiple workspaces from one Hive deployment is the standard shape every real Slack app uses, and Public Distribution makes it reachable without the App Directory gate. The integration ended up with per-installation tenancy (installation_id FK on every Slack-owned table) rather than the static-token model, which is structurally similar to Atlas’s enum but anchored in a real DB row representing an installed workspace.

Capabilities

  • Events API at POST /api/slack/events with HMAC-SHA256 signature verification (handles the url_verification challenge automatically).
  • Outbound Web API via a small Hive.Slack.API Req wrapper: chat.postMessage, chat.update, conversations.info, conversations.replies, users.info, plus post_response/2 for interaction response_urls.
  • App-mention thread replies driven by Hive.Slack.Agents.ConversationAgent (Condukt) and an Oban worker on the :agents queue. Dormant when no LLM is configured.
  • Block Kit interactivity at POST /api/slack/interactions (the block_actions branch is a stub for future button/select handlers).
  • Message shortcut capture_feature_request: right-click a Slack message → captures it as a Hive forage feature request by matching the Slack user to a Hive user via email. Confirmation posted ephemerally through response_url; failures get a useful ephemeral error.
  • Settings UI at /account/slack to connect / disconnect workspaces, with an inert empty state when env vars are missing.
  • Audit entries for every install, disconnect, app-mention, thread reply, and feature-request capture.

Configuration

When all three of HIVE_SLACK_CLIENT_ID, HIVE_SLACK_CLIENT_SECRET, and HIVE_SLACK_SIGNING_SECRET are set, Hive.Slack.enabled?/0 is true and /slack/install is reachable. With any of them missing, the integration stays dormant, mirroring Hive.Agents.enabled?/0 and Hive.GitHub.Webhooks.secret/0.

Approach

  • lib/hive/slack/ mirrors ../atlas/lib/atlas/slack/’s shape, but the slack_app enum + signing-secret loop + company-only gates are all gone. Per-workspace tenancy is the installation_id FK on slack_channels / slack_users / slack_messages, with composite unique indexes like [installation_id, slack_channel_id].
  • Signature verification is a single app-wide secret (one Slack app, many workspaces), not a loop over per-bot secrets like Atlas does.
  • HiveWeb.CacheBodyReader stashes the raw body for any path under /api/slack/ (the same one-line if it already used for /webhooks/github).
  • All tests are async: true; Mimic stubs (Hive.Slack.API, Hive.Slack.Installations, Hive.Slack.Signature, Hive.Slack, Req, Condukt.Operation) keep parallelism safe.

Verification

  • mix format
  • mix compile --warnings-as-errors (clean)
  • mix credo --strict (no new issues; pre-existing ones unchanged)
  • mix test — 419 tests, 0 failures (up from 368, so 51 new tests cover signature verification, OAuth code exchange, API wire format, event dispatch, interaction dispatch, the Oban worker, and both controllers)

Testing

  • mix format
  • mix compile --warnings-as-errors
  • mix credo --strict
  • mix test
  • Manual Slack-side smoke test is documented in docs/guide/self-hosting/slack.md for operators.
Comments

No GitHub comments yet.