Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 6 additions & 16 deletions packages/browser/test/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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: {
Expand Down Expand Up @@ -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);

Expand Down
20 changes: 14 additions & 6 deletions packages/browser/test/integrations/httpclient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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: {
Expand Down Expand Up @@ -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' },
Expand All @@ -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',
Expand Down
50 changes: 0 additions & 50 deletions packages/cloudflare/test/request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -102,67 +97,6 @@ describe('MCP Server PII Filtering', () => {
});
});

describe('Integration Tests - Network PII (sendDefaultPii bridge)', () => {
let mockMcpServer: ReturnType<typeof createMockMcpServer>;
let mockTransport: ReturnType<typeof createMockTransport>;

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 = {
Expand Down
9 changes: 0 additions & 9 deletions packages/core/test/lib/integrations/mcp-server/testUtils.ts
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import {
createMockStdioTransport,
createMockTransport,
createMockWrapperTransport,
createTestClientWithSendDefaultPii,
} from './testUtils';

describe('MCP Server Transport Instrumentation', () => {
Expand Down Expand Up @@ -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)', () => {
Expand Down
Loading
Loading