diff --git a/CHANGELOG.md b/CHANGELOG.md index 99107ac..e08c04c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## Unreleased + +### Important Changes + +- **fix(browser): Ensure IP address is only inferred by Relay if `sendDefaultPii` is `true`** ([#390](https://github.com/getsentry/sentry-cordova/pull/390)) + +This release includes a fix for a behaviour change +that was originally introduced with the newer JavaScript SDK: User IP Addresses should only be added to Sentry events automatically, +if `sendDefaultPii` was set to `true`. + +To avoid making a major bump, the fix was patched on the current version and not by bumping to V10. +There is _no API_ breakage involved and hence it is safe to update. +However, after updating the SDK, events (errors, traces, replays, etc.) sent from the browser, will only include +user IP addresses, if you set `sendDefaultPii: true` in your `Sentry.init` options. + +We apologize for any inconvenience caused! + ## 1.6.0 ### Fixes diff --git a/src/js/__tests__/integrations/sdkinfo.test.ts b/src/js/__tests__/integrations/sdkinfo.test.ts new file mode 100644 index 0000000..2db8815 --- /dev/null +++ b/src/js/__tests__/integrations/sdkinfo.test.ts @@ -0,0 +1,95 @@ +import { addEventProcessor, getClient } from '@sentry/core'; + +import { SdkInfo } from '../../integrations/sdkinfo'; +import { SDK_NAME, SDK_VERSION } from '../../version'; + +jest.mock('@sentry/core', () => ({ + addEventProcessor: jest.fn(), + getClient: jest.fn(), +})); + +describe('SdkInfo Integration', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should have correct id and name', () => { + const sdkInfo = new SdkInfo(); + expect(SdkInfo.id).toBe('SdkInfo'); + expect(sdkInfo.name).toBe('SdkInfo'); + }); + + it('should add an event processor', () => { + (getClient as jest.Mock).mockReturnValue({ + getOptions: () => ({ sendDefaultPii: true }), + }); + + const sdkInfo = new SdkInfo(); + sdkInfo.setupOnce(); + + expect(addEventProcessor).toHaveBeenCalled(); + }); + + it('should patch event sdk info correctly with sendDefaultPii true', async () => { + (getClient as jest.Mock).mockReturnValue({ + getOptions: () => ({ sendDefaultPii: true }), + }); + + const sdkInfo = new SdkInfo(); + sdkInfo.setupOnce(); + + const eventProcessor = (addEventProcessor as jest.Mock).mock.calls[0][0]; + + const event = { sdk: { packages: [] } }; + const processedEvent = await eventProcessor(event); + + expect(processedEvent.platform).toBe('javascript'); + expect(processedEvent.sdk.name).toBe(SDK_NAME); + expect(processedEvent.sdk.version).toBe(SDK_VERSION); + expect(processedEvent.sdk.packages).toContainEqual({ + name: 'npm:sentry-cordova', + version: SDK_VERSION, + }); + expect(processedEvent.sdk.settings?.infer_ip).toBe('auto'); + }); + + it('should patch event sdk info correctly with sendDefaultPii false', async () => { + (getClient as jest.Mock).mockReturnValue({ + getOptions: () => ({ sendDefaultPii: false }), + }); + + const sdkInfo = new SdkInfo(); + sdkInfo.setupOnce(); + + const eventProcessor = (addEventProcessor as jest.Mock).mock.calls[0][0]; + + const event = { sdk: {} }; + const processedEvent = await eventProcessor(event); + + expect(processedEvent.sdk.settings?.infer_ip).toBe('never'); + }); + + it('should preserve existing sdk settings', async () => { + (getClient as jest.Mock).mockReturnValue({ + getOptions: () => ({ sendDefaultPii: true }), + }); + + const sdkInfo = new SdkInfo(); + sdkInfo.setupOnce(); + + const eventProcessor = (addEventProcessor as jest.Mock).mock.calls[0][0]; + + const event = { + sdk: { + packages: [], + settings: { debug: true }, + }, + }; + const processedEvent = await eventProcessor(event); + + expect(processedEvent.sdk.settings).toEqual({ + infer_ip: 'auto', + debug: true, + }); + }); +}); diff --git a/src/js/integrations/sdkinfo.ts b/src/js/integrations/sdkinfo.ts index cef5b5b..ddf7c92 100644 --- a/src/js/integrations/sdkinfo.ts +++ b/src/js/integrations/sdkinfo.ts @@ -1,8 +1,14 @@ -import { addEventProcessor } from '@sentry/core'; -import type { Integration } from '@sentry/types'; +import { addEventProcessor, getClient } from '@sentry/core'; +import type { Integration, SdkInfo as SdkInfoType} from '@sentry/types'; import { SDK_NAME, SDK_VERSION } from '../version'; +interface IpPatchedSdkInfo extends SdkInfoType { + settings?: { + infer_ip?: 'auto' | 'never'; + }; +} + /** Default SdkInfo instrumentation */ export class SdkInfo implements Integration { /** @@ -19,21 +25,38 @@ export class SdkInfo implements Integration { * @inheritDoc */ public setupOnce(): void { + + let defaultPii: boolean | undefined = undefined; + + const client = getClient(); + if (client) { + const options = client.getOptions(); + defaultPii = options.sendDefaultPii; + } + addEventProcessor(async (event) => { event.platform = event.platform || 'javascript'; - event.sdk = { - ...event.sdk, - name: SDK_NAME, - packages: [ - ...((event.sdk && event.sdk.packages) || []), - { - name: 'npm:sentry-cordova', - version: SDK_VERSION, - }, - ], - version: SDK_VERSION, + const sdk = (event.sdk || {}) as IpPatchedSdkInfo; + + sdk.name = sdk.name || SDK_NAME; + sdk.packages = [ + ...((event.sdk && event.sdk.packages) || []), + { + name: 'npm:sentry-cordova', + version: SDK_VERSION, + }, + ]; + sdk.version = SDK_VERSION; + + // Patch missing infer_ip. + sdk.settings = { + infer_ip: defaultPii ? 'auto' : 'never', + // purposefully allowing already passed settings to override the default + ...sdk.settings }; + event.sdk = sdk; + return event; }); }