feat(channels): add Slack channel#83
Conversation
9e0a1b8 to
2be42d5
Compare
viettranx
left a comment
There was a problem hiding this comment.
Code Review — Slack Channel Integration
Overall quality: 7.5/10 — Solid architecture, good test coverage (~170 tests), but there are 2 critical issues that should be fixed before merge.
🔴 Critical (must fix)
1. SSRF Protection gap in CheckRedirect (handlers.go)
The redirect handler only checks for HTTPS scheme but does not validate the hostname. An attacker could craft a Slack file URL that redirects to an internal/cloud metadata endpoint (e.g., 169.254.169.254).
Fix: Add hostname validation in the CheckRedirect function — only allow redirects to known Slack CDN domains (e.g., *.slack-edge.com, files.slack.com).
2. BaseChannel.HandleMessage change affects ALL channels (channel.go:247)
The change from !c.IsAllowed(senderID) to !c.IsAllowed(senderID) && !c.IsAllowed(chatID) is a behavior change for every channel (Telegram, Discord, Feishu, WhatsApp, Zalo) — not just Slack.
With this change, if a group chatID is in the allowlist, any user in that group is implicitly allowed, which may not be the intended behavior for existing channels.
Fix: Revert the BaseChannel change and handle chatID-based allowlist logic specifically in the Slack channel's HandleMessage override.
🟡 High Priority
3. Temp file leak in downloadFile() (handlers.go)
downloadFile() creates temp files via os.CreateTemp but there's no cleanup (os.Remove) after the file is processed and sent to the message bus. In production with high volume, this will leak disk space.
Fix: Add defer os.Remove(tmpFile.Name()) after successful creation, or ensure the consumer cleans up.
4. Debounce metadata overwrite (handlers.go)
When batching multiple messages in the debounce window, the metadata map is only set from the first message. Subsequent messages in the same batch overwrite with stale message_id. The final batched message should use the last message's metadata.
5. Debounce flush on shutdown
When Stop() is called, any pending messages in the debounce timer window are silently dropped. Consider flushing pending debounce entries before shutdown completes.
💡 Suggestions (non-blocking)
format.go: TheconvertNodefunction handles many cases — consider a dispatch table (map[string]func) for cleaner extensibility.reactions.go: ThethinkingReactiongoroutine could leak if the context is never cancelled. Add a safety timeout.stream.go:editMessageretries onrate_limitedbut doesn't read theRetry-Afterheader from Slack's response.media.go: File size limit (20MB) is hardcoded — consider making it configurable viaSlackConfig.
✅ What's done well
- Token prefix validation (
xoxb-,xapp-) at startup — nice defensive check - Dead socket classification with fail-fast on auth errors
- Event dedup mechanism prevents duplicate processing
- Thread participation cache with configurable TTL
- Clean DRY refactor:
ExtractDocumentContentextracted to sharedmedia_utils.go - Graceful shutdown with WaitGroup + context cancellation + timeout
- Good test structure with table-driven tests
Bug fixes included (verified ✅)
isValidChannelType()now includes "slack" — correct- Empty allowlist no longer bypasses pairing — good fix
- Thread TTL
*intpointer semantics (0=disabled, nil=24h default) — clean approach
2be42d5 to
0fd255b
Compare
Review Follow-up — All Critical & High Items AddressedRebased on latest main and applied fixes for all review feedback: Critical Fixes
High Priority Fixes
Additional Bug Fix (found during testing)
Verified
|
0fd255b to
4a921e1
Compare
Implement Slack integration using Socket Mode (xapp-/xoxb- tokens): - Event-driven messaging via app_mention + message events - Policy checks: open, pairing, allowlist, disabled (DM + group) - Thread participation with configurable TTL - Markdown-to-mrkdwn formatting pipeline - Streaming support (edit-in-place + native ChatStreamer) - SSRF-protected file downloads - Debounce, dedup, reactions, group history context - 170 unit tests (format, helpers, stream, SSRF) Fix BaseChannel.HandleMessage allowlist to also check chatID, enabling group allowlist with channel IDs across all channels. Closes nextlevelbuilder#37
- Wire inbound file download into handleMessage (images, audio, documents) - Add media.go with resolveMedia, classifyMime, buildMediaTags - Extract shared ExtractDocumentContent to channels/media_utils.go (DRY with Telegram) - Support file_share and message_changed subtypes - Handle edit-to-mention: respond when user edits old message to add @bot - Add MediaMaxBytes config field (default 20MB) - Fix debounce media accumulation (was silently dropping files) - Add 60s HTTP client timeout on file downloads - Refactor downloadFile signature for slack.File compatibility
4a921e1 to
7c0b471
Compare
Summary
Add Slack channel integration using Socket Mode with full policy support, streaming, and formatting.
Bug fixes
isValidChannelType()missing "slack" in HTTP and WS validationBaseChannel.HandleMessage()allowlist now checks chatID (group allowlist with channel IDs)*intpointer (0 = disabled, nil = 24h default)Closes #37
Test plan