Skip to content

Commit 1e60ab3

Browse files
fix(slack): acknowledge permanently ignored deliveries
1 parent 808473b commit 1e60ab3

5 files changed

Lines changed: 77 additions & 7 deletions

File tree

apps/sim/app/api/webhooks/slack/custom/[credentialId]/route.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,40 @@ describe('Slack custom-bot webhook route', () => {
147147
expect(res.status).toBe(200)
148148
})
149149

150+
it('returns 200 when every target permanently lacks its deployed trigger block', async () => {
151+
mockDispatchResolvedWebhookTarget.mockResolvedValue({
152+
outcome: 'ignored',
153+
response: new Response('Trigger block not found in deployment', { status: 404 }),
154+
reason: 'block-missing',
155+
})
156+
157+
const res = await POST(makeRequest(), context)
158+
159+
expect(mockDispatchResolvedWebhookTarget).toHaveBeenCalledTimes(1)
160+
expect(res.status).toBe(200)
161+
})
162+
163+
it('returns a retryable failure when another target fails beside a missing block', async () => {
164+
mockFindWebhooksByRoutingKey.mockResolvedValue([webhook('wh1'), webhook('wh2')])
165+
mockDispatchResolvedWebhookTarget
166+
.mockResolvedValueOnce({
167+
outcome: 'ignored',
168+
response: new Response('Trigger block not found in deployment', { status: 404 }),
169+
reason: 'block-missing',
170+
})
171+
.mockResolvedValueOnce({
172+
outcome: 'failed',
173+
response: new Response('Queue failed', { status: 500 }),
174+
reason: 'queue-failed',
175+
})
176+
177+
const res = await POST(makeRequest(), context)
178+
179+
expect(mockDispatchResolvedWebhookTarget).toHaveBeenCalledTimes(2)
180+
expect(res.status).toBe(500)
181+
await expect(res.text()).resolves.toBe('Queue failed')
182+
})
183+
150184
it('returns the dispatch failure when no target is acknowledged', async () => {
151185
mockDispatchResolvedWebhookTarget.mockResolvedValue({
152186
outcome: 'failed',

apps/sim/app/api/webhooks/slack/custom/[credentialId]/route.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,7 @@ async function handleSlackCustomBotWebhook(
7878
(result) => result.outcome !== 'failed' && result.reason !== 'block-missing'
7979
)
8080
if (!acknowledged) {
81-
const failure = dispatchResults.find(
82-
(result) => result.outcome === 'failed' || result.reason === 'block-missing'
83-
)
81+
const failure = dispatchResults.find((result) => result.outcome === 'failed')
8482
if (failure) return failure.response
8583
}
8684

apps/sim/app/api/webhooks/trigger/[path]/route.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,6 +1178,36 @@ describe('Webhook Trigger API Route', () => {
11781178
await expect(response.json()).resolves.toEqual({ message: 'Webhook event ignored' })
11791179
expect(dispatchResolvedWebhookTargetMock).not.toHaveBeenCalled()
11801180
})
1181+
1182+
it('acknowledges a legacy fan-out when every target permanently lacks its trigger block', async () => {
1183+
testData.webhooks.push({
1184+
id: 'legacy-slack-webhook',
1185+
provider: 'slack',
1186+
path: 'legacy-slack-path',
1187+
routingKey: 'credential-1',
1188+
isActive: true,
1189+
providerConfig: {
1190+
triggerId: 'slack_webhook',
1191+
credentialId: 'credential-1',
1192+
ingressMode: 'legacy_custom_bot',
1193+
},
1194+
workflowId: 'test-workflow-id',
1195+
})
1196+
dispatchSlackCustomBotCredentialMock.mockResolvedValueOnce([
1197+
{
1198+
outcome: 'ignored',
1199+
reason: 'block-missing',
1200+
response: new NextResponse('Trigger block not found in deployment', { status: 404 }),
1201+
},
1202+
])
1203+
1204+
const response = await POST(createMockRequest('POST', { type: 'event_callback' }), {
1205+
params: Promise.resolve({ path: 'legacy-slack-path' }),
1206+
})
1207+
1208+
expect(response.status).toBe(200)
1209+
expect(dispatchResolvedWebhookTargetMock).not.toHaveBeenCalled()
1210+
})
11811211
})
11821212

11831213
describe('Reservation-free filtering', () => {

apps/sim/app/api/webhooks/trigger/[path]/route.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,11 +260,16 @@ async function handleWebhookDelivery(
260260
*/
261261
const responses: NextResponse[] = []
262262
const failures: NextResponse[] = []
263+
let hasPermanentlyIgnoredLegacyTarget = false
263264
for (const dispatchResult of legacySlackDispatchResults) {
264-
if (dispatchResult.outcome === 'failed' || dispatchResult.reason === 'block-missing') {
265+
if (dispatchResult.outcome === 'failed') {
265266
failures.push(dispatchResult.response)
266267
continue
267268
}
269+
if (dispatchResult.reason === 'block-missing') {
270+
hasPermanentlyIgnoredLegacyTarget = true
271+
continue
272+
}
268273
responses.push(dispatchResult.response)
269274
}
270275
const dispatchTargetCount = directWebhooksForPath.length + legacySlackDispatchResults.length
@@ -341,6 +346,9 @@ async function handleWebhookDelivery(
341346
if (failures.length > 0) {
342347
return failures[0]
343348
}
349+
if (hasPermanentlyIgnoredLegacyTarget) {
350+
return new NextResponse(null, { status: 200 })
351+
}
344352
return new NextResponse('No webhooks processed successfully', { status: 500 })
345353
}
346354

apps/sim/lib/copilot/tools/server/blocks/get-blocks-metadata-projection.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ describe('get_blocks_metadata against the real registries', () => {
5050

5151
it('resolves an integration block’s operations and their tool-derived inputs', async () => {
5252
const result = await getBlocksMetadataServerTool.execute(
53-
{ blockIds: ['slack'] },
53+
{ blockIds: ['slack_v2'] },
5454
{ userId: 'user-1', workspaceId: 'workspace-1' }
5555
)
5656

57-
const slack = result.metadata.slack as AgentBlockMetadata
58-
expect(slack.blockType).toBe('slack')
57+
const slack = result.metadata.slack_v2 as AgentBlockMetadata
58+
expect(slack.blockType).toBe('slack_v2')
5959
expect(slack.name).toBe('Slack')
6060

6161
const operations = slack.operations ?? {}

0 commit comments

Comments
 (0)