Skip to content

Commit f37e448

Browse files
Merge branch 'main' into ensure-android-plugin-type-safety
2 parents 86a8998 + 05f2a7f commit f37e448

9 files changed

Lines changed: 149 additions & 47 deletions

File tree

.github/workflows/codeql-analysis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ jobs:
4444

4545
# Initializes the CodeQL tools for scanning.
4646
- name: Initialize CodeQL
47-
uses: github/codeql-action/init@76621b61decf072c1cee8dd1ce2d2a82d33c17ed # pin@v3.29.5
47+
uses: github/codeql-action/init@df559355d593797519d70b90fc8edd5db049e7a2 # pin@v3.29.5
4848
with:
4949
languages: ${{ matrix.language }}
5050
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -55,7 +55,7 @@ jobs:
5555
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
5656
# If this step fails, then you should remove it and run the build manually (see below)
5757
- name: Autobuild
58-
uses: github/codeql-action/autobuild@76621b61decf072c1cee8dd1ce2d2a82d33c17ed # pin@v3.29.5
58+
uses: github/codeql-action/autobuild@df559355d593797519d70b90fc8edd5db049e7a2 # pin@v3.29.5
5959

6060
# ℹ️ Command-line programs to run using the OS shell.
6161
# 📚 https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
@@ -66,4 +66,4 @@ jobs:
6666
# make bootstrap
6767
# make release
6868
- name: Perform CodeQL Analysis
69-
uses: github/codeql-action/analyze@76621b61decf072c1cee8dd1ce2d2a82d33c17ed # pin@v3.29.5
69+
uses: github/codeql-action/analyze@df559355d593797519d70b90fc8edd5db049e7a2 # pin@v3.29.5

.github/workflows/e2e-v2.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ jobs:
313313
runs-on: macos-14
314314
- platform: ios
315315
rn-version: '0.65.3'
316-
runs-on: macos-15
316+
runs-on: macos-14
317317
- platform: android
318318
runs-on: ubuntu-latest
319319
exclude:

.github/workflows/native-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818

1919
test-ios:
2020
name: ios
21-
runs-on: macos-15
21+
runs-on: macos-14
2222
needs: [diff_check]
2323
if: ${{ needs.diff_check.outputs.skip_ci != 'true' }}
2424
steps:

.github/workflows/testflight.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414

1515
upload_to_testflight:
1616
name: Build and Upload React Native Sample to Testflight
17-
runs-on: macos-15
17+
runs-on: macos-14
1818
needs: [diff_check]
1919
if: ${{ needs.diff_check.outputs.skip_ci != 'true' }}
2020
steps:

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,29 @@
66
> make sure you follow our [migration guide](https://docs.sentry.io/platforms/react-native/migration/) first.
77
<!-- prettier-ignore-end -->
88
9+
## Unreleased
10+
11+
12+
### Important Changes
13+
14+
- **fix(browser): Ensure IP address is only inferred by Relay if `sendDefaultPii` is `true`** ([#5092](https://github.com/getsentry/sentry-react-native/pull/5092))
15+
16+
This release includes a fix for a [behaviour change](https://docs.sentry.io/platforms/javascript/migration/v8-to-v9/#behavior-changes)
17+
that was originally introduced with v9 of the JavaScript SDK: User IP Addresses should only be added to Sentry events automatically,
18+
if `sendDefaultPii` was set to `true`.
19+
20+
However, the change in v9 required further internal adjustment, which should have been included in v10 of the SDK.
21+
To avoid making a major bump, the fix was patched on the current version and not by bumping to V10.
22+
There is _no API_ breakage involved and hence it is safe to update.
23+
However, after updating the SDK, events (errors, traces, replays, etc.) sent from the browser, will only include
24+
user IP addresses, if you set `sendDefaultPii: true` in your `Sentry.init` options.
25+
26+
We apologize for any inconvenience caused!
27+
28+
## Fixes
29+
30+
- Remove the warning that used to indicate that Time To Initial Display and Time To Full Display are not supported ([#5081](https://github.com/getsentry/sentry-react-native/pull/5081))
31+
932
## 6.20.0
1033

1134
### Features

packages/core/src/js/integrations/sdkinfo.ts

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ import { isExpoGo, notWeb } from '../utils/environment';
55
import { SDK_NAME, SDK_PACKAGE_NAME, SDK_VERSION } from '../version';
66
import { NATIVE } from '../wrapper';
77

8+
// TODO: Remove this on JS V10.
9+
interface IpPatchedSdkInfo extends SdkInfoType {
10+
settings?: {
11+
infer_ip?: 'auto' | 'never';
12+
};
13+
}
14+
815
const INTEGRATION_NAME = 'SdkInfo';
916

1017
type DefaultSdkInfo = Pick<Required<SdkInfoType>, 'name' | 'packages' | 'version'>;
@@ -19,13 +26,25 @@ export const defaultSdkInfo: DefaultSdkInfo = {
1926
],
2027
version: SDK_VERSION,
2128
};
29+
let DefaultPii: boolean | undefined = undefined;
2230

2331
/** Default SdkInfo instrumentation */
2432
export const sdkInfoIntegration = (): Integration => {
2533
const fetchNativeSdkInfo = createCachedFetchNativeSdkInfo();
2634

2735
return {
2836
name: INTEGRATION_NAME,
37+
setup(client) {
38+
const options = client.getOptions();
39+
DefaultPii = options.sendDefaultPii;
40+
if (DefaultPii) {
41+
client.on('beforeSendEvent', event => {
42+
if (event.user?.ip_address === '{{auto}}') {
43+
delete event.user.ip_address;
44+
}
45+
});
46+
}
47+
},
2948
setupOnce: () => {
3049
// noop
3150
},
@@ -37,15 +56,24 @@ async function processEvent(event: Event, fetchNativeSdkInfo: () => Promise<Pack
3756
const nativeSdkPackage = await fetchNativeSdkInfo();
3857

3958
event.platform = event.platform || 'javascript';
40-
event.sdk = event.sdk || {};
41-
event.sdk.name = event.sdk.name || defaultSdkInfo.name;
42-
event.sdk.version = event.sdk.version || defaultSdkInfo.version;
43-
event.sdk.packages = [
59+
const sdk = (event.sdk || {}) as IpPatchedSdkInfo;
60+
sdk.name = sdk.name || defaultSdkInfo.name;
61+
sdk.version = sdk.version || defaultSdkInfo.version;
62+
sdk.packages = [
4463
// default packages are added by baseclient and should not be added here
45-
...(event.sdk.packages || []),
64+
...(sdk.packages || []),
4665
...((nativeSdkPackage && [nativeSdkPackage]) || []),
4766
];
4867

68+
// Patch missing infer_ip.
69+
sdk.settings = {
70+
infer_ip: DefaultPii ? 'auto' : 'never',
71+
// purposefully allowing already passed settings to override the default
72+
...sdk.settings,
73+
};
74+
75+
event.sdk = sdk;
76+
4977
return event;
5078
}
5179

packages/core/src/js/tracing/timetodisplay.tsx

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,10 @@ import { fill, getActiveSpan, getSpanDescendants, logger, SEMANTIC_ATTRIBUTE_SEN
33
import * as React from 'react';
44
import { useState } from 'react';
55

6-
import { isTurboModuleEnabled } from '../utils/environment';
76
import { SPAN_ORIGIN_AUTO_UI_TIME_TO_DISPLAY, SPAN_ORIGIN_MANUAL_UI_TIME_TO_DISPLAY } from './origin';
8-
import { getRNSentryOnDrawReporter, nativeComponentExists } from './timetodisplaynative';
7+
import { getRNSentryOnDrawReporter } from './timetodisplaynative';
98
import { setSpanDurationAsMeasurement, setSpanDurationAsMeasurementOnSpan } from './utils';
109

11-
let nativeComponentMissingLogged = false;
12-
1310
/**
1411
* Flags of active spans with manual initial display.
1512
*/
@@ -62,17 +59,6 @@ function TimeToDisplay(props: {
6259
parentSpanId?: string;
6360
}): React.ReactElement {
6461
const RNSentryOnDrawReporter = getRNSentryOnDrawReporter();
65-
const isNewArchitecture = isTurboModuleEnabled();
66-
67-
if (__DEV__ && (isNewArchitecture || (!nativeComponentExists && !nativeComponentMissingLogged))){
68-
nativeComponentMissingLogged = true;
69-
// Using setTimeout with a delay of 0 milliseconds to defer execution and avoid printing the React stack trace.
70-
setTimeout(() => {
71-
logger.warn(
72-
'TimeToInitialDisplay and TimeToFullDisplay are not supported on the web, Expo Go and New Architecture. Run native build or report an issue at https://github.com/getsentry/sentry-react-native');
73-
}, 0);
74-
}
75-
7662
return (
7763
<>
7864
<RNSentryOnDrawReporter

packages/core/test/integrations/sdkinfo.test.ts

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Event, EventHint, Package } from '@sentry/core';
1+
import type { Client, Event, EventHint, Package } from '@sentry/core';
22

33
import { SDK_NAME, SDK_VERSION } from '../../src/js';
44
import { sdkInfoIntegration } from '../../src/js/integrations/sdkinfo';
@@ -86,9 +86,93 @@ describe('Sdk Info', () => {
8686
expect(processedEvent?.sdk?.name).toEqual(SDK_NAME);
8787
expect(processedEvent?.sdk?.version).toEqual(SDK_VERSION);
8888
});
89+
90+
it('Add none setting when defaultIp is undefined', async () => {
91+
mockedFetchNativeSdkInfo = jest.fn().mockResolvedValue(null);
92+
const mockEvent: Event = {};
93+
const processedEvent = await processEvent(mockEvent, {}, undefined);
94+
95+
expect(processedEvent?.sdk?.name).toEqual(SDK_NAME);
96+
expect(processedEvent?.sdk?.version).toEqual(SDK_VERSION);
97+
// @ts-expect-error injected type.
98+
expect(processedEvent?.sdk?.settings?.infer_ip).toEqual('never');
99+
});
100+
101+
it('Add none setting when defaultIp is false', async () => {
102+
mockedFetchNativeSdkInfo = jest.fn().mockResolvedValue(null);
103+
const mockEvent: Event = {};
104+
const processedEvent = await processEvent(mockEvent, {}, false);
105+
106+
expect(processedEvent?.sdk?.name).toEqual(SDK_NAME);
107+
expect(processedEvent?.sdk?.version).toEqual(SDK_VERSION);
108+
// @ts-expect-error injected type.
109+
expect(processedEvent?.sdk?.settings?.infer_ip).toEqual('never');
110+
});
111+
112+
it('Add auto setting when defaultIp is true', async () => {
113+
mockedFetchNativeSdkInfo = jest.fn().mockResolvedValue(null);
114+
const mockEvent: Event = {};
115+
const processedEvent = await processEvent(mockEvent, {}, true);
116+
117+
expect(processedEvent?.sdk?.name).toEqual(SDK_NAME);
118+
expect(processedEvent?.sdk?.version).toEqual(SDK_VERSION);
119+
// @ts-expect-error injected type.
120+
expect(processedEvent?.sdk?.settings?.infer_ip).toEqual('auto');
121+
});
122+
123+
it('removes ip_address if it is "{{auto}}"', () => {
124+
const mockHandler = jest.fn();
125+
126+
const client = {
127+
getOptions: () => ({ sendDefaultPii: true }),
128+
on: (eventName: string, cb: (event: any) => void) => {
129+
if (eventName === 'beforeSendEvent') {
130+
mockHandler.mockImplementation(cb);
131+
}
132+
},
133+
};
134+
135+
sdkInfoIntegration().setup!(client as any);
136+
137+
const testEvent = { user: { ip_address: '{{auto}}' } };
138+
mockHandler(testEvent);
139+
140+
expect(testEvent.user.ip_address).toBeUndefined();
141+
});
142+
143+
it('keeps ip_address if it is not "{{auto}}"', () => {
144+
const mockHandler = jest.fn();
145+
146+
const client = {
147+
getOptions: () => ({ sendDefaultPii: true }),
148+
on: (eventName: string, cb: (event: any) => void) => {
149+
if (eventName === 'beforeSendEvent') {
150+
mockHandler.mockImplementation(cb);
151+
}
152+
},
153+
};
154+
155+
sdkInfoIntegration().setup!(client as any);
156+
157+
const testEvent = { user: { ip_address: '1.2.3.4' } };
158+
mockHandler(testEvent);
159+
160+
expect(testEvent.user.ip_address).toBe('1.2.3.4');
161+
});
89162
});
90163

91-
function processEvent(mockedEvent: Event, mockedHint: EventHint = {}): Event | null | PromiseLike<Event | null> {
164+
function processEvent(
165+
mockedEvent: Event,
166+
mockedHint: EventHint = {},
167+
sendDefaultPii?: boolean,
168+
): Event | null | PromiseLike<Event | null> {
92169
const integration = sdkInfoIntegration();
170+
if (sendDefaultPii != null) {
171+
const mockClient: jest.Mocked<Client> = {
172+
getOptions: jest.fn().mockReturnValue({ sendDefaultPii: sendDefaultPii }),
173+
on: jest.fn(),
174+
} as any;
175+
integration.setup!(mockClient);
176+
}
93177
return integration.processEvent!(mockedEvent, mockedHint, {} as any);
94178
}

packages/core/test/tracing/timetodisplay.test.tsx

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ jest.mock('../../src/js/wrapper', () => mockWrapper);
77
import * as mockedtimetodisplaynative from './mockedtimetodisplaynative';
88
jest.mock('../../src/js/tracing/timetodisplaynative', () => mockedtimetodisplaynative);
99

10-
import { isTurboModuleEnabled } from '../../src/js/utils/environment';
1110
jest.mock('../../src/js/utils/environment', () => ({
1211
isWeb: jest.fn().mockReturnValue(false),
1312
isTurboModuleEnabled: jest.fn().mockReturnValue(false),
@@ -290,24 +289,6 @@ describe('TimeToDisplay', () => {
290289
expect(getInitialDisplaySpanJSON(client.event!.spans!)!.timestamp).toEqual(initialDisplayEndTimestampMs / 1_000);
291290
expect(getFullDisplaySpanJSON(client.event!.spans!)!.timestamp).toEqual(initialDisplayEndTimestampMs / 1_000);
292291
});
293-
294-
test('should not log a warning if native component exists and not in new architecture', async () => {
295-
(isTurboModuleEnabled as jest.Mock).mockReturnValue(false);
296-
297-
TestRenderer.create(<TimeToInitialDisplay record={true} />);
298-
await jest.runOnlyPendingTimersAsync(); // Flush setTimeout.
299-
300-
expect(logger.warn).not.toHaveBeenCalled();
301-
});
302-
303-
test('should log a warning if in new architecture', async () => {
304-
(isTurboModuleEnabled as jest.Mock).mockReturnValue(true);
305-
TestRenderer.create(<TimeToInitialDisplay record={true} />);
306-
await jest.runOnlyPendingTimersAsync(); // Flush setTimeout.
307-
308-
expect(logger.warn).toHaveBeenCalledWith(
309-
'TimeToInitialDisplay and TimeToFullDisplay are not supported on the web, Expo Go and New Architecture. Run native build or report an issue at https://github.com/getsentry/sentry-react-native');
310-
});
311292
});
312293

313294
function getInitialDisplaySpanJSON(spans: SpanJSON[]) {

0 commit comments

Comments
 (0)