Repository navigation
ref: add the DataCollection resolver and SendDefaultPii bridge - #5885
Merged
Merged
Conversation
Integrations will read their data collection policy from DataCollectionResolver rather than from SendDefaultPii or DataCollection directly. Resolution is lazy, since SentryOptions stays mutable after Init, and falls back to SendDefaultPii while DataCollection is null. No consumer migrated yet, so this is behaviour-neutral. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5885 +/- ##
==========================================
+ Coverage 76.77% 76.81% +0.03%
==========================================
Files 532 533 +1
Lines 19826 19850 +24
Branches 3909 3920 +11
==========================================
+ Hits 15222 15248 +26
+ Misses 3718 3717 -1
+ Partials 886 885 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
ric-oliv
reviewed
Nov 8, 2026
This was referenced Nov 8, 2026
…lver tests Incoming request bodies have never been gated on SendDefaultPii: RequestBodyExtractionDispatcher switches on RequestSize alone, and both ASP.NET Core and AddAspNet call it unconditionally. That direction now falls back to true, so #5430 cannot cost an app that set MaxRequestBodySize its request bodies. Tests configure one body direction at a time, and leave UserInfo at its default where DatabaseQueryData is the subject, so that reading the wrong category fails. Docs say what is true today: until the integrations migrate, SendDefaultPii still decides what they collect, and setting a category - not only restricting one - has no effect yet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
4 of 20 tasks
ric-oliv
reviewed
Nov 9, 2026
The test and the PR description already carry the reasoning, and src/ aims for no comments. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #5426
Adds
DataCollectionResolver, the single read path integrations will use for data collection policy, and theSendDefaultPiibridge behind it. Nothing reads it yet — each call site moves over in its own Phase 2 issue — so this is behaviour-neutral.Resolution is the two-step rule from the resolution-model comment, now that #5853 made every category non-nullable:
options.DataCollectionisnull(nobody calledConfigureDataCollection, nothing bound from configuration) → derive each category fromSendDefaultPii; otherwise read the object and ignoreSendDefaultPii.Decisions this settles
Lazy, not resolve-once.
SentryOptionsstays mutable afterInitand tests mutate it, so a snapshot taken at init would silently ignore later edits. The resolver holds the options and recomputes per query, likeio.sentry.DataCollectionResolver. Cost is a null check and a field read; the two defaultKeyValueCollectionBehaviorinstances are cached statics, which is safe now that #5853 made them immutable.The
SendDefaultPii = falsebridge does not extend deny lists with the GDPR terms, contrary to the issue text, which came from the JS bridge. The .NET SDK has never filteredX-Forwarded-Forand friends, so adding those terms here would make the Phase 2 header migration ship a behaviour change inside a refactor. Headers and query params therefore resolve to a plainDenyList()either way, and cookies toOffwhenSendDefaultPiiis false. This matches what sentry-java's resolver actually does (explicitOrEmptyDenyList, andoff()for cookies), as opposed to what the spec prescribes for a from-scratch SDK. Turning the terms on by default for legacy users stays available as a deliberate change in #5422.That also makes the
KeyValueCollectionBehavior.DenyListdoc wrong where it says those terms "restore the header filtering thatSendDefaultPiiapplied when disabled" — there was none to restore. Reworded to present them as the terms the spec names for filtering end-user-identifying keys.The legacy gate is per call site, not per category. The global fallbacks above are faithful to the server-side capture path, where
SendDefaultPii = falseskips only theCookieheader and collects every other header and the query string regardless (ScopeExtensions.cs:140,SystemWebRequestEventProcessor.cs:62). The client-side handlers are all-or-nothing on headers instead:SentryHttpFailedRequestHandlerandSentryGraphQLHttpFailedRequestHandlerattach no request or response headers and neither cookie set when it is off. Migrating those onto the globalRequestHeaders/ResponseHeaderswould start sending that data forSendDefaultPii = falseapps, so each needs a sibling accessor falling back toSendDefaultPii ? DenyList : Off— the shape cookies already have — landing with its consumer, as sentry-java does withisGraphqlDocumentWithLegacyBodyGate().Request.Urlis not one of them, andUrlQueryParamsneeds no gated variant.HttpRequestUrl()keeps the query string — what it drops isuser:pass@and the fragment — so the query reaches Sentry whichever waySendDefaultPiiis set, inRequest.Urland in the unconditionally-setRequest.QueryString. Both handlers pinhttp://localhost/test/path?query=stringwith PII off (SentryHttpFailedRequestHandlerTests.cs:238,SentryGraphQlHttpFailedRequestHandlerTests.cs:150), which a gated accessor resolving toOffwould break. So the global accessor applies to both fields, and what the URL gate really decides — whether credentials and the fragment are sent — is no DataCollection category at all:RedactUrlis the SDK's answer to credentials in URLs but never runs onRequest.Url. Left to #5429 as its own call. Noted on #5429 and #5432 with the per-field detail. Thanks @ric-oliv for both catches.HTTP bodies resolve per direction (
IncomingRequestBody,OutgoingRequestBody, …) rather than exposingHttpBodyTypes, because that is what a call site needs and because the legacy gate differs per direction:OutgoingRequestBody/IncomingResponseBodyfall back toSendDefaultPii, which is what gates them today (SentryGraphQLHttpFailedRequestHandler.cs:74and:78).IncomingRequestBodyfalls back totrue.MaxRequestBodySizehas always been its only gate, in both ASP.NET Core andAddAspNet—RequestBodyExtractionDispatcherswitches onRequestSizeand never readsSendDefaultPii— so aSendDefaultPiifallback would cost an app that setMaxRequestBodySizeits request bodies once DataCollection phase 2: migrate Sentry.AspNetCore #5430 lands.OutgoingResponseBodyhas no consumer today, so there is no behaviour to preserve; it followsSendDefaultPiias the conservative default.GenAI content follows
SendDefaultPii, and that is a deliberate change for #5434 to ship visibly.Sentry.Extensions.AInever readsSendDefaultPii, andRecordInputs/RecordOutputsdefault totrue, so a default app records prompts and completions today. Gating them is what the spec and the other SDKs do, andSendDefaultPii = falsefailing to suppress the most PII-dense data the SDK collects is the anomaly — but it is user-visible, so it belongs in #5434 with a changelog entry rather than arriving inside a refactor. Noted there.Docs
The XML docs said these options were inert. That stays true until Phase 2 migrates the first consumer, so rather than deleting the caveats as the issue note suggested, they now name the real state:
ConfigureDataCollectionscopes theSendDefaultPiireplacement to the integrations that have moved over, and the caveat says that until they do,SendDefaultPiistill decides what they collect and setting a category has no effect. The caveat goes away for real as Phase 2 lands.No public API change, so no approval-snapshot churn.
#skip-changelog
🤖 Generated with Claude Code