Skip to content

Commit 737f69f

Browse files
authored
feat(cloudflare): Migrate to dataCollection (#21237)
Migrates the Cloudflare SDK from `sendDefaultPii` to the new `dataCollection` spec, **without changing default behavior** (the breaking default flips are deferred to v11). - **`request.ts`**: Pass `client.getDataCollectionOptions()` to `httpHeadersToSpanAttributes` instead of the `sendDefaultPii` boolean. Header/cookie filtering is now driven by the resolved `dataCollection`. - **`sdk.ts`**: `requestDataIntegration` is configured from `dataCollection`, but cookies are kept **off by default** (Cloudflare's historical behavior) unless the user opts in via `sendDefaultPii` or `dataCollection.cookies`. Marked `TODO(v11)` to drop this gate and let cookies default on (denylist-filtered) per spec (#21260). - **`httpServer.ts`**: `maxRequestBodySize` continues to default to `'medium'` (bodies captured by default, matching the Node SDK and pre-migration behavior). Marked `TODO(v11)` to gate body capture on `dataCollection.httpBodies` (#21258). Fixes #20934
1 parent c78c8b8 commit 737f69f

4 files changed

Lines changed: 87 additions & 4 deletions

File tree

packages/cloudflare/src/integrations/httpServer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ export async function captureIncomingRequestBody(client: Client, request: Reques
8585
return;
8686
}
8787

88+
// TODO(v11): Gate incoming request body capture on `dataCollection.httpBodies` (capture only when
89+
// `'incomingRequest'` is listed) instead of defaulting to `'medium'`.
8890
const maxRequestBodySize = integration.maxRequestBodySize;
8991

9092
if (maxRequestBodySize === 'none') {

packages/cloudflare/src/request.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export function wrapRequestHandler(
7474
attributes,
7575
httpHeadersToSpanAttributes(
7676
winterCGHeadersToDict(request.headers),
77-
getClient()?.getOptions().sendDefaultPii ?? false,
77+
getClient()?.getDataCollectionOptions() ?? false,
7878
),
7979
);
8080

packages/cloudflare/src/sdk.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ import { defaultStackParser } from './vendor/stacktrace';
2424

2525
/** Get the default integrations for the Cloudflare SDK. */
2626
export function getDefaultIntegrations(options: CloudflareOptions): Integration[] {
27-
const sendDefaultPii = options.sendDefaultPii ?? false;
27+
// TODO(v11): Drop this transitional gating and let `requestDataIntegration` rely on the resolved
28+
// `dataCollection` defaults directly. Until then, preserve the historical Cloudflare behavior of not
29+
// attaching cookies unless the user explicitly opts in via `sendDefaultPii` or `dataCollection.cookies`.
30+
const cookiesEnabled = options.sendDefaultPii || options.dataCollection?.cookies != null;
2831
return [
2932
// The Dedupe integration should not be used in workflows because we want to
3033
// capture all step failures, even if they are the same error.
@@ -38,8 +41,7 @@ export function getDefaultIntegrations(options: CloudflareOptions): Integration[
3841
fetchIntegration(),
3942
honoIntegration(),
4043
httpServerIntegration(),
41-
// TODO(v11): the `include` object should be defined directly in the integration based on `sendDefaultPii`
42-
requestDataIntegration(sendDefaultPii ? undefined : { include: { cookies: false } }),
44+
requestDataIntegration(cookiesEnabled ? undefined : { include: { cookies: false } }),
4345
consoleIntegration(),
4446
];
4547
}

packages/cloudflare/test/request.test.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,9 @@ describe('withSentry', () => {
205205
expect(sentryEvent.contexts?.culture).toEqual({ timezone: 'UTC' });
206206
});
207207

208+
// TODO(v11): Body capture should be gated on `dataCollection.httpBodies` (only capture when
209+
// `'incomingRequest'` is listed). Until then we keep the historical behavior of capturing
210+
// incoming request bodies by default at `'medium'`, consistent with the Node SDK.
208211
test('captures request body with default integration (medium size)', async () => {
209212
let sentryEvent: Event = {};
210213
const context = createMockExecutionContext();
@@ -237,6 +240,82 @@ describe('withSentry', () => {
237240
);
238241
});
239242

243+
// TODO(v11): Cookies should be attached (subject to denylist filtering) by default. Until then we keep the
244+
// historical Cloudflare behavior of not attaching cookies unless the user explicitly opts in.
245+
test('does not capture cookies by default', async () => {
246+
let sentryEvent: Event = {};
247+
248+
await wrapRequestHandler(
249+
{
250+
options: {
251+
...MOCK_OPTIONS,
252+
beforeSend(event) {
253+
sentryEvent = event;
254+
return null;
255+
},
256+
},
257+
request: new Request('https://example.com', { headers: { cookie: 'foo=bar' } }),
258+
context: createMockExecutionContext(),
259+
},
260+
() => {
261+
SentryCore.captureMessage('cookies');
262+
return new Response('test');
263+
},
264+
);
265+
266+
expect(sentryEvent.request?.cookies).toBeUndefined();
267+
});
268+
269+
test('captures cookies when dataCollection.cookies is enabled', async () => {
270+
let sentryEvent: Event = {};
271+
272+
await wrapRequestHandler(
273+
{
274+
options: {
275+
...MOCK_OPTIONS,
276+
dataCollection: { cookies: true },
277+
beforeSend(event) {
278+
sentryEvent = event;
279+
return null;
280+
},
281+
},
282+
request: new Request('https://example.com', { headers: { cookie: 'foo=bar' } }),
283+
context: createMockExecutionContext(),
284+
},
285+
() => {
286+
SentryCore.captureMessage('cookies');
287+
return new Response('test');
288+
},
289+
);
290+
291+
expect(sentryEvent.request?.cookies).toEqual({ foo: 'bar' });
292+
});
293+
294+
test('captures cookies when sendDefaultPii is enabled', async () => {
295+
let sentryEvent: Event = {};
296+
297+
await wrapRequestHandler(
298+
{
299+
options: {
300+
...MOCK_OPTIONS,
301+
sendDefaultPii: true,
302+
beforeSend(event) {
303+
sentryEvent = event;
304+
return null;
305+
},
306+
},
307+
request: new Request('https://example.com', { headers: { cookie: 'foo=bar' } }),
308+
context: createMockExecutionContext(),
309+
},
310+
() => {
311+
SentryCore.captureMessage('cookies');
312+
return new Response('test');
313+
},
314+
);
315+
316+
expect(sentryEvent.request?.cookies).toEqual({ foo: 'bar' });
317+
});
318+
240319
test('does not capture request body for GET requests', async () => {
241320
let sentryEvent: Event = {};
242321
const context = createMockExecutionContext();

0 commit comments

Comments
 (0)