fix: sanitize span events and links, not just span attributes - #56
Merged
Merged
Conversation
MaskingSpanExporter read span.attributes alone, so content in event attributes (OTel GenAI's event-based shape), link attributes, and record_exception's provider-echoed error strings exported verbatim under capture_content=False or a mask. - content keys in event and link attributes now go through the same strip/mask machinery as span attributes - exception events: capture_content=False drops exception.message and exception.stacktrace but keeps the event and exception.type, so failures stay visible and classifiable (TypeScript SDK policy); a mask is applied to both keys - six new tests pin events, links, the exception pair on both paths, and the untouched pass-through
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 the RIUS-380 privacy gap:
MaskingSpanExporter._sanitized()readspan.attributesand nothing else, so content in event attributes, link attributes, andrecord_exception's provider-echoed error strings exported verbatim even undercapture_content=Falseor amask. Route 1 needs no unusual instrumentation: any provider 400 that echoes the rejected request produces an exception event carrying the user's prompt.Changes
_sanitize_mapping()extracted from the attributes path and applied uniformly tospan.attributes,span.events[].attributes, andspan.links[].attributeson both the strip and mask paths. Unchanged collections are returned as-is (no copies on the no-op path).capture_content=False,exception.messageandexception.stacktraceare dropped while the exception event andexception.typestay, so failures remain visible and classifiable.capture_content=Falseonly; for themaskpath I chose to apply the mask toexception.message/exception.stacktraceas well, because a PII scrubber that skips provider-echoed prompts in error strings re-creates exactly this bug for mask users. If the TS implementation decided otherwise, flag it and I'll align.Tests
Six new tests pinning the boundary, not the collection: content in event attributes (strip + mask), content in link attributes, the exception pair under both paths, and the pass-through case (capture on, no mask) proving events stay untouched. Per the ticket's closing note, the existing tests all asserted on
span.attributesand shared the defect's blind spot; these are the first to assert on events and links.Suite: 205 passed; ruff, format, mypy strict clean.
RIUS-380