Skip to content

Commit 51b7326

Browse files
scttcperharshithadurai
authored andcommitted
fix(issues): Avoid destructuring null in event data (#81166)
1 parent 5775264 commit 51b7326

File tree

4 files changed

+59
-16
lines changed

4 files changed

+59
-16
lines changed

static/app/components/events/interfaces/request/index.spec.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
import {DataScrubbingRelayPiiConfigFixture} from 'sentry-fixture/dataScrubbingRelayPiiConfig';
22
import {EventFixture} from 'sentry-fixture/event';
3+
import {UserFixture} from 'sentry-fixture/user';
34

45
import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
56
import {textWithMarkupMatcher} from 'sentry-test/utils';
67

78
import {Request} from 'sentry/components/events/interfaces/request';
9+
import ConfigStore from 'sentry/stores/configStore';
810
import type {EntryRequest} from 'sentry/types/event';
911
import {EntryType} from 'sentry/types/event';
1012

1113
jest.unmock('prismjs');
1214

1315
describe('Request entry', function () {
16+
beforeEach(() => {
17+
ConfigStore.set('user', UserFixture());
18+
});
19+
1420
it('display redacted data', async function () {
1521
const event = EventFixture({
1622
entries: [
@@ -327,6 +333,38 @@ describe('Request entry', function () {
327333
).not.toThrow();
328334
});
329335

336+
it('should remove any non-tuple values from array', function () {
337+
const user = UserFixture();
338+
user.options.prefersIssueDetailsStreamlinedUI = true;
339+
ConfigStore.set('user', user);
340+
341+
const data: EntryRequest['data'] = {
342+
apiTarget: null,
343+
query: 'a%AFc',
344+
data: '',
345+
headers: [['foo', 'bar'], null],
346+
cookies: [],
347+
env: {},
348+
method: 'POST',
349+
url: '/Home/PostIndex',
350+
};
351+
const event = EventFixture({
352+
entries: [
353+
{
354+
type: EntryType.REQUEST,
355+
data,
356+
},
357+
],
358+
});
359+
expect(() =>
360+
render(<Request event={event} data={event.entries[0].data} />, {
361+
organization: {
362+
relayPiiConfig: JSON.stringify(DataScrubbingRelayPiiConfigFixture()),
363+
},
364+
})
365+
).not.toThrow();
366+
});
367+
330368
it("should not cause an invariant violation if data.data isn't a string", function () {
331369
const data: EntryRequest['data'] = {
332370
apiTarget: null,

static/app/components/events/interfaces/request/index.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -251,10 +251,13 @@ function RequestDataCard({
251251
const contentItems: KeyValueDataContentProps[] = [];
252252

253253
if (Array.isArray(data) && data.length > 0) {
254-
data.forEach(([key, value], i: number) => {
255-
const valueMeta = meta?.[i] ? meta[i]?.[1] : undefined;
256-
contentItems.push({item: {key, subject: key, value}, meta: valueMeta});
257-
});
254+
data
255+
// Remove any non-tuple values
256+
.filter(x => Array.isArray(x))
257+
.forEach(([key, value], i: number) => {
258+
const valueMeta = meta?.[i] ? meta[i]?.[1] : undefined;
259+
contentItems.push({item: {key, subject: key, value}, meta: valueMeta});
260+
});
258261
} else if (typeof data === 'object') {
259262
// Spread to flatten if it's a proxy
260263
Object.entries({...data}).forEach(([key, value]) => {

static/app/components/events/interfaces/utils.tsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,22 +125,22 @@ export function getCurlCommand(data: EntryRequest['data']) {
125125
result += ' \\\n -X ' + data.method;
126126
}
127127

128-
data.headers = data.headers?.filter(defined);
128+
const headers =
129+
data.headers
130+
?.filter(defined)
131+
// sort headers
132+
.sort(function (a, b) {
133+
return a[0] === b[0] ? 0 : a[0] < b[0] ? -1 : 1;
134+
}) ?? [];
129135

130136
// TODO(benvinegar): just gzip? what about deflate?
131-
const compressed = data.headers?.find(
137+
const compressed = headers?.find(
132138
h => h[0] === 'Accept-Encoding' && h[1].includes('gzip')
133139
);
134140
if (compressed) {
135141
result += ' \\\n --compressed';
136142
}
137143

138-
// sort headers
139-
const headers =
140-
data.headers?.sort(function (a, b) {
141-
return a[0] === b[0] ? 0 : a[0] < b[0] ? -1 : 1;
142-
}) ?? [];
143-
144144
for (const header of headers) {
145145
result += ' \\\n -H "' + header[0] + ': ' + escapeBashString(header[1] + '') + '"';
146146
}
@@ -172,7 +172,9 @@ export function getCurlCommand(data: EntryRequest['data']) {
172172
return result;
173173
}
174174

175-
export function stringifyQueryList(query: string | [key: string, value: string][]) {
175+
export function stringifyQueryList(
176+
query: string | Array<[key: string, value: string] | null>
177+
) {
176178
if (typeof query === 'string') {
177179
return query;
178180
}

static/app/types/event.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,17 +336,17 @@ export interface EntryRequestDataDefault {
336336
apiTarget: null;
337337
method: string;
338338
url: string;
339-
cookies?: [key: string, value: string][];
339+
cookies?: Array<[key: string, value: string] | null>;
340340
data?: string | null | Record<string, any> | [key: string, value: any][];
341341
env?: Record<string, string>;
342342
fragment?: string | null;
343-
headers?: [key: string, value: string][];
343+
headers?: Array<[key: string, value: string] | null>;
344344
inferredContentType?:
345345
| null
346346
| 'application/json'
347347
| 'application/x-www-form-urlencoded'
348348
| 'multipart/form-data';
349-
query?: [key: string, value: string][] | string;
349+
query?: Array<[key: string, value: string] | null> | string;
350350
}
351351

352352
export interface EntryRequestDataGraphQl

0 commit comments

Comments
 (0)