@@ -305,7 +305,12 @@ describe('resolveWebhookConfigForBlock — slack_oauth routing', () => {
305305 } )
306306 }
307307
308- it ( 'routes a custom bot credential without the native app signing secret' , async ( ) => {
308+ it . each ( [
309+ 'message' ,
310+ 'app_context_changed' ,
311+ 'agent_session_stopped' ,
312+ 'agent_session_title_changed' ,
313+ ] ) ( 'routes custom-bot %s without the native app signing secret' , async ( eventType ) => {
309314 setEnvFlags ( { isSlackExtendedScopesEnabled : false } )
310315 setEnv ( { SLACK_SIGNING_SECRET : undefined } )
311316 mockGetSlackBotCredential . mockResolvedValue ( {
@@ -316,7 +321,7 @@ describe('resolveWebhookConfigForBlock — slack_oauth routing', () => {
316321 signingSecret : 'secret' ,
317322 } )
318323
319- const result = await resolveSlack ( { eventType : 'message' , customBotCredential : 'cred_bot_1' } )
324+ const result = await resolveSlack ( { eventType, customBotCredential : 'cred_bot_1' } )
320325
321326 expect ( result ?. success ) . toBe ( true )
322327 if ( ! result ?. success ) throw new Error ( 'expected success' )
@@ -327,6 +332,31 @@ describe('resolveWebhookConfigForBlock — slack_oauth routing', () => {
327332 expect ( mockFetchSlackTeamId ) . not . toHaveBeenCalled ( )
328333 } )
329334
335+ it . each ( [
336+ [ 'assistant_thread_started' , 'customBotCredential' ] ,
337+ [ 'assistant_thread_context_changed' , 'customBotCredential' ] ,
338+ [ 'assistant_thread_started' , 'manualBotCredential' ] ,
339+ [ 'assistant_thread_context_changed' , 'manualBotCredential' ] ,
340+ ] ) ( 'rejects persisted custom-bot %s through %s before deployment' , async ( eventType , field ) => {
341+ mockGetSlackBotCredential . mockResolvedValue ( {
342+ workspaceId : 'ws-1' ,
343+ botToken : 'xoxb-token' ,
344+ signingSecret : 'secret' ,
345+ } )
346+
347+ const result = await resolveSlack ( { eventType, [ field ] : 'cred_bot_1' } )
348+
349+ expect ( result ?. success ) . toBe ( false )
350+ if ( result ?. success ) throw new Error ( 'expected failure' )
351+ expect ( result ?. error ) . toEqual ( {
352+ message :
353+ 'Legacy Assistant events require a native Sim Slack connection. Choose an Agent View event for a custom bot.' ,
354+ status : 400 ,
355+ } )
356+ expect ( mockRefreshAccessTokenIfNeeded ) . not . toHaveBeenCalled ( )
357+ expect ( mockFetchSlackTeamId ) . not . toHaveBeenCalled ( )
358+ } )
359+
330360 it ( 'deploys a slash command trigger and preserves its command filter' , async ( ) => {
331361 mockGetSlackBotCredential . mockResolvedValue ( {
332362 workspaceId : 'ws-1' ,
@@ -525,27 +555,34 @@ describe('resolveWebhookConfigForBlock — slack_oauth routing', () => {
525555 expect ( mockRefreshAccessTokenIfNeeded ) . not . toHaveBeenCalled ( )
526556 } )
527557
528- it ( 'routes an OAuth account by team_id on the slack_app provider' , async ( ) => {
529- mockGetSlackBotCredential . mockResolvedValue ( null )
530- mockResolveOAuthAccountId . mockResolvedValue ( { accountId : 'acct-1' } )
531- queueTableRows ( credential , [ { id : 'cred_oauth_1' } ] )
532- queueTableRows ( account , [ { userId : 'owner-1' } ] )
533- mockRefreshAccessTokenIfNeeded . mockResolvedValue ( 'xoxb-token' )
534- mockFetchSlackTeamId . mockResolvedValue ( { teamId : 'T123' , userId : 'UBOT' } )
535-
536- const result = await resolveSlack ( { eventType : 'message' , customBotCredential : 'cred_oauth_1' } )
537-
538- expect ( result ?. success ) . toBe ( true )
539- if ( ! result ?. success ) throw new Error ( 'expected success' )
540- expect ( result . config . provider ) . toBe ( 'slack_app' )
541- expect ( result . config . routingKey ) . toBe ( 'T123' )
542- expect ( result . config . triggerPath ) . toBeNull ( )
543- expect ( result . config . providerConfig . bot_user_id ) . toBe ( 'UBOT' )
544- // Runtime token resolution + disconnect cleanup key slack_app rows on this.
545- expect ( result . config . providerConfig . credentialId ) . toBe ( 'cred_oauth_1' )
546- // Owner's token, not the deploying actor's.
547- expect ( mockRefreshAccessTokenIfNeeded ) . toHaveBeenCalledWith ( 'cred_oauth_1' , 'owner-1' , 'req-1' )
548- } )
558+ it . each ( [ 'message' , 'assistant_thread_started' , 'assistant_thread_context_changed' ] ) (
559+ 'routes native OAuth %s by team_id on the slack_app provider' ,
560+ async ( eventType ) => {
561+ mockGetSlackBotCredential . mockResolvedValue ( null )
562+ mockResolveOAuthAccountId . mockResolvedValue ( { accountId : 'acct-1' } )
563+ queueTableRows ( credential , [ { id : 'cred_oauth_1' } ] )
564+ queueTableRows ( account , [ { userId : 'owner-1' } ] )
565+ mockRefreshAccessTokenIfNeeded . mockResolvedValue ( 'xoxb-token' )
566+ mockFetchSlackTeamId . mockResolvedValue ( { teamId : 'T123' , userId : 'UBOT' } )
567+
568+ const result = await resolveSlack ( { eventType, customBotCredential : 'cred_oauth_1' } )
569+
570+ expect ( result ?. success ) . toBe ( true )
571+ if ( ! result ?. success ) throw new Error ( 'expected success' )
572+ expect ( result . config . provider ) . toBe ( 'slack_app' )
573+ expect ( result . config . routingKey ) . toBe ( 'T123' )
574+ expect ( result . config . triggerPath ) . toBeNull ( )
575+ expect ( result . config . providerConfig . bot_user_id ) . toBe ( 'UBOT' )
576+ // Runtime token resolution + disconnect cleanup key slack_app rows on this.
577+ expect ( result . config . providerConfig . credentialId ) . toBe ( 'cred_oauth_1' )
578+ // Owner's token, not the deploying actor's.
579+ expect ( mockRefreshAccessTokenIfNeeded ) . toHaveBeenCalledWith (
580+ 'cred_oauth_1' ,
581+ 'owner-1' ,
582+ 'req-1'
583+ )
584+ }
585+ )
549586
550587 it ( 'fails when the connected Slack account token cannot be resolved' , async ( ) => {
551588 mockGetSlackBotCredential . mockResolvedValue ( null )
0 commit comments