Skip to content

Commit 29e65bb

Browse files
fix(slack): remove user-token-only workflow actions
1 parent 415330c commit 29e65bb

23 files changed

Lines changed: 68 additions & 1613 deletions

‎apps/docs/content/docs/integrations/slack.mdx‎

Lines changed: 7 additions & 318 deletions
Large diffs are not rendered by default.

‎apps/sim/blocks/blocks/slack-workflow-operations.test.ts‎

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -37,27 +37,20 @@ describe('Slack workflow operations in the existing block', () => {
3737
).toBe(true)
3838
}
3939
}
40-
const credentialId =
41-
operation.auth === 'bot'
42-
? 'apiBotCredential'
43-
: operation.auth === 'user'
44-
? 'apiManagedUserCredentialId'
45-
: 'apiOAuthCredential'
40+
const credentialId = operation.auth === 'bot' ? 'apiBotCredential' : 'apiOAuthCredential'
4641
expect(fieldIds).toContain(credentialId)
4742
expect(fieldIds).not.toContain('credential')
4843
expect(fieldIds).not.toContain('listBotCredential')
4944
if (operation.auth === 'bot')
5045
expect(fields.find(({ id }) => id === credentialId)?.credentialKind).toBe('service-account')
51-
if (operation.auth === 'user')
52-
expect(fields.some(({ type }) => type === 'oauth-input')).toBe(false)
5346
expect(SlackV2Block.canvasPresentation?.sentences?.byOperation?.[operation.id]).toBeDefined()
5447
}
5548
)
5649

5750
it('keeps message output types while exposing conversation and file metadata separately', () => {
5851
expect(SlackV2Block.outputs.channel.type).toBe('string')
5952
expect(SlackV2Block.outputs.files.type).toBe('file[]')
60-
for (const key of ['conversation', 'fileMetadata', 'fileSearchResults'])
53+
for (const key of ['conversation', 'fileMetadata'])
6154
expect(SlackV2Block.outputs[key].type).toBe('json')
6255
})
6356

@@ -100,18 +93,18 @@ describe('Slack workflow operations in the existing block', () => {
10093
apiBotCredentialId: 'stale',
10194
slack_open_conversation_users: '["U1","U2"]',
10295
slack_open_conversation_return_im: false,
103-
slack_update_user_profile_profile: 'invalid stale JSON',
96+
slack_share_canvas_user_ids: 'invalid stale JSON',
10497
})
10598
).toEqual({ credential: 'account', users: ['U1', 'U2'], return_im: false })
10699
expect(
107100
mapParams({
108-
operation: 'search_messages',
109-
apiManagedUserCredentialId: 'user',
110-
apiOAuthCredentialId: 'native',
111-
slack_search_messages_query: 'roadmap',
112-
slack_search_messages_count: '25',
101+
operation: 'list_files',
102+
apiOAuthCredentialId: 'account',
103+
apiBotCredentialId: 'stale',
104+
slack_list_files_channel: 'C1',
105+
slack_list_files_count: '25',
113106
})
114-
).toEqual({ credential: 'user', query: 'roadmap', count: 25, sort: 'score', sort_dir: 'desc' })
107+
).toEqual({ credential: 'account', channel: 'C1', count: 25 })
115108
expect(
116109
mapParams({
117110
operation: 'edit_bookmark',
@@ -121,9 +114,7 @@ describe('Slack workflow operations in the existing block', () => {
121114
slack_edit_bookmark_emoji: '',
122115
})
123116
).toEqual({ credential: 'bot', channel_id: 'C1', bookmark_id: 'Bk1', emoji: '' })
124-
expect(() =>
125-
mapParams({ operation: 'search_messages', slack_search_messages_count: 'many' })
126-
).toThrow()
117+
expect(() => mapParams({ operation: 'list_files', slack_list_files_count: 'many' })).toThrow()
127118
expect(() =>
128119
mapParams({ operation: 'share_canvas', slack_share_canvas_user_ids: 'invalid JSON' })
129120
).toThrow()
@@ -199,12 +190,29 @@ describe('Slack custom-app permissions', () => {
199190
)
200191
})
201192

202-
it('covers user-only operations through managed user scopes and leaves native Sim scopes unchanged', () => {
203-
for (const operation of SLACK_WORKFLOW_OPERATIONS.filter(({ auth }) => auth === 'user')) {
204-
expect(SLACK_MANAGED_USER_SCOPES).toEqual(
205-
expect.arrayContaining(tools[operation.tool].oauth!.requiredScopes!)
206-
)
193+
it('excludes user-only actions and their newly added scopes from the integration', () => {
194+
const operationField = SlackV2Block.subBlocks.find(({ id }) => id === 'operation')!
195+
const options = operationField.options
196+
if (!Array.isArray(options)) throw new Error('Expected static operation options')
197+
for (const operation of [
198+
'update_user_profile',
199+
'search_messages',
200+
'search_files',
201+
'search_all',
202+
'set_dnd_snooze',
203+
'end_dnd_snooze',
204+
'end_dnd',
205+
]) {
206+
expect(options.map(({ id }) => id)).not.toContain(operation)
207+
expect(SlackV2Block.tools.access).not.toContain(`slack_${operation}`)
208+
expect(tools).not.toHaveProperty(`slack_${operation}`)
207209
}
210+
expect(SlackV2Block.subBlocks.map(({ id }) => id)).not.toContain('apiManagedUserCredentialId')
211+
expect(SLACK_MANAGED_USER_SCOPES).not.toContain('dnd:write')
212+
expect(SLACK_MANAGED_USER_SCOPES).not.toContain('search:read')
213+
})
214+
215+
it('leaves native Sim scopes unchanged', () => {
208216
const native = getScopesForService('slack')
209217
for (const scope of [
210218
'lists:read',

0 commit comments

Comments
 (0)