feat(slack): native OAuth trigger#5323
Conversation
Add assistant:write, app_mentions:read, and im:history to the Slack bot OAuth scopes so the Set Assistant Status / Title / Suggested Prompts tools (assistant.threads.*) work with users' existing Slack credentials — no new app or credentials required. Restore the action_assistant trigger capability (scope assistant:write) in the manifest generator. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WpeT8J5yVCrrNQB9Hzm9uS
…e, add channel-id input
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryHigh Risk Overview Sim mode registers webhooks as OAuth scopes gain Reviewed by Cursor Bugbot for commit 310061d. Bugbot is set up for automated code reviews on this repo. Configure here. |
Greptile SummaryThis PR adds native Slack OAuth triggers through the official Sim Slack app. The main changes are:
Confidence Score: 4/5This is close, but the Slack channel filter should be fixed before merging.
apps/sim/app/api/webhooks/slack/route.ts Important Files Changed
Reviews (4): Last reviewed commit: "fix(slack-trigger): empty operation sele..." | Re-trigger Greptile |
| }, | ||
| } | ||
| } | ||
| try { |
There was a problem hiding this comment.
This branch uses the OAuth bot token only to fetch the Slack team_id, then stores a slack_app webhook without any token that slackHandler.formatInput() can read. Native reaction_added and reaction_removed triggers therefore skip fetchSlackMessageText() and deliver an empty event.text even though the connected Slack account has the needed scopes.
| id: 'botToken', | ||
| title: 'Bot Token', | ||
| type: 'short-input', | ||
| placeholder: 'xoxb-...', | ||
| description: | ||
| 'The bot token from your Slack app. Required for downloading files attached to messages.', | ||
| password: true, | ||
| required: false, | ||
| mode: 'trigger', | ||
| condition: { field: 'appType', value: 'custom' }, | ||
| }, |
There was a problem hiding this comment.
The unified trigger only exposes botToken for appType: custom, and it removed the legacy includeFiles switch from the native Sim path. For native Slack OAuth message events with attachments, slackHandler.formatInput() sees hasFiles but has neither includeFiles === true nor a providerConfig.botToken, so workflows receive hasFiles: true with an empty files array and cannot process the uploaded file content.
# Conflicts: # apps/sim/blocks/blocks/slack.ts # apps/sim/lib/webhooks/deploy.ts # packages/db/migrations/meta/0253_snapshot.json # packages/db/migrations/meta/_journal.json # scripts/check-api-validation-contracts.ts
|
@greptile review |
…oken for reaction text + file downloads
|
@greptile review — addressed the three findings: (1) unmapped/unselected events now drop instead of bypassing the Operations filter, (2) formatInput resolves the OAuth bot token for slack_app webhooks so reaction-message text works, (3) re-added the includeFiles toggle + token resolution so native file downloads work. |
| // Fire only for events that map to a selected Operation. Unmapped events | ||
| // (e.g. assistant_thread_*) and unselected events no-op — never bypass. | ||
| const selectedEvents = normalizeSelection(providerConfig.events) | ||
| if (selectedEvents.length > 0 && (!eventKey || !selectedEvents.includes(eventKey))) { |
There was a problem hiding this comment.
Empty Selection Matches All
When the events multi-select is saved as an empty array, normalizeSelection(providerConfig.events) returns [] and this condition skips the operation filter entirely. An unmapped Slack event with eventKey === null can then fall through to queueWebhookExecution for every matching team_id. Empty selections should fail closed instead of acting like “match all”.
…token via credential owner not execution actor
|
@greptile review — addressed both: empty operation selection now fires nothing (no match-all), and the OAuth token is resolved via the credential owner (not the execution actor) so it works in shared workspaces. |
| ...normalizeSelection(providerConfig.channelFilter), | ||
| ...normalizeSelection(providerConfig.manualChannelFilter), | ||
| ] | ||
| if ( |
There was a problem hiding this comment.
Stale Channel Matches The route merges the current
channelFilter value with manualChannelFilter, so an old manual channel ID can keep matching after the user switches back to the picker. For example, if a workflow was once deployed with manual channel C123 and is later redeployed from the picker with only C456, the stale manualChannelFilter value can still be included here and events from C123 can run the workflow. Use one canonical channel selection for dispatch, or ignore inactive raw channel fields.
…r channel picker over stale manual ids
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 310061d. Configure here.
| workflowId, | ||
| blockId: block.id, | ||
| provider, | ||
| triggerPath, |
There was a problem hiding this comment.
Redeploy leaves stale Slack routing
High Severity
After the first deploy, changing the linked Slack account, Operations, channel filters, or Sim/Custom app type can leave the existing slack_app webhook row unchanged. routingKey, provider, path, and providerConfig are only written on insert, while shouldRecreateExternalWebhookSubscription returns false for slack/slack_app, so events may route to the wrong workspace or not at all.
Reviewed by Cursor Bugbot for commit 310061d. Configure here.
|
|
||
| if (isBot && providerConfig.filterBotMessages !== false) { | ||
| continue | ||
| } |
There was a problem hiding this comment.
Custom Slack ignores Operations filter
Medium Severity
The unified slack_oauth trigger applies Operations, channel, and bot-message filtering only on /api/webhooks/slack for Sim app type. Custom app deliveries still use the path-based trigger route, which queues every verified Slack event without reading providerConfig.events or the channel filters.
Reviewed by Cursor Bugbot for commit 310061d. Configure here.


Summary
team_id; no per-workflow app or signing secretassistant:write, plusapp_mentions:read/im:historyscopeswebhook.path+routing_keycolumn (migration0253, CONCURRENTLY index) + shared/api/webhooks/slackingest routeType of Change
Testing
Tested manually on dev — DMs and private-channel messages trigger workflows end-to-end (verified via CloudWatch).
lint:check,check:api-validation:strict, andcheck:migrations origin/stagingall pass.Checklist