@@ -9,8 +9,7 @@ import { tmpdir } from "node:os";
99import sodium from "libsodium-wrappers-sumo" ;
1010import {
1111 canonicalizeEnvelope ,
12- canonicalizeOutbound ,
13- canonicalizeOutboundV2 ,
12+ canonicalizeProtocolRequest ,
1413} from "../slack-bridge/crypto.mjs" ;
1514
1615function b64 ( bytes = 32 , fill = 1 ) {
@@ -54,6 +53,8 @@ describe("broker pull bridge semi-integration", () => {
5453 } ) ;
5554
5655 it ( "acks poison messages from broker to avoid infinite retry loops" , async ( ) => {
56+ await sodium . ready ;
57+
5758 let pullCount = 0 ;
5859 let ackPayload = null ;
5960
@@ -162,7 +163,16 @@ describe("broker pull bridge semi-integration", () => {
162163 await Promise . race ( [ ackWait , bridgeExited ] ) ;
163164
164165 expect ( ackPayload . workspace_id ) . toBe ( "T123BROKER" ) ;
166+ expect ( ackPayload . protocol_version ) . toBe ( "2026-02-1" ) ;
165167 expect ( ackPayload . message_ids ) . toContain ( "m-poison-1" ) ;
168+
169+ const signKeypair = sodium . crypto_sign_seed_keypair ( new Uint8Array ( Buffer . alloc ( 32 , 13 ) ) ) ;
170+ const canonical = canonicalizeProtocolRequest ( "T123BROKER" , "2026-02-1" , "inbox.ack" , ackPayload . timestamp , {
171+ message_ids : ackPayload . message_ids ,
172+ } ) ;
173+ const sigBytes = new Uint8Array ( Buffer . from ( ackPayload . signature , "base64" ) ) ;
174+ const valid = sodium . crypto_sign_verify_detached ( sigBytes , canonical , signKeypair . publicKey ) ;
175+ expect ( valid ) . toBe ( true ) ;
166176 } ) ;
167177
168178 it ( "forwards user messages to agent in fire-and-forget mode without get_message/turn_end RPCs" , async ( ) => {
@@ -352,7 +362,7 @@ describe("broker pull bridge semi-integration", () => {
352362 expect ( sendPayloads . some ( ( payload ) => payload . action === "reactions.add" ) ) . toBe ( false ) ;
353363 } ) ;
354364
355- it ( "uses inbox.pull.v2 signatures with wait_seconds by default" , async ( ) => {
365+ it ( "uses protocol-versioned inbox.pull signatures with wait_seconds by default" , async ( ) => {
356366 await sodium . ready ;
357367
358368 const workspaceId = "T123BROKER" ;
@@ -423,10 +433,11 @@ describe("broker pull bridge semi-integration", () => {
423433 await waitFor ( ( ) => pullPayload !== null , 10_000 , 50 , "timeout waiting for inbox pull request" ) ;
424434
425435 expect ( pullPayload . workspace_id ) . toBe ( workspaceId ) ;
436+ expect ( pullPayload . protocol_version ) . toBe ( "2026-02-1" ) ;
426437 expect ( pullPayload . max_messages ) . toBe ( 10 ) ;
427438 expect ( pullPayload . wait_seconds ) . toBe ( 20 ) ;
428439
429- const canonical = canonicalizeOutboundV2 ( workspaceId , "inbox.pull.v2 " , pullPayload . timestamp , {
440+ const canonical = canonicalizeProtocolRequest ( workspaceId , "2026-02-1" , " inbox.pull", pullPayload . timestamp , {
430441 max_messages : 10 ,
431442 wait_seconds : 20 ,
432443 } ) ;
@@ -437,7 +448,7 @@ describe("broker pull bridge semi-integration", () => {
437448 bridge . kill ( "SIGTERM" ) ;
438449 } ) ;
439450
440- it ( "falls back to legacy inbox.pull signature when SLACK_BROKER_WAIT_SECONDS =0" , async ( ) => {
451+ it ( "uses protocol-versioned inbox.pull signature with wait_seconds =0" , async ( ) => {
441452 await sodium . ready ;
442453
443454 const workspaceId = "T123BROKER" ;
@@ -506,13 +517,17 @@ describe("broker pull bridge semi-integration", () => {
506517 } ) ;
507518 children . push ( bridge ) ;
508519
509- await waitFor ( ( ) => pullPayload !== null , 10_000 , 50 , "timeout waiting for legacy inbox pull request" ) ;
520+ await waitFor ( ( ) => pullPayload !== null , 10_000 , 50 , "timeout waiting for protocol inbox pull request" ) ;
510521
511522 expect ( pullPayload . workspace_id ) . toBe ( workspaceId ) ;
523+ expect ( pullPayload . protocol_version ) . toBe ( "2026-02-1" ) ;
512524 expect ( pullPayload . max_messages ) . toBe ( 10 ) ;
513- expect ( Object . prototype . hasOwnProperty . call ( pullPayload , " wait_seconds" ) ) . toBe ( false ) ;
525+ expect ( pullPayload . wait_seconds ) . toBe ( 0 ) ;
514526
515- const canonical = canonicalizeOutbound ( workspaceId , "inbox.pull" , pullPayload . timestamp , "10" ) ;
527+ const canonical = canonicalizeProtocolRequest ( workspaceId , "2026-02-1" , "inbox.pull" , pullPayload . timestamp , {
528+ max_messages : 10 ,
529+ wait_seconds : 0 ,
530+ } ) ;
516531 const sigBytes = new Uint8Array ( Buffer . from ( pullPayload . signature , "base64" ) ) ;
517532 const valid = sodium . crypto_sign_verify_detached ( sigBytes , canonical , signKeypair . publicKey ) ;
518533 expect ( valid ) . toBe ( true ) ;
@@ -592,10 +607,11 @@ describe("broker pull bridge semi-integration", () => {
592607 await waitFor ( ( ) => pullPayload !== null , 10_000 , 50 , "timeout waiting for clamped inbox pull request" ) ;
593608
594609 expect ( pullPayload . workspace_id ) . toBe ( workspaceId ) ;
610+ expect ( pullPayload . protocol_version ) . toBe ( "2026-02-1" ) ;
595611 expect ( pullPayload . max_messages ) . toBe ( 100 ) ;
596612 expect ( pullPayload . wait_seconds ) . toBe ( 20 ) ;
597613
598- const canonical = canonicalizeOutboundV2 ( workspaceId , "inbox.pull.v2 " , pullPayload . timestamp , {
614+ const canonical = canonicalizeProtocolRequest ( workspaceId , "2026-02-1" , " inbox.pull", pullPayload . timestamp , {
599615 max_messages : 100 ,
600616 wait_seconds : 20 ,
601617 } ) ;
0 commit comments