From 67ee6801054b6b0da4fa3821226caf4772b8ba10 Mon Sep 17 00:00:00 2001 From: lorentz Date: Sat, 18 Jul 2026 05:46:22 -0400 Subject: [PATCH] test(quick-260718-7v8): cover held-message date-scoping and sender-relevance guard - blast-radius: getHeldMessages called with same start/end window as searchDeliveredMessages - blast-radius: unrelated-sender held row excluded from held/matched and perRecipient; matching-sender held row still counts and overrides - client: getHeldMessages threads start/end into POST body data[0] when provided, omits them when not --- lib/services/mimecast-blast-radius.test.ts | 125 +++++++++++++++++++++ lib/services/mimecast-client.test.ts | 43 ++++++- 2 files changed, 167 insertions(+), 1 deletion(-) diff --git a/lib/services/mimecast-blast-radius.test.ts b/lib/services/mimecast-blast-radius.test.ts index 54ebbd6..d0b9fa5 100644 --- a/lib/services/mimecast-blast-radius.test.ts +++ b/lib/services/mimecast-blast-radius.test.ts @@ -283,4 +283,129 @@ describe('getBlastRadius', () => { }); expect(setCachedDataMock).not.toHaveBeenCalled(); }); + + it('calls getHeldMessages with the SAME start/end window passed to searchDeliveredMessages', async () => { + await getBlastRadius(BASE_INPUT); + + const expectedStart = BASE_INPUT.dateWindow.start.toISOString().replace(/\.\d{3}Z$/, '+0000'); + const expectedEnd = BASE_INPUT.dateWindow.end.toISOString().replace(/\.\d{3}Z$/, '+0000'); + + expect(searchDeliveredMessagesMock).toHaveBeenCalledWith( + expect.objectContaining({ start: expectedStart, end: expectedEnd }) + ); + expect(getHeldMessagesMock).toHaveBeenCalledWith({ + recipient: BASE_INPUT.recipient, + start: expectedStart, + end: expectedEnd, + }); + }); + + it('excludes an in-window held row from an UNRELATED sender domain from held/matched and perRecipient', async () => { + searchDeliveredMessagesMock.mockResolvedValue({ + messages: [ + { + id: 'd1', + status: 'Delivered', + subject: BASE_INPUT.subject, + from: BASE_INPUT.sender, + fromEnv: BASE_INPUT.sender, + to: BASE_INPUT.recipient, + toDisplay: 'Reporter', + received: '2026-07-14T12:00:00+0000', + senderIP: '1.2.3.4', + spamScore: 0, + detectionLevel: 'none', + attachments: false, + route: 'inbound', + info: '', + }, + ], + }); + getHeldMessagesMock.mockResolvedValue({ + messages: [ + { + id: 'h1', + subject: 'Weekly promo', + from: 'promo@paulfredrick.test', // unrelated domain vs. evil.test + fromDisplay: 'Paul Fredrick', + to: BASE_INPUT.recipient, + toDisplay: 'Reporter', + dateReceived: '2026-07-14T13:00:00+0000', + reason: 'spam', + reasonCode: 'SPAM', + policyInfo: '', + route: 'inbound', + hasAttachments: false, + size: 100, + }, + ], + totalCount: 1, + }); + + const result = await getBlastRadius(BASE_INPUT); + + expect(result).toEqual({ + status: 'ok', + matched: 1, + delivered: 1, + held: 0, + rejected: 0, + clicked: 0, + perRecipient: [{ recipient: BASE_INPUT.recipient, status: 'delivered' }], + source: 'fan-out', + }); + }); + + it('still counts and overrides when a held row sender domain MATCHES input.sender', async () => { + searchDeliveredMessagesMock.mockResolvedValue({ + messages: [ + { + id: 'd1', + status: 'Delivered', + subject: BASE_INPUT.subject, + from: BASE_INPUT.sender, + fromEnv: BASE_INPUT.sender, + to: BASE_INPUT.recipient, + toDisplay: 'Reporter', + received: '2026-07-14T12:00:00+0000', + senderIP: '1.2.3.4', + spamScore: 0, + detectionLevel: 'none', + attachments: false, + route: 'inbound', + info: '', + }, + ], + }); + getHeldMessagesMock.mockResolvedValue({ + messages: [ + { + id: 'h1', + subject: BASE_INPUT.subject, + from: 'queue@evil.test', // same domain as BASE_INPUT.sender (evil.test) + fromDisplay: 'Attacker Queue', + to: BASE_INPUT.recipient, + toDisplay: 'Reporter', + dateReceived: '2026-07-14T13:00:00+0000', + reason: 'spam', + reasonCode: 'SPAM', + policyInfo: '', + route: 'inbound', + hasAttachments: false, + size: 100, + }, + ], + totalCount: 1, + }); + + const result = await getBlastRadius(BASE_INPUT); + + expect(result.status).toBe('ok'); + if (result.status === 'ok') { + expect(result.held).toBe(1); + expect(result.delivered).toBe(1); + expect(result.matched).toBe(2); // 1 non-rejected delivered + 1 held (counts are independent of the perRecipient override) + expect(result.perRecipient).toEqual([{ recipient: BASE_INPUT.recipient, status: 'held' }]); + } + }); }); diff --git a/lib/services/mimecast-client.test.ts b/lib/services/mimecast-client.test.ts index a0fcb44..748ca80 100644 --- a/lib/services/mimecast-client.test.ts +++ b/lib/services/mimecast-client.test.ts @@ -6,7 +6,7 @@ * for this phase (Phase 17, Plan 01, Task 1). */ -import { describe, it, expect, beforeEach } from 'vitest'; +import { describe, it, expect, beforeEach, vi } from 'vitest'; import { isMimecastConfigured, getMimecastClient, @@ -103,3 +103,44 @@ describe('getMimecastClientForTenant', () => { expect(() => getMimecastClientForTenant({ client_id: 'tid', client_secret: 'tsecret' })).not.toThrow(); }); }); + +describe('getHeldMessages date-scoping', () => { + // Fake credentials only — never real mimecast_tenants values. + const FAKE_TENANT = { client_id: 'tid', client_secret: 'tsecret', base_url: 'https://tenant.example' }; + + it('includes start/end in the POST body data[0] when provided', async () => { + const client = getMimecastClientForTenant(FAKE_TENANT); + const requestSpy = vi + .spyOn(client as any, 'request') + .mockResolvedValue({ data: [], meta: { pagination: {} } }); + + await client.getHeldMessages({ + recipient: 'r@x.test', + start: '2026-07-14T00:00:00+0000', + end: '2026-07-15T00:00:00+0000', + }); + + expect(requestSpy).toHaveBeenCalledTimes(1); + const body: any = requestSpy.mock.calls[0][2]; + expect(body.data[0]).toMatchObject({ + admin: true, + start: '2026-07-14T00:00:00+0000', + end: '2026-07-15T00:00:00+0000', + searchBy: { fieldName: 'recipient', value: 'r@x.test' }, + }); + }); + + it('omits start/end from the POST body data[0] when not provided', async () => { + const client = getMimecastClientForTenant(FAKE_TENANT); + const requestSpy = vi + .spyOn(client as any, 'request') + .mockResolvedValue({ data: [], meta: { pagination: {} } }); + + await client.getHeldMessages({ recipient: 'r@x.test' }); + + expect(requestSpy).toHaveBeenCalledTimes(1); + const body: any = requestSpy.mock.calls[0][2]; + expect(body.data[0]).not.toHaveProperty('start'); + expect(body.data[0]).not.toHaveProperty('end'); + }); +});