feat(slack): auto-approve channels the bot is added to (resolves #68)#78
Open
juniperbevensee wants to merge 1 commit into
Open
feat(slack): auto-approve channels the bot is added to (resolves #68)#78juniperbevensee wants to merge 1 commit into
juniperbevensee wants to merge 1 commit into
Conversation
…ignal reconcile) Resolves #68. Slack had no equivalent of Signal's group reconcile: channels had to be listed in SLACK_ALLOWED_CHANNELS manually, so adding the bot to a new channel did nothing until an operator edited the env var. Mirror the Signal pattern with two additive, self-contained entry points: - member_joined_channel event handler — when the joining member is our bot user, auto-approve the channel (trusts the *action* of being added, the way Signal's invite handler trusts the inviter). - _reconcile_channels() on connect — list the bot's member channels via users.conversations and approve them, recovering the add-while-offline gap (analogous to Signal's _reconcile_groups add-at-creation recovery). Approvals are persisted to slack_approved_channels.json under HERMES_HOME so they survive restarts, and unioned into the effective allowlist only when a static whitelist is active — with no whitelist the bot already responds everywhere, so approving would wrongly turn an unrestricted install into a restricted one (matches Signal's early return on the "*" wildcard). Gated by SLACK_CHANNEL_JOIN_POLICY (auto|disabled, default auto). All paths are best-effort and never break connect. 26 new tests cover policy parsing, the allowlist union, persistence round-trip, the join handler, and reconcile (pagination + failure isolation). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BZiFLur67KjEViZb3oQ2Z3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resolves #68 — Slack parity with Signal's group reconcile.
Root cause
gateway/platforms/slack.py(theplugins/platforms/slack/adapter.pyadapter) had no discover/reconcile step. Channels had to be listed inSLACK_ALLOWED_CHANNELSmanually, so an admin adding the bot to a channel did nothing until an operator hand-edited the env var. Signal already solves the equivalent problem via_reconcile_groups+ an invite handler + a persistedsignal_approved_groups.json.Approach (mirrors Signal, additive + self-contained)
Two entry points, matching the two ways a channel becomes live:
member_joined_channelevent handler — when the joining member is our bot user, auto-approve the channel. Trusts the action of being added (a Slack workspace is admin-managed, so being added is already admin-gated), the same way Signal's invite handler trusts the inviter._reconcile_channels()on connect — lists the bot's member channels viausers.conversations(paginated, capped) and approves them. Recovers the add-while-offline / missed-event gap, analogous to Signal's add-at-creation_reconcile_groups.Approvals are:
slack_approved_channels.jsonunderHERMES_HOME(tmp-file +os.replace, best-effort) so they survive restarts — parity withsignal_approved_groups.json.*is present._slack_allowed_channels()now layers runtime approvals on top of the operator-authored_slack_configured_channels().SLACK_CHANNEL_JOIN_POLICY(auto|disabled, defaultauto).disabledrestores the pre-Slack: auto-approve channels the bot is added to (parity with Signal group reconcile) #68 manual behavior.Every path is best-effort and self-guarded — a reconcile/persist failure never breaks connect. Fork stays minimally divergent: no upstream files touched beyond the Slack adapter, no behavior change for existing installs (empty/
*allowlist unaffected).Tests
New
tests/gateway/test_slack_channel_auto_approve.py— 26 tests, all passing:_channel_approval_activetruth table (no whitelist /*/ whitelist / disabled)*)_approve_channel(adds+persists, idempotent, no-op when inactive, skips already-configured)member_joined_channel(bot added → approve; other user → ignore; no-whitelist no-op; malformed event non-fatal)_reconcile_channels(approves members, no-op without whitelist/when disabled, API-failure isolation, pagination)Existing
test_slack_mention.py(79) andtest_slack.pystill pass for the code under change; the 15 unrelated failures in my ad-hoc venv (SSRF/session-scope/bot-auth) reproduce identically on the clean tree (environmental, not caused by this change).🤖 Generated with Claude Code