Skip to content

Commit 633f26d

Browse files
authored
feat(replay): Add warning banners for Jetpack Compose 1.8+ (#93916)
This displays warning banners on the replay list and details when: - any replay has sdk name `sentry.java.android` - sdk version is < 8.14.0 - on replay details we also check to see if it is a video replay ![image](https://github.com/user-attachments/assets/51ae7cc6-22d4-4353-9afd-d79f9d25ba4e) ![image](https://github.com/user-attachments/assets/f52a21d2-23ba-4172-acf5-8086e57e12f4)
1 parent c471f0b commit 633f26d

File tree

8 files changed

+169
-11
lines changed

8 files changed

+169
-11
lines changed

static/app/components/replays/replayView.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ import {ReplaySidebarToggleButton} from 'sentry/components/replays/replaySidebar
1414
import TextCopyInput from 'sentry/components/textCopyInput';
1515
import {tct} from 'sentry/locale';
1616
import {space} from 'sentry/styles/space';
17+
import {MIN_JETPACK_COMPOSE_VIEW_HIERARCHY_PII_FIX} from 'sentry/utils/replays/sdkVersions';
18+
import {semverCompare} from 'sentry/utils/versions/semverCompare';
1719
import useIsFullscreen from 'sentry/utils/window/useIsFullscreen';
1820
import Breadcrumbs from 'sentry/views/replays/detail/breadcrumbs';
1921
import BrowserOSIcons from 'sentry/views/replays/detail/browserOSIcons';
2022
import FluidHeight from 'sentry/views/replays/detail/layout/fluidHeight';
23+
import {JetpackComposePiiNotice} from 'sentry/views/replays/jetpackComposePiiNotice';
2124

2225
import {CanvasSupportNotice} from './canvasSupportNotice';
2326

@@ -82,6 +85,14 @@ function ReplayView({toggleFullscreen, isLoading}: Props) {
8285
<ReplayProcessingError processingErrors={replay.processingErrors()} />
8386
) : (
8487
<FluidHeight>
88+
{isVideoReplay &&
89+
replay?.getReplay()?.sdk.name === 'sentry.java.android' &&
90+
semverCompare(
91+
replay?.getReplay()?.sdk.version || '',
92+
MIN_JETPACK_COMPOSE_VIEW_HIERARCHY_PII_FIX.minVersion
93+
) === -1 ? (
94+
<JetpackComposePiiNotice />
95+
) : null}
8596
<CanvasSupportNotice />
8697
<Panel>
8798
<ReplayPlayer inspectable />

static/app/utils/replays/sdkVersions.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,8 @@ export const MIN_DEAD_RAGE_CLICK_SDK = {
33
changelog:
44
'https://changelog.getsentry.com/announcements/user-frustration-signals-rage-and-dead-clicks-in-session-replay',
55
};
6+
7+
export const MIN_JETPACK_COMPOSE_VIEW_HIERARCHY_PII_FIX = {
8+
minVersion: '8.14.0',
9+
changelog: 'https://github.com/getsentry/sentry-java/releases',
10+
};

static/app/views/replays/detail/tagPanel/useTagFilters.spec.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ describe('useTagsFilters', () => {
2424
const {result} = renderHook(useTagFilters, {
2525
initialProps: {tags},
2626
});
27-
expect(Object.keys(result.current.items)).toHaveLength(9);
27+
expect(Object.keys(result.current.items)).toHaveLength(10);
2828
});
2929

3030
it('should filter by searchTerm', () => {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import styled from '@emotion/styled';
2+
3+
import {Alert} from 'sentry/components/core/alert';
4+
import ExternalLink from 'sentry/components/links/externalLink';
5+
import {tct} from 'sentry/locale';
6+
import {space} from 'sentry/styles/space';
7+
import {MIN_JETPACK_COMPOSE_VIEW_HIERARCHY_PII_FIX} from 'sentry/utils/replays/sdkVersions';
8+
9+
export function JetpackComposePiiNotice() {
10+
return (
11+
<AndroidSdkWarningContainer>
12+
<Alert type="error" showIcon>
13+
{tct(
14+
'There is a [advisory:known PII/masking issue] with [jetpack:Jetpack Compose versions 1.8 and above]. [link:Update your Sentry SDK to version 8.14.0 or later] to ensure replays are properly masked.',
15+
{
16+
jetpack: <strong />,
17+
advisory: (
18+
<ExternalLink href="https://github.com/getsentry/sentry-java/security/advisories/GHSA-7cjh-xx4r-qh3f" />
19+
),
20+
link: (
21+
<ExternalLink href={MIN_JETPACK_COMPOSE_VIEW_HIERARCHY_PII_FIX.changelog} />
22+
),
23+
}
24+
)}
25+
</Alert>
26+
</AndroidSdkWarningContainer>
27+
);
28+
}
29+
30+
const AndroidSdkWarningContainer = styled('div')`
31+
margin-bottom: ${space(2)};
32+
`;

static/app/views/replays/list/replaysList.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@ import {t, tct} from 'sentry/locale';
66
import {trackAnalytics} from 'sentry/utils/analytics';
77
import {decodeList, decodeScalar, decodeSorts} from 'sentry/utils/queryString';
88
import useFetchReplayList from 'sentry/utils/replays/hooks/useFetchReplayList';
9+
import {MIN_JETPACK_COMPOSE_VIEW_HIERARCHY_PII_FIX} from 'sentry/utils/replays/sdkVersions';
910
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
1011
import useLocationQuery from 'sentry/utils/url/useLocationQuery';
1112
import {useNavigate} from 'sentry/utils/useNavigate';
1213
import useOrganization from 'sentry/utils/useOrganization';
1314
import usePageFilters from 'sentry/utils/usePageFilters';
1415
import useProjectSdkNeedsUpdate from 'sentry/utils/useProjectSdkNeedsUpdate';
16+
import {semverCompare} from 'sentry/utils/versions/semverCompare';
1517
import useAllMobileProj from 'sentry/views/replays/detail/useAllMobileProj';
18+
import {JetpackComposePiiNotice} from 'sentry/views/replays/jetpackComposePiiNotice';
1619
import ReplayTable from 'sentry/views/replays/replayTable';
1720
import {ReplayColumn} from 'sentry/views/replays/replayTable/types';
1821

@@ -84,8 +87,19 @@ function ReplaysList() {
8487
ReplayColumn.ACTIVITY,
8588
];
8689

90+
const needsJetpackComposePiiWarning = replays?.find(replay => {
91+
return (
92+
replay?.sdk.name === 'sentry.java.android' &&
93+
semverCompare(
94+
replay?.sdk.version ?? '',
95+
MIN_JETPACK_COMPOSE_VIEW_HIERARCHY_PII_FIX.minVersion
96+
) === -1
97+
);
98+
});
99+
87100
return (
88101
<Fragment>
102+
{needsJetpackComposePiiWarning && <JetpackComposePiiNotice />}
89103
<ReplayTable
90104
referrerLocation={'replay'}
91105
fetchError={error}

static/app/views/replays/types.tsx

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,34 @@ export type ReplayRecord = {
2020
name: null | string;
2121
version: null | string;
2222
};
23+
clicks: Array<{
24+
['click.alt']: string | null;
25+
['click.class']: string | null;
26+
['click.component_name']: string | null;
27+
['click.id']: string | null;
28+
['click.label']: string | null;
29+
['click.role']: string | null;
30+
['click.tag']: string | null;
31+
['click.testid']: string | null;
32+
['click.text']: string | null;
33+
['click.title']: string | null;
34+
}>;
35+
/**
36+
* The number of dead clicks associated with the replay.
37+
*/
38+
count_dead_clicks: number;
2339
/**
2440
* The number of errors associated with the replay.
2541
*/
2642
count_errors: number;
43+
/**
44+
* The number of infos associated with the replay.
45+
*/
46+
count_infos: number;
47+
/**
48+
* The number of rage clicks associated with the replay.
49+
*/
50+
count_rage_clicks: number;
2751
/**
2852
* The number of segments that make up the replay.
2953
*/
@@ -32,6 +56,10 @@ export type ReplayRecord = {
3256
* The number of urls visited in the replay.
3357
*/
3458
count_urls: number;
59+
/**
60+
* The number of warnings associated with the replay.
61+
*/
62+
count_warnings: number;
3563
device: {
3664
brand: null | string;
3765
family: null | string;
@@ -44,6 +72,9 @@ export type ReplayRecord = {
4472
*/
4573
duration: Duration;
4674
environment: null | string;
75+
/**
76+
* The IDs of the errors associated with the replay.
77+
*/
4778
error_ids: string[];
4879
/**
4980
* The **latest** timestamp received as determined by the SDK.
@@ -57,6 +88,10 @@ export type ReplayRecord = {
5788
* The ID of the Replay instance
5889
*/
5990
id: string;
91+
/**
92+
* The IDs of the infos associated with the replay.
93+
*/
94+
info_ids: string[];
6095
/**
6196
* Whether the replay was deleted.
6297
* When deleted the rrweb data & attachments are removed from blob storage,
@@ -67,9 +102,15 @@ export type ReplayRecord = {
67102
name: null | string;
68103
version: null | string;
69104
};
105+
ota_updates: {
106+
channel: string;
107+
runtime_version: string;
108+
update_id: string;
109+
};
70110
platform: string;
71111
project_id: string;
72112
releases: null | string[];
113+
replay_type: 'buffer' | 'session';
73114
sdk: {
74115
name: null | string;
75116
version: null | string;
@@ -89,14 +130,7 @@ export type ReplayRecord = {
89130
username: null | string;
90131
geo?: Geo;
91132
};
92-
/**
93-
* The number of dead clicks associated with the replay.
94-
*/
95-
count_dead_clicks?: number;
96-
/**
97-
* The number of rage clicks associated with the replay.
98-
*/
99-
count_rage_clicks?: number;
133+
warning_ids: string[];
100134
};
101135

102136
// The ReplayRecord fields, but with nested fields represented as `foo.bar`.
@@ -152,18 +186,37 @@ export type ReplayListRecord = Pick<
152186
ReplayRecord,
153187
| 'activity'
154188
| 'browser'
189+
| 'clicks'
155190
| 'count_dead_clicks'
156191
| 'count_errors'
192+
| 'count_infos'
157193
| 'count_rage_clicks'
194+
| 'count_segments'
195+
| 'count_urls'
196+
| 'count_warnings'
197+
| 'device'
198+
| 'dist'
158199
| 'duration'
200+
| 'environment'
201+
| 'error_ids'
159202
| 'finished_at'
160203
| 'has_viewed'
161204
| 'id'
205+
| 'info_ids'
162206
| 'is_archived'
163207
| 'os'
208+
| 'ota_updates'
209+
| 'platform'
164210
| 'project_id'
211+
| 'releases'
212+
| 'replay_type'
213+
| 'sdk'
165214
| 'started_at'
215+
| 'tags'
216+
| 'trace_ids'
217+
| 'urls'
166218
| 'user'
219+
| 'warning_ids'
167220
>;
168221

169222
/**

tests/js/fixtures/replayList.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,24 @@ export function ReplayListFixture(
1515
name: 'Firefox',
1616
version: '111.0',
1717
},
18+
clicks: [],
1819
count_dead_clicks: 0,
19-
count_rage_clicks: 0,
2020
count_errors: 0,
21+
count_infos: 0,
22+
count_rage_clicks: 0,
23+
count_segments: 0,
24+
count_urls: 0,
25+
count_warnings: 0,
26+
device: {
27+
brand: 'Firefox',
28+
family: 'Firefox',
29+
model_id: '111.0',
30+
name: 'Firefox',
31+
},
32+
dist: '111.0',
33+
environment: 'production',
34+
error_ids: [],
35+
info_ids: [],
2136
duration: duration(30000),
2237
finished_at: new Date('2022-09-15T06:54:00+00:00'),
2338
has_viewed: false,
@@ -27,8 +42,24 @@ export function ReplayListFixture(
2742
name: 'sentry.javascript.react',
2843
version: '7.42.0',
2944
},
45+
ota_updates: {
46+
channel: 'stable',
47+
runtime_version: '111.0',
48+
update_id: '1234567890',
49+
},
50+
platform: 'javascript',
3051
project_id: '2',
52+
releases: [],
53+
replay_type: 'buffer',
54+
sdk: {
55+
name: 'sentry.javascript.react',
56+
version: '7.42.0',
57+
},
3158
started_at: new Date('2022-09-15T06:50:03+00:00'),
59+
tags: {},
60+
trace_ids: [],
61+
urls: [],
62+
warning_ids: [],
3263
user: {
3364
display_name: 'testDisplayName',
3465
email: '',

tests/js/fixtures/replayRecord.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,18 @@ export function ReplayRecordFixture(
77
): ReplayRecord {
88
return {
99
activity: 0,
10+
clicks: [],
1011
browser: {
1112
name: 'Other',
1213
version: '',
1314
},
1415
count_dead_clicks: 1,
15-
count_rage_clicks: 1,
1616
count_errors: 1,
17+
count_infos: 1,
18+
count_rage_clicks: 1,
1719
count_segments: 14,
1820
count_urls: 1,
21+
count_warnings: 1,
1922
device: {
2023
name: '',
2124
brand: '',
@@ -29,14 +32,21 @@ export function ReplayRecordFixture(
2932
finished_at: new Date('Sep 22, 2022 5:00:03 PM UTC'),
3033
has_viewed: false,
3134
id: '761104e184c64d439ee1014b72b4d83b',
35+
info_ids: [],
3236
is_archived: false,
3337
os: {
3438
name: 'Other',
3539
version: '',
3640
},
41+
ota_updates: {
42+
channel: 'stable',
43+
runtime_version: '1.0.0',
44+
update_id: '1234567890',
45+
},
3746
platform: 'javascript',
3847
project_id: '6273278',
3948
releases: ['1.0.0', '2.0.0'],
49+
replay_type: 'buffer',
4050
sdk: {
4151
name: 'sentry.javascript.browser',
4252
version: '7.1.1',
@@ -51,6 +61,7 @@ export function ReplayRecordFixture(
5161
ip: '127.0.0.1',
5262
display_name: '127.0.0.1',
5363
},
64+
warning_ids: [],
5465
...replayRecord,
5566
tags: {
5667
...replayRecord.tags,
@@ -60,6 +71,7 @@ export function ReplayRecordFixture(
6071
'os.name': [replayRecord.os?.name ?? 'Other'],
6172
platform: [replayRecord.platform ?? 'javascript'],
6273
releases: replayRecord.releases ?? ['1.0.0', '2.0.0'],
74+
replayType: ['buffer'],
6375
'sdk.name': [replayRecord.sdk?.name ?? 'sentry.javascript.browser'],
6476
'sdk.version': [replayRecord.sdk?.version ?? '7.1.1'],
6577
'user.ip': [replayRecord.user?.ip ?? '127.0.0.1'],

0 commit comments

Comments
 (0)