From cf9d4db7230466b368edb8e2e6f5918d814c4a78 Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Fri, 31 Jul 2026 13:18:08 +0200 Subject: [PATCH] test(dataCollection): Remove all occurences of `sendDefaultPii` in unit tests --- packages/browser/test/client.test.ts | 22 +- .../test/integrations/httpclient.test.ts | 20 +- packages/cloudflare/test/request.test.ts | 50 ----- .../mcp-server/piiFiltering.test.ts | 68 +------ .../lib/integrations/mcp-server/testUtils.ts | 9 - .../transportInstrumentation.test.ts | 58 ------ .../test/lib/integrations/requestdata.test.ts | 154 +++++++------- .../test/lib/integrations/supabase.test.ts | 8 +- packages/core/test/lib/logs/internal.test.ts | 14 +- .../core/test/lib/metrics/internal.test.ts | 2 +- .../core/test/lib/tracing/ai/utils.test.ts | 23 --- .../lib/tracing/spans/captureSpan.test.ts | 189 +++++++++--------- .../test/lib/tracing/spans/envelope.test.ts | 8 +- packages/core/test/lib/trpc.test.ts | 6 +- .../defaultPiiToCollectionOptions.test.ts | 73 ------- .../resolveDataCollectionOptions.test.ts | 40 +--- packages/core/test/lib/utils/request.test.ts | 85 +++++--- packages/deno/test/deno-serve.test.ts | 38 +--- .../utils/setUrlProcessingMetadata.test.ts | 4 +- .../test/integrations/systemError.test.ts | 47 +---- 20 files changed, 280 insertions(+), 638 deletions(-) delete mode 100644 packages/core/test/lib/utils/data-collection/defaultPiiToCollectionOptions.test.ts diff --git a/packages/browser/test/client.test.ts b/packages/browser/test/client.test.ts index 75a7fe63b775..efd9aa9cc60d 100644 --- a/packages/browser/test/client.test.ts +++ b/packages/browser/test/client.test.ts @@ -173,18 +173,18 @@ describe('SDK metadata', () => { expect(client.getOptions()._metadata?.sdk?.settings?.infer_ip).toBe('never'); }); - it('sets infer_ip to "never" if sendDefaultPii is false', () => { + it('sets infer_ip to "never" if dataCollection.userInfo is false', () => { const options = getDefaultBrowserClientOptions({ - sendDefaultPii: false, + dataCollection: { userInfo: false }, }); const client = new BrowserClient(options); expect(client.getOptions()._metadata?.sdk?.settings?.infer_ip).toBe('never'); }); - it('sets infer_ip to "auto" if sendDefaultPii is true', () => { + it('sets infer_ip to "auto" if dataCollection.userInfo is true', () => { const options = getDefaultBrowserClientOptions({ - sendDefaultPii: true, + dataCollection: { userInfo: true }, }); const client = new BrowserClient(options); @@ -209,19 +209,9 @@ describe('SDK metadata', () => { expect(client.getOptions()._metadata?.sdk?.settings?.infer_ip).toBe('never'); }); - it('dataCollection.userInfo takes precedence over sendDefaultPii', () => { - const options = getDefaultBrowserClientOptions({ - sendDefaultPii: true, - dataCollection: { userInfo: false }, - }); - const client = new BrowserClient(options); - - expect(client.getOptions()._metadata?.sdk?.settings?.infer_ip).toBe('never'); - }); - it("doesn't override already set sdk metadata settings", () => { const options = getDefaultBrowserClientOptions({ - sendDefaultPii: true, + dataCollection: { userInfo: true }, _metadata: { sdk: { settings: { @@ -291,7 +281,7 @@ describe('SDK metadata', () => { }, // Usually, this would cause infer_ip to be set to 'never' // but we're passing it in explicitly, so it should be preserved - sendDefaultPii: false, + dataCollection: { userInfo: false }, }); const client = new BrowserClient(options); diff --git a/packages/browser/test/integrations/httpclient.test.ts b/packages/browser/test/integrations/httpclient.test.ts index 67b811cb1aa6..05b362754bad 100644 --- a/packages/browser/test/integrations/httpclient.test.ts +++ b/packages/browser/test/integrations/httpclient.test.ts @@ -90,8 +90,10 @@ describe('httpClientIntegration', () => { } describe('fetch', () => { - it('filters sensitive request and response headers while keeping safe ones with sendDefaultPii', () => { - const { fetchHandler, captureEventSpy } = setup({ sendDefaultPii: true }); + it('filters sensitive request and response headers while keeping safe ones with data collection enabled', () => { + const { fetchHandler, captureEventSpy } = setup({ + dataCollection: { httpHeaders: { request: true, response: true } }, + }); triggerFetch(fetchHandler, { requestHeaders: { @@ -123,7 +125,9 @@ describe('httpClientIntegration', () => { }); it('keeps PII headers like x-forwarded-for when collection is enabled', () => { - const { fetchHandler, captureEventSpy } = setup({ sendDefaultPii: true }); + const { fetchHandler, captureEventSpy } = setup({ + dataCollection: { httpHeaders: { request: true, response: true } }, + }); triggerFetch(fetchHandler, { requestHeaders: { @@ -219,8 +223,10 @@ describe('httpClientIntegration', () => { }); describe('xhr', () => { - it('filters sensitive request and response headers with sendDefaultPii', () => { - const { xhrHandler, captureEventSpy } = setup({ sendDefaultPii: true }); + it('filters sensitive request and response headers with data collection enabled', () => { + const { xhrHandler, captureEventSpy } = setup({ + dataCollection: { httpHeaders: { request: true, response: true } }, + }); triggerXhr(xhrHandler, { requestHeaders: { Authorization: 'Bearer super-secret-token', 'X-Custom': 'safe-value' }, @@ -242,7 +248,9 @@ describe('httpClientIntegration', () => { }); it('parses and filters sensitive cookies from the Set-Cookie response header', () => { - const { xhrHandler, captureEventSpy } = setup({ sendDefaultPii: true }); + const { xhrHandler, captureEventSpy } = setup({ + dataCollection: { httpHeaders: { request: true, response: true } }, + }); triggerXhr(xhrHandler, { setCookie: 'session=abc123; theme=dark; connect.sid=secret', diff --git a/packages/cloudflare/test/request.test.ts b/packages/cloudflare/test/request.test.ts index f9d8932aa87f..e991dc468646 100644 --- a/packages/cloudflare/test/request.test.ts +++ b/packages/cloudflare/test/request.test.ts @@ -325,56 +325,6 @@ describe('withSentry', () => { expect(sentryEvent.request?.cookies).toBeUndefined(); }); - test('captures cookies when dataCollection.cookies is enabled', async () => { - let sentryEvent: Event = {}; - - await wrapRequestHandler( - { - options: { - ...MOCK_OPTIONS, - dataCollection: { cookies: true }, - beforeSend(event) { - sentryEvent = event; - return null; - }, - }, - request: new Request('https://example.com', { headers: { cookie: 'foo=bar' } }), - context: createMockExecutionContext(), - }, - () => { - SentryCore.captureMessage('cookies'); - return new Response('test'); - }, - ); - - expect(sentryEvent.request?.cookies).toEqual({ foo: 'bar' }); - }); - - test('captures cookies when sendDefaultPii is enabled', async () => { - let sentryEvent: Event = {}; - - await wrapRequestHandler( - { - options: { - ...MOCK_OPTIONS, - sendDefaultPii: true, - beforeSend(event) { - sentryEvent = event; - return null; - }, - }, - request: new Request('https://example.com', { headers: { cookie: 'foo=bar' } }), - context: createMockExecutionContext(), - }, - () => { - SentryCore.captureMessage('cookies'); - return new Response('test'); - }, - ); - - expect(sentryEvent.request?.cookies).toEqual({ foo: 'bar' }); - }); - test('does not capture request body for GET requests', async () => { let sentryEvent: Event = {}; const context = createMockExecutionContext(); diff --git a/packages/core/test/lib/integrations/mcp-server/piiFiltering.test.ts b/packages/core/test/lib/integrations/mcp-server/piiFiltering.test.ts index 8da2aa9cdd27..8be3c1919957 100644 --- a/packages/core/test/lib/integrations/mcp-server/piiFiltering.test.ts +++ b/packages/core/test/lib/integrations/mcp-server/piiFiltering.test.ts @@ -3,12 +3,7 @@ import * as currentScopes from '../../../../src/currentScopes'; import { wrapMcpServerWithSentry } from '../../../../src/integrations/mcp-server'; import { filterMcpPiiFromSpanData } from '../../../../src/integrations/mcp-server/piiFiltering'; import * as tracingModule from '../../../../src/tracing'; -import { - createMockClient, - createMockMcpServer, - createMockTransport, - createTestClientWithSendDefaultPii, -} from './testUtils'; +import { createMockClient, createMockMcpServer, createMockTransport } from './testUtils'; describe('MCP Server PII Filtering', () => { const startInactiveSpanSpy = vi.spyOn(tracingModule, 'startInactiveSpan'); @@ -102,67 +97,6 @@ describe('MCP Server PII Filtering', () => { }); }); - describe('Integration Tests - Network PII (sendDefaultPii bridge)', () => { - let mockMcpServer: ReturnType; - let mockTransport: ReturnType; - - beforeEach(() => { - mockMcpServer = createMockMcpServer(); - mockTransport = createMockTransport(); - mockTransport.sessionId = 'test-session-123'; - }); - - it('should include network PII when sendDefaultPii is true', async () => { - getClientSpy.mockReturnValue(createTestClientWithSendDefaultPii(true)); - - const wrappedMcpServer = wrapMcpServerWithSentry(mockMcpServer); - await wrappedMcpServer.connect(mockTransport); - - const extraWithClientInfo = { - requestInfo: { remoteAddress: '192.168.1.100', remotePort: 54321 }, - }; - - mockTransport.onmessage?.( - { jsonrpc: '2.0', method: 'tools/call', id: 'req-pii-true', params: { name: 'weather', arguments: {} } }, - extraWithClientInfo, - ); - - expect(startInactiveSpanSpy).toHaveBeenCalledWith( - expect.objectContaining({ - attributes: expect.objectContaining({ - 'client.address': '192.168.1.100', - 'client.port': 54321, - }), - }), - ); - }); - - it('should exclude network PII when sendDefaultPii is false', async () => { - getClientSpy.mockReturnValue(createTestClientWithSendDefaultPii(false)); - - const wrappedMcpServer = wrapMcpServerWithSentry(mockMcpServer); - await wrappedMcpServer.connect(mockTransport); - - const extraWithClientInfo = { - requestInfo: { remoteAddress: '192.168.1.100', remotePort: 54321 }, - }; - - mockTransport.onmessage?.( - { jsonrpc: '2.0', method: 'tools/call', id: 'req-pii-false', params: { name: 'weather', arguments: {} } }, - extraWithClientInfo, - ); - - expect(startInactiveSpanSpy).toHaveBeenCalledWith( - expect.objectContaining({ - attributes: expect.not.objectContaining({ - 'client.address': expect.anything(), - 'client.port': expect.anything(), - }), - }), - ); - }); - }); - describe('filterMcpPiiFromSpanData Function', () => { it('should preserve all data when userInfo is true', () => { const spanData = { diff --git a/packages/core/test/lib/integrations/mcp-server/testUtils.ts b/packages/core/test/lib/integrations/mcp-server/testUtils.ts index 2a34ee6eeb8a..5a86f78c72da 100644 --- a/packages/core/test/lib/integrations/mcp-server/testUtils.ts +++ b/packages/core/test/lib/integrations/mcp-server/testUtils.ts @@ -1,6 +1,5 @@ import type { Client } from '../../../../src/client'; import { vi } from 'vitest'; -import { getDefaultTestClientOptions, TestClient } from '../../../mocks/client'; /** * Creates a mock Sentry client with getDataCollectionOptions for use in MCP server tests. @@ -28,14 +27,6 @@ export function createMockClient(userInfo = true, genAI?: { inputs: boolean; out } as unknown as Client; } -/** - * Creates a real TestClient configured with the legacy sendDefaultPii flag. - * Use this in tests that verify the sendDefaultPii → dataCollection bridge still works. - */ -export function createTestClientWithSendDefaultPii(sendDefaultPii: boolean): Client { - return new TestClient(getDefaultTestClientOptions({ dsn: 'https://key@sentry.io/1', sendDefaultPii })); -} - /** * Create a mock MCP server instance for testing (legacy API: tool/resource/prompt) */ diff --git a/packages/core/test/lib/integrations/mcp-server/transportInstrumentation.test.ts b/packages/core/test/lib/integrations/mcp-server/transportInstrumentation.test.ts index a7b00bb3b1c6..703374363a23 100644 --- a/packages/core/test/lib/integrations/mcp-server/transportInstrumentation.test.ts +++ b/packages/core/test/lib/integrations/mcp-server/transportInstrumentation.test.ts @@ -30,7 +30,6 @@ import { createMockStdioTransport, createMockTransport, createMockWrapperTransport, - createTestClientWithSendDefaultPii, } from './testUtils'; describe('MCP Server Transport Instrumentation', () => { @@ -807,63 +806,6 @@ describe('MCP Server Transport Instrumentation', () => { }), ); }); - - // todo: delete the following test once we remove sendDefaultPii - it('should capture inputs/outputs when sendDefaultPii is false (genAI collected by default)', async () => { - getClientSpy.mockReturnValue(createTestClientWithSendDefaultPii(false)); - - const mockMcpServer = createMockMcpServer(); - const wrappedMcpServer = wrapMcpServerWithSentry(mockMcpServer); - const transport = createMockTransport(); - - await wrappedMcpServer.connect(transport); - - transport.onmessage?.( - { - jsonrpc: '2.0', - method: 'tools/call', - id: 'tool-1', - params: { name: 'weather', arguments: { location: 'London' } }, - }, - {}, - ); - - expect(startInactiveSpanSpy).toHaveBeenCalledWith( - expect.objectContaining({ - attributes: expect.objectContaining({ - 'mcp.request.argument.location': expect.anything(), - }), - }), - ); - }); - - it('should capture inputs/outputs when sendDefaultPii is true (legacy bridge)', async () => { - getClientSpy.mockReturnValue(createTestClientWithSendDefaultPii(true)); - - const mockMcpServer = createMockMcpServer(); - const wrappedMcpServer = wrapMcpServerWithSentry(mockMcpServer); - const transport = createMockTransport(); - - await wrappedMcpServer.connect(transport); - - transport.onmessage?.( - { - jsonrpc: '2.0', - method: 'tools/call', - id: 'tool-1', - params: { name: 'weather', arguments: { location: 'London' } }, - }, - {}, - ); - - expect(startInactiveSpanSpy).toHaveBeenCalledWith( - expect.objectContaining({ - attributes: expect.objectContaining({ - 'mcp.request.argument.location': '"London"', - }), - }), - ); - }); }); describe('Wrapper Transport Pattern (NodeStreamableHTTPServerTransport)', () => { diff --git a/packages/core/test/lib/integrations/requestdata.test.ts b/packages/core/test/lib/integrations/requestdata.test.ts index d65a35e8ec1a..2810277fe90f 100644 --- a/packages/core/test/lib/integrations/requestdata.test.ts +++ b/packages/core/test/lib/integrations/requestdata.test.ts @@ -8,10 +8,10 @@ import type { StreamedSpanJSON } from '../../../src/types/span'; import { resolveDataCollectionOptions } from '../../../src/utils/data-collection/resolveDataCollectionOptions'; import { ipHeaderNames } from '../../../src/vendor/getIpAddress'; -function mockClient(sendDefaultPii: boolean | undefined, dataCollection?: DataCollection): Client { +function mockClient(dataCollection?: DataCollection): Client { return { - getOptions: () => ({ sendDefaultPii: sendDefaultPii as boolean | undefined }), - getDataCollectionOptions: () => resolveDataCollectionOptions({ sendDefaultPii, dataCollection }), + getOptions: () => ({ dataCollection }), + getDataCollectionOptions: () => resolveDataCollectionOptions({ dataCollection }), } as unknown as Client; } @@ -54,7 +54,7 @@ describe('requestDataIntegration', () => { const integration = requestDataIntegration(); const event = baseEvent(); - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.headers).toEqual({ Host: 'example.com', @@ -77,7 +77,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.headers).toEqual({ Host: 'example.com', @@ -89,7 +89,7 @@ describe('requestDataIntegration', () => { const integration = requestDataIntegration(); const event = baseEvent(); - integration.processEvent?.(event, {}, mockClient(true)); + integration.processEvent?.(event, {}, mockClient({ userInfo: true })); expect(event.request?.headers).toEqual({ Host: 'example.com', @@ -102,7 +102,7 @@ describe('requestDataIntegration', () => { const integration = requestDataIntegration({ include: { ip: true } }); const event = baseEvent(); - integration.processEvent?.(event, {}, mockClient(false, { userInfo: false })); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.headers?.['X-Forwarded-For']).toBe('192.168.1.1'); expect(event.user?.ip_address).toBe('192.168.1.1'); @@ -112,7 +112,7 @@ describe('requestDataIntegration', () => { const integration = requestDataIntegration({ include: { ip: false } }); const event = baseEvent(); - integration.processEvent?.(event, {}, mockClient(true)); + integration.processEvent?.(event, {}, mockClient({ userInfo: true })); expect(event.request?.headers).toEqual({ Host: 'example.com' }); }); @@ -133,7 +133,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.headers).toEqual({ host: 'example.com', @@ -157,7 +157,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(true)); + integration.processEvent?.(event, {}, mockClient({ userInfo: true })); expect(event.request?.headers).toEqual({ host: 'example.com', @@ -172,7 +172,7 @@ describe('requestDataIntegration', () => { const integration = requestDataIntegration(); const event = baseEvent(); - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.user?.ip_address).toBeUndefined(); }); @@ -181,7 +181,7 @@ describe('requestDataIntegration', () => { const integration = requestDataIntegration(); const event = baseEvent(); - integration.processEvent?.(event, {}, mockClient(true)); + integration.processEvent?.(event, {}, mockClient({ userInfo: true })); expect(event.user?.ip_address).toBe('192.168.1.1'); }); @@ -201,7 +201,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(true)); + integration.processEvent?.(event, {}, mockClient({ userInfo: true })); expect(event.user?.ip_address).toBe('192.168.1.9'); }); @@ -219,7 +219,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(true)); + integration.processEvent?.(event, {}, mockClient({ userInfo: true })); expect(event.user?.ip_address).toBe('198.51.100.7'); }); @@ -237,7 +237,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.user?.ip_address).toBeUndefined(); }); @@ -250,7 +250,7 @@ describe('requestDataIntegration', () => { sdkProcessingMetadata: { normalizedRequest: richNormalizedRequest() }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.headers).toBeUndefined(); expect(event.request?.method).toBe('POST'); @@ -271,7 +271,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.headers).toBeUndefined(); expect(event.request?.cookies).toEqual({ id: '42' }); @@ -285,7 +285,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false, { httpHeaders: { request: true, response: true } })); + integration.processEvent?.(event, {}, mockClient({ httpHeaders: { request: true, response: true } })); expect(event.request?.headers).toBeUndefined(); }); @@ -303,7 +303,7 @@ describe('requestDataIntegration', () => { integration.processEvent?.( event, {}, - mockClient(false, { httpHeaders: { request: { allow: ['accept'] }, response: true } }), + mockClient({ httpHeaders: { request: { allow: ['accept'] }, response: true } }), ); expect(event.request?.headers).toEqual({ @@ -325,7 +325,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(true)); + integration.processEvent?.(event, {}, mockClient({ userInfo: true })); expect(event.request?.headers).toBeUndefined(); expect(event.user?.ip_address).toBe('192.0.2.1'); @@ -342,7 +342,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.headers).toEqual({ Accept: 'application/json', Authorization: '[Filtered]' }); }); @@ -366,7 +366,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(true)); + integration.processEvent?.(event, {}, mockClient({ userInfo: true })); expect(event.request?.headers).toEqual({ Host: 'example.com', @@ -389,7 +389,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.cookies).toBeUndefined(); }); @@ -402,7 +402,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false, { cookies: true })); + integration.processEvent?.(event, {}, mockClient({ cookies: true })); expect(event.request?.cookies).toBeUndefined(); }); @@ -415,7 +415,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false, { cookies: false })); + integration.processEvent?.(event, {}, mockClient({ cookies: false })); expect(event.request?.cookies).toEqual({ theme: 'dark', session: '[Filtered]' }); }); @@ -428,7 +428,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false, { cookies: { deny: ['experiment'] } })); + integration.processEvent?.(event, {}, mockClient({ cookies: { deny: ['experiment'] } })); expect(event.request?.cookies).toEqual({ theme: 'dark', @@ -445,7 +445,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false, { cookies: { allow: ['theme'] } })); + integration.processEvent?.(event, {}, mockClient({ cookies: { allow: ['theme'] } })); expect(event.request?.cookies).toEqual({ theme: 'dark', @@ -467,7 +467,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.cookies).toEqual({ preference: 'abc' }); }); @@ -485,7 +485,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.cookies).toEqual({ from: 'object' }); }); @@ -502,7 +502,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.cookies).toEqual({ a: '1', b: 'two' }); }); @@ -517,7 +517,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.cookies).toEqual({ theme: 'dark', @@ -536,7 +536,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false, { cookies: { deny: ['experiment'] } })); + integration.processEvent?.(event, {}, mockClient({ cookies: { deny: ['experiment'] } })); expect(event.request?.cookies).toEqual({ theme: 'dark', experiment: '[Filtered]' }); }); @@ -553,7 +553,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.cookies).toEqual({}); }); @@ -566,7 +566,7 @@ describe('requestDataIntegration', () => { sdkProcessingMetadata: { normalizedRequest: richNormalizedRequest() }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.url).toBeUndefined(); expect(event.request?.method).toBe('POST'); @@ -582,7 +582,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false, { urlQueryParams: true })); + integration.processEvent?.(event, {}, mockClient({ urlQueryParams: true })); expect(event.request?.query_string).toBeUndefined(); }); @@ -595,7 +595,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false, { urlQueryParams: false })); + integration.processEvent?.(event, {}, mockClient({ urlQueryParams: false })); expect(event.request?.query_string).toBe('page=1&token=[Filtered]'); }); @@ -608,7 +608,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.query_string).toBe('q=hello%20world&token=[Filtered]'); }); @@ -621,7 +621,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false, { urlQueryParams: { allow: ['page'] } })); + integration.processEvent?.(event, {}, mockClient({ urlQueryParams: { allow: ['page'] } })); expect(event.request?.query_string).toBe('page=1&sort=[Filtered]&token=[Filtered]'); }); @@ -632,7 +632,7 @@ describe('requestDataIntegration', () => { sdkProcessingMetadata: { normalizedRequest: richNormalizedRequest() }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.query_string).toBeUndefined(); expect(event.request?.url).toBe('https://example.com/items?q=1'); @@ -646,7 +646,7 @@ describe('requestDataIntegration', () => { sdkProcessingMetadata: { normalizedRequest: richNormalizedRequest() }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.data).toBeUndefined(); }); @@ -659,7 +659,7 @@ describe('requestDataIntegration', () => { sdkProcessingMetadata: { normalizedRequest: richNormalizedRequest() }, }; - integration.processEvent?.(event, {}, mockClient(true)); + integration.processEvent?.(event, {}, mockClient({ userInfo: true })); expect(event.request).toEqual({ method: 'POST', @@ -683,7 +683,7 @@ describe('requestDataIntegration', () => { sdkProcessingMetadata: { normalizedRequest: richNormalizedRequest() }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.headers).toEqual({ Host: 'example.com', @@ -707,7 +707,7 @@ describe('requestDataIntegration', () => { sdkProcessingMetadata: { normalizedRequest: richNormalizedRequest() }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.method).toBe('POST'); expect(event.request?.headers?.Host).toBe('example.com'); @@ -724,7 +724,7 @@ describe('requestDataIntegration', () => { const integration = requestDataIntegration(); const event: Event = { sdkProcessingMetadata: {} }; - integration.processEvent?.(event, {}, mockClient(true)); + integration.processEvent?.(event, {}, mockClient({ userInfo: true })); expect(event.request).toBeUndefined(); }); @@ -736,7 +736,7 @@ describe('requestDataIntegration', () => { sdkProcessingMetadata: {}, }; - integration.processEvent?.(event, {}, mockClient(true)); + integration.processEvent?.(event, {}, mockClient({ userInfo: true })); expect(event.request).toEqual({ url: 'https://unchanged/' }); }); @@ -756,7 +756,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.env).toEqual({ INTEGRATION: 'test' }); expect(event.request?.method).toBe('PUT'); @@ -776,7 +776,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(event.request?.url).toBe('https://preserved/'); expect(event.request?.method).toBe('GET'); @@ -799,7 +799,7 @@ describe('requestDataIntegration', () => { }, }; - integration.processEvent?.(event, {}, mockClient(false)); + integration.processEvent?.(event, {}, mockClient({ userInfo: false })); expect(normalizedHeaders['X-Forwarded-For']).toBe('192.168.1.1'); expect(event.request?.headers?.['X-Forwarded-For']).toBeUndefined(); @@ -847,7 +847,7 @@ describe('requestDataIntegration processSegmentSpan', () => { }, }); - integration.processSegmentSpan!(span, mockClient(false)); + integration.processSegmentSpan!(span, mockClient({ userInfo: false })); expect(span.attributes).toMatchObject({ 'url.full': 'https://example.com/api/users', @@ -864,7 +864,7 @@ describe('requestDataIntegration processSegmentSpan', () => { mockIsolationScope({}); - integration.processSegmentSpan!(span, mockClient(false)); + integration.processSegmentSpan!(span, mockClient({ userInfo: false })); expect(span.attributes).toEqual({}); }); @@ -878,7 +878,7 @@ describe('requestDataIntegration processSegmentSpan', () => { headers: { 'x-forwarded-for': '203.0.113.50' }, }); - integration.processSegmentSpan!(span, mockClient(true)); + integration.processSegmentSpan!(span, mockClient({ userInfo: true })); expect(span.attributes).toMatchObject({ 'user.ip_address': '203.0.113.50', @@ -891,7 +891,7 @@ describe('requestDataIntegration processSegmentSpan', () => { mockIsolationScope({ url: 'https://example.com', headers: {} }, '192.168.1.1'); - integration.processSegmentSpan!(span, mockClient(true)); + integration.processSegmentSpan!(span, mockClient({ userInfo: true })); expect(span.attributes).toMatchObject({ 'user.ip_address': '192.168.1.1', @@ -907,7 +907,7 @@ describe('requestDataIntegration processSegmentSpan', () => { headers: { 'x-forwarded-for': '203.0.113.50' }, }); - integration.processSegmentSpan!(span, mockClient(false)); + integration.processSegmentSpan!(span, mockClient({ userInfo: false })); expect(span.attributes).not.toHaveProperty('user.ip_address'); }); @@ -920,7 +920,7 @@ describe('requestDataIntegration processSegmentSpan', () => { cookies: { theme: 'dark', locale: 'en' }, }); - integration.processSegmentSpan!(span, mockClient(false)); + integration.processSegmentSpan!(span, mockClient({ userInfo: false })); expect(span.attributes).toMatchObject({ 'http.request.header.cookie.theme': 'dark', @@ -936,7 +936,7 @@ describe('requestDataIntegration processSegmentSpan', () => { headers: { cookie: 'theme=dark; locale=en' }, }); - integration.processSegmentSpan!(span, mockClient(false)); + integration.processSegmentSpan!(span, mockClient({ userInfo: false })); expect(span.attributes).toMatchObject({ 'http.request.header.cookie.theme': 'dark', @@ -952,7 +952,7 @@ describe('requestDataIntegration processSegmentSpan', () => { cookies: { theme: 'dark', 'connect.sid': 'secret', session_token: 'secret' }, }); - integration.processSegmentSpan!(span, mockClient(false)); + integration.processSegmentSpan!(span, mockClient({ userInfo: false })); expect(span.attributes).toMatchObject({ 'http.request.header.cookie.theme': 'dark', @@ -967,7 +967,7 @@ describe('requestDataIntegration processSegmentSpan', () => { mockIsolationScope({ data: { key: 'value' } }); - integration.processSegmentSpan!(span, mockClient(false)); + integration.processSegmentSpan!(span, mockClient({ userInfo: false })); expect(span.attributes).toMatchObject({ 'http.request.body.data': '{"key":"value"}', @@ -980,7 +980,7 @@ describe('requestDataIntegration processSegmentSpan', () => { mockIsolationScope({ query_string: { page: '1', limit: '10' } }); - integration.processSegmentSpan!(span, mockClient(false)); + integration.processSegmentSpan!(span, mockClient({ userInfo: false })); expect(span.attributes).toMatchObject({ 'url.query': 'page=1&limit=10', @@ -993,7 +993,7 @@ describe('requestDataIntegration processSegmentSpan', () => { mockIsolationScope({ query_string: { redirect: '/home?tab=one&sort=asc', token: 'secret' } }); - integration.processSegmentSpan!(span, mockClient(false)); + integration.processSegmentSpan!(span, mockClient({ userInfo: false })); expect(span.attributes).toMatchObject({ 'url.query': 'redirect=%2Fhome%3Ftab%3Done%26sort%3Dasc&token=[Filtered]', @@ -1012,7 +1012,7 @@ describe('requestDataIntegration processSegmentSpan', () => { ], }); - integration.processSegmentSpan!(span, mockClient(false)); + integration.processSegmentSpan!(span, mockClient({ userInfo: false })); expect(span.attributes).toMatchObject({ 'url.query': 'page=hello+world&page=second%26value&token=[Filtered]', @@ -1026,7 +1026,7 @@ describe('requestDataIntegration processSegmentSpan', () => { mockIsolationScope({ url: 'https://example.com', method: 'GET' }); - integration.processSegmentSpan!(span, mockClient(false)); + integration.processSegmentSpan!(span, mockClient({ userInfo: false })); expect(span.attributes).not.toHaveProperty('url.full'); expect(span.attributes).toMatchObject({ 'http.request.method': 'GET' }); @@ -1041,7 +1041,7 @@ describe('requestDataIntegration processSegmentSpan', () => { headers: { 'content-type': 'application/json' }, }); - integration.processSegmentSpan!(span, mockClient(false)); + integration.processSegmentSpan!(span, mockClient({ userInfo: false })); expect(span.attributes).not.toHaveProperty('http.request.header.content_type'); }); @@ -1054,7 +1054,7 @@ describe('requestDataIntegration processSegmentSpan', () => { headers: { 'content-type': 'application/json', cookie: 'theme=dark' }, }); - integration.processSegmentSpan!(span, mockClient(false)); + integration.processSegmentSpan!(span, mockClient({ userInfo: false })); expect(span.attributes).toMatchObject({ 'http.request.header.content_type': 'application/json', @@ -1070,7 +1070,7 @@ describe('requestDataIntegration processSegmentSpan', () => { headers: { 'content-type': 'application/json', 'x-forwarded-for': '203.0.113.50' }, }); - integration.processSegmentSpan!(span, mockClient(false)); + integration.processSegmentSpan!(span, mockClient({ userInfo: false })); expect(span.attributes).toMatchObject({ 'http.request.header.content_type': 'application/json', @@ -1085,7 +1085,7 @@ describe('requestDataIntegration processSegmentSpan', () => { mockIsolationScope({ url: 'https://example.com', data: { key: 'value' } }); - integration.processSegmentSpan!(span, mockClient(false)); + integration.processSegmentSpan!(span, mockClient({ userInfo: false })); expect(span.attributes).not.toHaveProperty('http.request.body.data'); }); @@ -1096,7 +1096,7 @@ describe('requestDataIntegration processSegmentSpan', () => { mockIsolationScope({ url: 'https://example.com', query_string: 'page=1' }); - integration.processSegmentSpan!(span, mockClient(false)); + integration.processSegmentSpan!(span, mockClient({ userInfo: false })); expect(span.attributes).not.toHaveProperty('url.query'); }); @@ -1107,7 +1107,7 @@ describe('requestDataIntegration processSegmentSpan', () => { mockIsolationScope({ headers: { 'x-forwarded-for': '203.0.113.50' } }); - integration.processSegmentSpan!(span, mockClient(false, { userInfo: false })); + integration.processSegmentSpan!(span, mockClient({ userInfo: false })); expect(span.attributes?.['user.ip_address']).toBe('203.0.113.50'); }); @@ -1120,7 +1120,7 @@ describe('requestDataIntegration processSegmentSpan', () => { headers: { 'content-type': 'application/json', accept: 'text/html' }, }); - integration.processSegmentSpan!(span, mockClient(false, { httpHeaders: { request: false, response: false } })); + integration.processSegmentSpan!(span, mockClient({ httpHeaders: { request: false, response: false } })); expect(span.attributes).toMatchObject({ 'http.request.header.content_type': 'application/json', @@ -1136,7 +1136,7 @@ describe('requestDataIntegration processSegmentSpan', () => { integration.processSegmentSpan!( span, - mockClient(false, { httpHeaders: { request: { allow: ['accept'] }, response: true } }), + mockClient({ httpHeaders: { request: { allow: ['accept'] }, response: true } }), ); expect(span.attributes?.['http.request.header.accept']).toBe('application/json'); @@ -1151,7 +1151,7 @@ describe('requestDataIntegration processSegmentSpan', () => { cookies: { theme: 'dark', locale: 'en' }, }); - integration.processSegmentSpan!(span, mockClient(false, { cookies: false })); + integration.processSegmentSpan!(span, mockClient({ cookies: false })); expect(span.attributes).toMatchObject({ 'http.request.header.cookie.theme': 'dark', @@ -1165,7 +1165,7 @@ describe('requestDataIntegration processSegmentSpan', () => { mockIsolationScope({ cookies: { theme: 'dark', locale: 'en', session: 'secret' } }); - integration.processSegmentSpan!(span, mockClient(false, { cookies: { allow: ['theme'] } })); + integration.processSegmentSpan!(span, mockClient({ cookies: { allow: ['theme'] } })); expect(span.attributes?.['http.request.header.cookie.theme']).toBe('dark'); expect(span.attributes?.['http.request.header.cookie.locale']).toBe('[Filtered]'); @@ -1178,14 +1178,14 @@ describe('requestDataIntegration processSegmentSpan', () => { mockIsolationScope({ query_string: 'page=1&token=secret' }); - integration.processSegmentSpan!(span, mockClient(false, { urlQueryParams: false })); + integration.processSegmentSpan!(span, mockClient({ urlQueryParams: false })); expect(span.attributes?.['url.query']).toBe('page=1&token=[Filtered]'); }); }); }); -describe('requestDataIntegration legacy sendDefaultPii bridge', () => { +describe('requestDataIntegration userInfo collection', () => { afterEach(() => { vi.restoreAllMocks(); }); @@ -1212,17 +1212,17 @@ describe('requestDataIntegration legacy sendDefaultPii bridge', () => { } as ReturnType); } - it('sendDefaultPii: true bridges to userInfo: true and includes IP on events', () => { + it('includes IP on events when dataCollection.userInfo is true', () => { const integration = requestDataIntegration(); const event = baseEvent(); - integration.processEvent?.(event, {}, mockClient(true)); + integration.processEvent?.(event, {}, mockClient({ userInfo: true })); expect(event.user?.ip_address).toBe('192.168.1.1'); expect(event.request?.headers?.['X-Forwarded-For']).toBe('192.168.1.1'); }); - it('sendDefaultPii: true bridges to userInfo: true and includes IP on spans', () => { + it('includes IP on spans when dataCollection.userInfo is true', () => { const integration = requestDataIntegration(); const span = makeSpan(); @@ -1231,7 +1231,7 @@ describe('requestDataIntegration legacy sendDefaultPii bridge', () => { headers: { 'x-forwarded-for': '203.0.113.50', 'content-type': 'application/json' }, }); - integration.processSegmentSpan!(span, mockClient(true)); + integration.processSegmentSpan!(span, mockClient({ userInfo: true })); expect(span.attributes).toMatchObject({ 'user.ip_address': '203.0.113.50', diff --git a/packages/core/test/lib/integrations/supabase.test.ts b/packages/core/test/lib/integrations/supabase.test.ts index 361af18f19fc..07ef5f583205 100644 --- a/packages/core/test/lib/integrations/supabase.test.ts +++ b/packages/core/test/lib/integrations/supabase.test.ts @@ -330,8 +330,8 @@ describe('Supabase Integration', () => { expect(spanOptions.attributes['db.body']).toBeUndefined(); }); - it('includes data when legacy sendDefaultPii: true is bridged to dataCollection.databaseQueryData', async () => { - const resolved = resolveDataCollectionOptions({ sendDefaultPii: true }); + it('includes data when dataCollection.databaseQueryData is true', async () => { + const resolved = resolveDataCollectionOptions({ dataCollection: { databaseQueryData: true } }); currentScopesMocks.getClient.mockReturnValue({ getDataCollectionOptions: () => resolved, } as any); @@ -354,8 +354,8 @@ describe('Supabase Integration', () => { ); }); - it('redacts data when legacy sendDefaultPii is not set (bridged defaults)', async () => { - const resolved = resolveDataCollectionOptions({ sendDefaultPii: false }); + it('redacts data when dataCollection.databaseQueryData is false', async () => { + const resolved = resolveDataCollectionOptions({ dataCollection: { databaseQueryData: false } }); currentScopesMocks.getClient.mockReturnValue({ getDataCollectionOptions: () => resolved, } as any); diff --git a/packages/core/test/lib/logs/internal.test.ts b/packages/core/test/lib/logs/internal.test.ts index c98cd8574692..b4b061c2d1c6 100644 --- a/packages/core/test/lib/logs/internal.test.ts +++ b/packages/core/test/lib/logs/internal.test.ts @@ -863,7 +863,7 @@ describe('_INTERNAL_captureLog', () => { it('includes partial user data when only some fields are available', () => { const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, - sendDefaultPii: true, + dataCollection: { userInfo: true }, }); const client = new TestClient(options); const scope = new Scope(); @@ -888,7 +888,7 @@ describe('_INTERNAL_captureLog', () => { it('includes user email and username without id', () => { const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, - sendDefaultPii: true, + dataCollection: { userInfo: true }, }); const client = new TestClient(options); const scope = new Scope(); @@ -918,7 +918,7 @@ describe('_INTERNAL_captureLog', () => { it('does not include user data when user object is empty', () => { const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, - sendDefaultPii: true, + dataCollection: { userInfo: true }, }); const client = new TestClient(options); const scope = new Scope(); @@ -936,7 +936,7 @@ describe('_INTERNAL_captureLog', () => { it('combines user data with other log attributes', () => { const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, - sendDefaultPii: true, + dataCollection: { userInfo: true }, release: '1.0.0', environment: 'test', }); @@ -990,7 +990,7 @@ describe('_INTERNAL_captureLog', () => { it('handles user data with non-string values', () => { const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, - sendDefaultPii: true, + dataCollection: { userInfo: true }, }); const client = new TestClient(options); const scope = new Scope(); @@ -1020,7 +1020,7 @@ describe('_INTERNAL_captureLog', () => { it('preserves existing user attributes in log and does not override them', () => { const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, - sendDefaultPii: true, + dataCollection: { userInfo: true }, }); const client = new TestClient(options); const scope = new Scope(); @@ -1063,7 +1063,7 @@ describe('_INTERNAL_captureLog', () => { it('only adds scope user data for attributes that do not already exist', () => { const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, - sendDefaultPii: true, + dataCollection: { userInfo: true }, }); const client = new TestClient(options); const scope = new Scope(); diff --git a/packages/core/test/lib/metrics/internal.test.ts b/packages/core/test/lib/metrics/internal.test.ts index 8faf24f992d0..2fc2993e27c4 100644 --- a/packages/core/test/lib/metrics/internal.test.ts +++ b/packages/core/test/lib/metrics/internal.test.ts @@ -272,7 +272,7 @@ describe('_INTERNAL_captureMetric', () => { expect(envelopeItemPayload.ingest_settings).toEqual({ infer_ip: 'auto', infer_user_agent: 'auto' }); }); - it('includes ingest_settings with never when dataCollection is not set (sendDefaultPii bridge defaults to userInfo: false)', () => { + it('includes ingest_settings with never when dataCollection is not set', () => { vi.spyOn(isBrowserModule, 'isBrowser').mockReturnValue(true); const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN }); diff --git a/packages/core/test/lib/tracing/ai/utils.test.ts b/packages/core/test/lib/tracing/ai/utils.test.ts index 7a6286223dec..c39b8673984c 100644 --- a/packages/core/test/lib/tracing/ai/utils.test.ts +++ b/packages/core/test/lib/tracing/ai/utils.test.ts @@ -20,13 +20,6 @@ describe('resolveAIRecordingOptions', () => { getGlobalScope().clear(); }); - function setupWithSendDefaultPii(sendDefaultPii: boolean): void { - const options = getDefaultTestClientOptions({ tracesSampleRate: 1, sendDefaultPii }); - const client = new TestClient(options); - setCurrentClient(client); - client.init(); - } - function setupWithDataCollection(genAI: { inputs?: boolean; outputs?: boolean }): void { const options = getDefaultTestClientOptions({ tracesSampleRate: 1, dataCollection: { genAI } }); const client = new TestClient(options); @@ -38,22 +31,6 @@ describe('resolveAIRecordingOptions', () => { expect(resolveAIRecordingOptions()).toEqual({ recordInputs: true, recordOutputs: true }); }); - // todo: delete the following tests once we remove sendDefaultPii - it.skip('defaults to false when sendDefaultPii is false (bridge)', () => { - setupWithSendDefaultPii(false); - expect(resolveAIRecordingOptions()).toEqual({ recordInputs: false, recordOutputs: false }); - }); - - it.skip('defaults to true when sendDefaultPii is true (bridge)', () => { - setupWithSendDefaultPii(true); - expect(resolveAIRecordingOptions()).toEqual({ recordInputs: true, recordOutputs: true }); - }); - - it.skip('explicit options override sendDefaultPii bridge', () => { - setupWithSendDefaultPii(true); - expect(resolveAIRecordingOptions({ recordInputs: false })).toEqual({ recordInputs: false, recordOutputs: true }); - }); - it('respects dataCollection.genAI.inputs and outputs', () => { setupWithDataCollection({ inputs: true, outputs: true }); expect(resolveAIRecordingOptions()).toEqual({ recordInputs: true, recordOutputs: true }); diff --git a/packages/core/test/lib/tracing/spans/captureSpan.test.ts b/packages/core/test/lib/tracing/spans/captureSpan.test.ts index 0560ebd2f702..d6578571238c 100644 --- a/packages/core/test/lib/tracing/spans/captureSpan.test.ts +++ b/packages/core/test/lib/tracing/spans/captureSpan.test.ts @@ -30,106 +30,103 @@ import { } from '@sentry/conventions/attributes'; describe('captureSpan', () => { - it.each([true, false, undefined])( - 'always applies scope user attributes to spans (sendDefaultPii: %s)', - sendDefaultPii => { - const client = new TestClient( - getDefaultTestClientOptions({ - dsn: 'https://dsn@ingest.f00.f00/1', - tracesSampleRate: 1, - release: '1.0.0', - environment: 'staging', - sendDefaultPii, - }), - ); + // User attributes are gated with dataCollection.userInfo, but could me manually set on the scope (and we send it) + it('always applies scope user attributes to spans', () => { + const client = new TestClient( + getDefaultTestClientOptions({ + dsn: 'https://dsn@ingest.f00.f00/1', + tracesSampleRate: 1, + release: '1.0.0', + environment: 'staging', + }), + ); - const span = withScope(scope => { - scope.setClient(client); - scope.setUser({ - id: '123', - email: 'user@example.com', - username: 'testuser', - ip_address: '127.0.0.1', - }); + const span = withScope(scope => { + scope.setClient(client); + scope.setUser({ + id: '123', + email: 'user@example.com', + username: 'testuser', + ip_address: '127.0.0.1', + }); - const span = startInactiveSpan({ name: 'my-span', attributes: { 'sentry.op': 'http.client' } }); - span.end(); + const span = startInactiveSpan({ name: 'my-span', attributes: { 'sentry.op': 'http.client' } }); + span.end(); - return span; - }); + return span; + }); - expect(captureSpan(span, client)).toStrictEqual({ - span_id: expect.stringMatching(/^[\da-f]{16}$/), - trace_id: expect.stringMatching(/^[\da-f]{32}$/), - parent_span_id: undefined, - links: undefined, - start_timestamp: expect.any(Number), - name: 'my-span', - end_timestamp: expect.any(Number), - status: 'ok', - is_segment: true, - attributes: { - [SENTRY_TRACE_LIFECYCLE]: { - type: 'string', - value: 'stream', - }, - [SEMANTIC_ATTRIBUTE_SENTRY_OP]: { - type: 'string', - value: 'http.client', - }, - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { - type: 'string', - value: 'manual', - }, - [SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: { - type: 'integer', - value: 1, - }, - [SENTRY_SEGMENT_NAME]: { - value: 'my-span', - type: 'string', - }, - [SENTRY_SEGMENT_ID]: { - value: span.spanContext().spanId, - type: 'string', - }, - ['sentry.segment.name.source']: { - value: 'custom', - type: 'string', - }, - [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: { - value: 'custom', - type: 'string', - }, - [SEMANTIC_ATTRIBUTE_SENTRY_RELEASE]: { - value: '1.0.0', - type: 'string', - }, - [SEMANTIC_ATTRIBUTE_SENTRY_ENVIRONMENT]: { - value: 'staging', - type: 'string', - }, - [SEMANTIC_ATTRIBUTE_USER_ID]: { - value: '123', - type: 'string', - }, - [SEMANTIC_ATTRIBUTE_USER_EMAIL]: { - value: 'user@example.com', - type: 'string', - }, - [SEMANTIC_ATTRIBUTE_USER_USERNAME]: { - value: 'testuser', - type: 'string', - }, - [SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS]: { - value: '127.0.0.1', - type: 'string', - }, + expect(captureSpan(span, client)).toStrictEqual({ + span_id: expect.stringMatching(/^[\da-f]{16}$/), + trace_id: expect.stringMatching(/^[\da-f]{32}$/), + parent_span_id: undefined, + links: undefined, + start_timestamp: expect.any(Number), + name: 'my-span', + end_timestamp: expect.any(Number), + status: 'ok', + is_segment: true, + attributes: { + [SENTRY_TRACE_LIFECYCLE]: { + type: 'string', + value: 'stream', }, - _segmentSpan: span, - }); - }, - ); + [SEMANTIC_ATTRIBUTE_SENTRY_OP]: { + type: 'string', + value: 'http.client', + }, + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: { + type: 'string', + value: 'manual', + }, + [SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: { + type: 'integer', + value: 1, + }, + [SENTRY_SEGMENT_NAME]: { + value: 'my-span', + type: 'string', + }, + [SENTRY_SEGMENT_ID]: { + value: span.spanContext().spanId, + type: 'string', + }, + ['sentry.segment.name.source']: { + value: 'custom', + type: 'string', + }, + [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: { + value: 'custom', + type: 'string', + }, + [SEMANTIC_ATTRIBUTE_SENTRY_RELEASE]: { + value: '1.0.0', + type: 'string', + }, + [SEMANTIC_ATTRIBUTE_SENTRY_ENVIRONMENT]: { + value: 'staging', + type: 'string', + }, + [SEMANTIC_ATTRIBUTE_USER_ID]: { + value: '123', + type: 'string', + }, + [SEMANTIC_ATTRIBUTE_USER_EMAIL]: { + value: 'user@example.com', + type: 'string', + }, + [SEMANTIC_ATTRIBUTE_USER_USERNAME]: { + value: 'testuser', + type: 'string', + }, + [SEMANTIC_ATTRIBUTE_USER_IP_ADDRESS]: { + value: '127.0.0.1', + type: 'string', + }, + }, + _segmentSpan: span, + }); + }); it('captures sdk name and version if available', () => { const client = new TestClient( @@ -438,7 +435,7 @@ describe('captureSpan', () => { tracesSampleRate: 1, release: '1.0.0', environment: 'staging', - sendDefaultPii: true, + dataCollection: { userInfo: true }, }), ); diff --git a/packages/core/test/lib/tracing/spans/envelope.test.ts b/packages/core/test/lib/tracing/spans/envelope.test.ts index 3686f7577dd6..e682a8865f8f 100644 --- a/packages/core/test/lib/tracing/spans/envelope.test.ts +++ b/packages/core/test/lib/tracing/spans/envelope.test.ts @@ -303,11 +303,11 @@ describe('createStreamedSpanEnvelope', () => { ]); }); - it('respects sendDefaultPii: true bridged to dataCollection.userInfo', () => { + it('sets ingest settings when dataCollection.userInfo is true', () => { vi.mocked(isBrowser).mockReturnValue(true); const mockSpan = createMockSerializedSpan(); - const mockClient = new TestClient(getDefaultTestClientOptions({ sendDefaultPii: true })); + const mockClient = new TestClient(getDefaultTestClientOptions({ dataCollection: { userInfo: true } })); const dsc: Partial = {}; const envelopeItems = createStreamedSpanEnvelope([mockSpan], dsc, mockClient)[1]; @@ -324,11 +324,11 @@ describe('createStreamedSpanEnvelope', () => { ]); }); - it('respects sendDefaultPii: false bridged to dataCollection.userInfo', () => { + it('sets ingest settings when dataCollection.userInfo is false', () => { vi.mocked(isBrowser).mockReturnValue(true); const mockSpan = createMockSerializedSpan(); - const mockClient = new TestClient(getDefaultTestClientOptions({ sendDefaultPii: false })); + const mockClient = new TestClient(getDefaultTestClientOptions({ dataCollection: { userInfo: false } })); const dsc: Partial = {}; const envelopeItems = createStreamedSpanEnvelope([mockSpan], dsc, mockClient)[1]; diff --git a/packages/core/test/lib/trpc.test.ts b/packages/core/test/lib/trpc.test.ts index 587d531b5d00..20b8e143f927 100644 --- a/packages/core/test/lib/trpc.test.ts +++ b/packages/core/test/lib/trpc.test.ts @@ -12,9 +12,11 @@ describe('trpcMiddleware', () => { const mockClient = { getOptions: vi.fn().mockReturnValue({ normalizeDepth: 3, - sendDefaultPii: false, + dataCollection: { httpBodies: [] }, }), - getDataCollectionOptions: vi.fn().mockReturnValue(resolveDataCollectionOptions({ sendDefaultPii: false })), + getDataCollectionOptions: vi + .fn() + .mockReturnValue(resolveDataCollectionOptions({ dataCollection: { httpBodies: [] } })), captureException: vi.fn(), } as unknown as Client; diff --git a/packages/core/test/lib/utils/data-collection/defaultPiiToCollectionOptions.test.ts b/packages/core/test/lib/utils/data-collection/defaultPiiToCollectionOptions.test.ts deleted file mode 100644 index dcbe278362e8..000000000000 --- a/packages/core/test/lib/utils/data-collection/defaultPiiToCollectionOptions.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { defaultPiiToCollectionOptions } from '../../../../src/utils/data-collection/defaultPiiToCollectionOptions'; - -describe('defaultPiiToCollectionOptions', () => { - it('returns permissive options when sendDefaultPii is true', () => { - expect(defaultPiiToCollectionOptions(true)).toEqual({ - userInfo: true, - cookies: true, - httpHeaders: { request: true, response: true }, - httpBodies: ['incomingRequest', 'outgoingRequest', 'incomingResponse', 'outgoingResponse'], - urlQueryParams: true, - graphQL: { document: true, variables: true }, - genAI: { inputs: true, outputs: true }, - databaseQueryData: true, - stackFrameVariables: true, - frameContextLines: 7, - }); - }); - - it('returns restrictive options when sendDefaultPii is false', () => { - expect(defaultPiiToCollectionOptions(false)).toEqual({ - userInfo: false, - cookies: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, - httpHeaders: { - request: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, - response: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, - }, - httpBodies: ['incomingRequest', 'outgoingRequest', 'incomingResponse', 'outgoingResponse'], - urlQueryParams: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, - graphQL: { document: true, variables: true }, - genAI: { inputs: true, outputs: true }, - databaseQueryData: false, - stackFrameVariables: true, - frameContextLines: 7, - }); - }); - - it('returns restrictive options when sendDefaultPii is undefined', () => { - expect(defaultPiiToCollectionOptions(undefined)).toEqual({ - userInfo: false, - cookies: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, - httpHeaders: { - request: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, - response: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, - }, - httpBodies: ['incomingRequest', 'outgoingRequest', 'incomingResponse', 'outgoingResponse'], - urlQueryParams: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, - graphQL: { document: true, variables: true }, - genAI: { inputs: true, outputs: true }, - databaseQueryData: false, - stackFrameVariables: true, - frameContextLines: 7, - }); - }); - - it('returns restrictive options when called with no arguments', () => { - expect(defaultPiiToCollectionOptions()).toEqual({ - userInfo: false, - cookies: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, - httpHeaders: { - request: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, - response: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, - }, - httpBodies: ['incomingRequest', 'outgoingRequest', 'incomingResponse', 'outgoingResponse'], - urlQueryParams: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, - graphQL: { document: true, variables: true }, - genAI: { inputs: true, outputs: true }, - databaseQueryData: false, - stackFrameVariables: true, - frameContextLines: 7, - }); - }); -}); diff --git a/packages/core/test/lib/utils/data-collection/resolveDataCollectionOptions.test.ts b/packages/core/test/lib/utils/data-collection/resolveDataCollectionOptions.test.ts index 310ae1ca85ad..bba37ae7608c 100644 --- a/packages/core/test/lib/utils/data-collection/resolveDataCollectionOptions.test.ts +++ b/packages/core/test/lib/utils/data-collection/resolveDataCollectionOptions.test.ts @@ -16,14 +16,12 @@ describe('resolveDataCollectionOptions', () => { }; describe('with no options', () => { - it('falls through to sendDefaultPii: undefined bridge when neither option is set', () => { + it('uses restrictive defaults when dataCollection is not set', () => { const result = resolveDataCollectionOptions({}); - // sendDefaultPii undefined → restrictive bridge (backward compat; userInfo defaults to true only when dataCollection is set) expect(result.userInfo).toBe(false); expect(result.httpBodies).toEqual(['incomingRequest', 'outgoingRequest', 'incomingResponse', 'outgoingResponse']); expect(result.genAI).toEqual({ inputs: true, outputs: true }); - // GraphQL documents are redacted at collection time, so they stay on to preserve legacy behavior. expect(result.graphQL).toEqual({ document: true, variables: true }); expect(result.databaseQueryData).toBe(false); expect(result.stackFrameVariables).toBe(true); @@ -41,41 +39,11 @@ describe('resolveDataCollectionOptions', () => { }); }); - describe('sendDefaultPii bridge (no dataCollection)', () => { - it('bridges sendDefaultPii: true to permissive config', () => { - const result = resolveDataCollectionOptions({ sendDefaultPii: true }); + describe('dataCollection options', () => { + it('uses spec defaults for fields that are not explicitly set', () => { + const result = resolveDataCollectionOptions({ dataCollection: { userInfo: false } }); - expect(result.userInfo).toBe(true); - expect(result.cookies).toBe(true); - expect(result.httpHeaders).toEqual({ request: true, response: true }); - expect(result.httpBodies).toEqual(['incomingRequest', 'outgoingRequest', 'incomingResponse', 'outgoingResponse']); - expect(result.urlQueryParams).toBe(true); - expect(result.graphQL).toEqual({ document: true, variables: true }); - expect(result.genAI).toEqual({ inputs: true, outputs: true }); - expect(result.databaseQueryData).toBe(true); - }); - - it('bridges sendDefaultPii: false to restrictive config', () => { - const result = resolveDataCollectionOptions({ sendDefaultPii: false }); - - expect(result.userInfo).toBe(false); - expect(result.httpBodies).toEqual(['incomingRequest', 'outgoingRequest', 'incomingResponse', 'outgoingResponse']); - expect(result.genAI).toEqual({ inputs: true, outputs: true }); - expect(result.graphQL).toEqual({ document: true, variables: true }); - expect(result.databaseQueryData).toBe(false); - }); - }); - - describe('dataCollection takes precedence over sendDefaultPii', () => { - it('uses dataCollection fields when both are set', () => { - const result = resolveDataCollectionOptions({ - sendDefaultPii: true, - dataCollection: { userInfo: false }, - }); - - // Explicit dataCollection override expect(result.userInfo).toBe(false); - // Remaining fields use spec defaults (not sendDefaultPii bridge) expect(result.httpBodies).toEqual(['incomingRequest', 'outgoingRequest', 'incomingResponse', 'outgoingResponse']); expect(result.genAI).toEqual({ inputs: true, outputs: true }); expect(result.databaseQueryData).toBe(true); diff --git a/packages/core/test/lib/utils/request.test.ts b/packages/core/test/lib/utils/request.test.ts index 4783f98be9f0..35652116e415 100644 --- a/packages/core/test/lib/utils/request.test.ts +++ b/packages/core/test/lib/utils/request.test.ts @@ -684,10 +684,21 @@ describe('request utils', () => { }); }); - it('still filters session-style cookie names when sendDefaultPii is true', () => { + it('still filters session-style cookie names when cookie collection is enabled', () => { const headers = { Cookie: 'connect.sid=s3cr3t; analytics=1' }; - const result = httpHeadersToSpanAttributes(headers, true); + const result = httpHeadersToSpanAttributes(headers, { + userInfo: true, + cookies: true, + httpHeaders: { request: true, response: true }, + httpBodies: [], + urlQueryParams: true, + graphQL: { document: true, variables: true }, + genAI: { inputs: true, outputs: true }, + databaseQueryData: true, + stackFrameVariables: true, + frameContextLines: 5, + }); expect(result).toEqual({ 'http.request.header.cookie.connect.sid': '[Filtered]', @@ -728,9 +739,51 @@ describe('request utils', () => { }); it.each([ - { sendDefaultPii: false, description: 'sendDefaultPii is false (default)' }, - { sendDefaultPii: true, description: 'sendDefaultPii is true' }, - ])('does not include PII headers when $description', ({ sendDefaultPii }) => { + { + dataCollection: { + userInfo: false, + cookies: true, + httpHeaders: { request: { deny: ['forwarded', '-ip', 'remote-', 'via', '-user'] }, response: true }, + httpBodies: [], + urlQueryParams: true, + graphQL: { document: true, variables: true }, + genAI: { inputs: true, outputs: true }, + databaseQueryData: true, + stackFrameVariables: true, + frameContextLines: 5, + }, + expected: { + 'http.request.header.content_type': 'application/json', + 'http.request.header.user_agent': 'Mozilla/5.0', + 'http.request.header.x_user': '[Filtered]', + 'http.request.header.x_forwarded_for': '[Filtered]', + 'http.request.header.x_forwarded_host': '[Filtered]', + 'http.request.header.x_forwarded_proto': '[Filtered]', + }, + }, + { + dataCollection: { + userInfo: true, + cookies: true, + httpHeaders: { request: true, response: true }, + httpBodies: [], + urlQueryParams: true, + graphQL: { document: true, variables: true }, + genAI: { inputs: true, outputs: true }, + databaseQueryData: true, + stackFrameVariables: true, + frameContextLines: 5, + }, + expected: { + 'http.request.header.content_type': 'application/json', + 'http.request.header.user_agent': 'Mozilla/5.0', + 'http.request.header.x_user': 'my-personal-username', + 'http.request.header.x_forwarded_for': '192.168.1.1', + 'http.request.header.x_forwarded_host': 'example.com', + 'http.request.header.x_forwarded_proto': 'https', + }, + }, + ])('filters PII headers according to dataCollection.httpHeaders', ({ dataCollection, expected }) => { const headers = { 'Content-Type': 'application/json', 'User-Agent': 'Mozilla/5.0', @@ -740,27 +793,7 @@ describe('request utils', () => { 'X-Forwarded-Proto': 'https', }; - const result = httpHeadersToSpanAttributes(headers, sendDefaultPii); - - if (sendDefaultPii) { - expect(result).toEqual({ - 'http.request.header.content_type': 'application/json', - 'http.request.header.user_agent': 'Mozilla/5.0', - 'http.request.header.x_user': 'my-personal-username', - 'http.request.header.x_forwarded_for': '192.168.1.1', - 'http.request.header.x_forwarded_host': 'example.com', - 'http.request.header.x_forwarded_proto': 'https', - }); - } else { - expect(result).toEqual({ - 'http.request.header.content_type': 'application/json', - 'http.request.header.user_agent': 'Mozilla/5.0', - 'http.request.header.x_user': '[Filtered]', - 'http.request.header.x_forwarded_for': '[Filtered]', - 'http.request.header.x_forwarded_host': '[Filtered]', - 'http.request.header.x_forwarded_proto': '[Filtered]', - }); - } + expect(httpHeadersToSpanAttributes(headers, dataCollection)).toEqual(expected); }); it('always filters comprehensive list of sensitive headers', () => { diff --git a/packages/deno/test/deno-serve.test.ts b/packages/deno/test/deno-serve.test.ts index 5622f3b34dbf..4ae95c4eb494 100644 --- a/packages/deno/test/deno-serve.test.ts +++ b/packages/deno/test/deno-serve.test.ts @@ -281,7 +281,7 @@ Deno.test('Deno.serve should capture request headers and set response context', dsn: 'https://username@domain/123', tracesSampleRate: 1, traceLifecycle: 'static', - sendDefaultPii: true, + dataCollection: { httpHeaders: { request: true, response: true } }, beforeSendTransaction: (event: TransactionEvent) => { transactionEvents.push(event); return null; @@ -362,42 +362,6 @@ Deno.test('Deno.serve should capture client address and port when userInfo data assertExists(transaction?.contexts?.trace?.data?.['client.port']); }); -Deno.test('Deno.serve should capture client address and port when sendDefaultPii is enabled', async () => { - resetGlobals(); - const transactionEvents: TransactionEvent[] = []; - - init({ - dsn: 'https://username@domain/123', - tracesSampleRate: 1, - traceLifecycle: 'static', - sendDefaultPii: true, - beforeSendTransaction: (event: TransactionEvent) => { - transactionEvents.push(event); - return null; - }, - }) as DenoClient; - - const abortController = new AbortController(); - let onListen: ((_: unknown) => void) | undefined = undefined; - const p = new Promise(resolve => (onListen = resolve)); - const server = Deno.serve({ port: 0, signal: abortController.signal, onListen }, () => { - return new Response('OK'); - }); - await p; - - const res = await fetch(`http://localhost:${server.addr.port}/test`); - assertEquals(await res.text(), 'OK'); - - abortController.abort(); - await server.finished; - - assertEquals(transactionEvents.length, 1); - const [transaction] = transactionEvents; - - assertExists(transaction?.contexts?.trace?.data?.['client.address']); - assertExists(transaction?.contexts?.trace?.data?.['client.port']); -}); - Deno.test('Deno.serve should not capture client address by default', async () => { resetGlobals(); const transactionEvents: TransactionEvent[] = []; diff --git a/packages/nextjs/test/utils/setUrlProcessingMetadata.test.ts b/packages/nextjs/test/utils/setUrlProcessingMetadata.test.ts index a170fbaa8a71..907f71e74495 100644 --- a/packages/nextjs/test/utils/setUrlProcessingMetadata.test.ts +++ b/packages/nextjs/test/utils/setUrlProcessingMetadata.test.ts @@ -9,9 +9,9 @@ describe('setUrlProcessingMetadata', () => { setUrlProcessingMetadata(event); }); - it('adds URL without sendDefaultPii', () => { + it('adds URL with data collection disabled', () => { vi.spyOn(SentryCore, 'getClient').mockReturnValue({ - getOptions: () => ({ sendDefaultPii: false }), + getOptions: () => ({ dataCollection: { userInfo: false } }), } as unknown as SentryCore.Client); const scopeData = { diff --git a/packages/node/test/integrations/systemError.test.ts b/packages/node/test/integrations/systemError.test.ts index cdbe2c824b6c..341b4d155868 100644 --- a/packages/node/test/integrations/systemError.test.ts +++ b/packages/node/test/integrations/systemError.test.ts @@ -25,13 +25,10 @@ describe('systemErrorIntegration', () => { vi.mocked(util.getSystemErrorMap).mockRestore(); }); - function createClient({ sendDefaultPii, userInfo }: { sendDefaultPii?: boolean; userInfo?: boolean } = {}): Client { - // When userInfo is explicitly provided, use it directly. - // Otherwise fall back to sendDefaultPii (mimicking resolveDataCollectionOptions). - const resolvedUserInfo = userInfo ?? sendDefaultPii ?? false; + function createClient({ userInfo = false }: { userInfo?: boolean } = {}): Client { return { - getOptions: () => ({ sendDefaultPii }), - getDataCollectionOptions: () => ({ userInfo: resolvedUserInfo }), + getOptions: () => ({ dataCollection: { userInfo } }), + getDataCollectionOptions: () => ({ userInfo }), } as unknown as Client; } @@ -106,44 +103,6 @@ describe('systemErrorIntegration', () => { expect(result.contexts?.node_system_error).toEqual({ errno }); }); - it('keeps path in context when legacy sendDefaultPii is true', () => { - const errno = -2; - vi.mocked(util.getSystemErrorMap).mockReturnValue( - new Map([[errno, ['ENOENT', 'no such file or directory']]]), - ); - - const integration = systemErrorIntegration(); - const error = Object.assign(new Error('boom'), { errno, path: '/secret/path' }); - const event = { exception: { values: [{ value: error.message }] } } as Event; - - const result = integration.processEvent!( - event, - { originalException: error }, - createClient({ sendDefaultPii: true }), - ) as Event; - - expect(result.contexts?.node_system_error).toEqual({ errno, path: '/secret/path' }); - }); - - it('strips path from context when legacy sendDefaultPii is false', () => { - const errno = -2; - vi.mocked(util.getSystemErrorMap).mockReturnValue( - new Map([[errno, ['ENOENT', 'no such file or directory']]]), - ); - - const integration = systemErrorIntegration(); - const error = Object.assign(new Error('boom'), { errno, path: '/secret/path' }); - const event = { exception: { values: [{ value: error.message }] } } as Event; - - const result = integration.processEvent!( - event, - { originalException: error }, - createClient({ sendDefaultPii: false }), - ) as Event; - - expect(result.contexts?.node_system_error).toEqual({ errno }); - }); - it('keeps path in context when includePaths option is true', () => { const errno = -2; vi.mocked(util.getSystemErrorMap).mockReturnValue(