diff --git a/packages/mosaic/src/lease-broker/broker-test-client.spec.ts b/packages/mosaic/src/lease-broker/broker-test-client.spec.ts index b4a4278..f1c6d68 100644 --- a/packages/mosaic/src/lease-broker/broker-test-client.spec.ts +++ b/packages/mosaic/src/lease-broker/broker-test-client.spec.ts @@ -24,8 +24,13 @@ async function scriptedBroker( connections += 1; socket.once('end', () => { if (chunks === 'hang') return; - for (const chunk of chunks) socket.write(chunk); - socket.end(); + void (async () => { + for (const chunk of chunks) { + socket.write(chunk); + await new Promise((resolve) => setTimeout(resolve, 5)); + } + socket.end(); + })(); }); socket.resume(); }); @@ -105,6 +110,40 @@ describe('newline-framed broker test client', () => { expect(broker.connections()).toBe(1); }); + test('rejects trailing bytes delivered after a complete frame in a later data event', async () => { + const broker = await scriptedBroker([[Buffer.from('{"ok":true}\n'), Buffer.from('extra')]]); + + const failure = await requestBrokerReply(broker.socketPath, { action: 'probe' }).catch( + (error: unknown) => error, + ); + + expect(failure).toBeInstanceOf(BrokerTransportError); + expect(failure).toMatchObject({ kind: 'malformed-reply', responseLength: 17 }); + expect(failure).toHaveProperty( + 'message', + expect.stringMatching(/bytes after the newline terminator/i), + ); + }); + + test('redacts security tokens from typed transport diagnostics', async () => { + const token = 'a'.repeat(64); + const reply = Buffer.from(`{"ok":true,"promotion_token":"${token}`); + const broker = await scriptedBroker([[reply]]); + + const failure = await requestBrokerReply(broker.socketPath, { action: 'probe' }).catch( + (error: unknown) => error, + ); + + expect(failure).toBeInstanceOf(BrokerTransportError); + expect(failure).toMatchObject({ + kind: 'early-close', + responseLength: reply.length, + responsePreview: '', + }); + expect(String((failure as Error).message)).not.toContain(token); + expect(JSON.stringify(failure)).not.toContain(token); + }); + test.each([ ['trailing bytes', Buffer.from('{"ok":true}\nextra'), /bytes after the newline/i], ['non-object JSON', Buffer.from('[]\n'), /JSON value is not an object/i],