@@ -131,14 +131,12 @@ def test_streaming(
131131 }
132132 if send_default_pii :
133133 expected_attrs ["url.full" ] = "https://bucket.s3.amazonaws.com/foo.pdf"
134- expected_attrs ["url.fragment" ] = ""
135- expected_attrs ["url.query" ] = ""
136134 assert span1 ["attributes" ] == ApproxDict (expected_attrs )
137135
136+ assert "url.fragment" not in span1 ["attributes" ]
137+ assert "url.query" not in span1 ["attributes" ]
138138 if not send_default_pii :
139139 assert "url.full" not in span1 ["attributes" ]
140- assert "url.fragment" not in span1 ["attributes" ]
141- assert "url.query" not in span1 ["attributes" ]
142140
143141 span2 = spans [1 ]
144142 assert span2 ["attributes" ]["sentry.op" ] == "http.client.stream"
@@ -426,9 +424,9 @@ def test_breadcrumb_span_streaming(sentry_init, capture_events, send_default_pii
426424 SPANDATA .URL_FULL : mock .ANY ,
427425 SPANDATA .HTTP_REQUEST_METHOD : "GET" ,
428426 SPANDATA .URL_QUERY : mock .ANY ,
429- SPANDATA .URL_FRAGMENT : "" ,
430427 }
431428 )
429+ assert SPANDATA .URL_FRAGMENT not in crumb ["data" ]
432430 else :
433431 assert crumb ["data" ] == ApproxDict (
434432 {
@@ -438,3 +436,159 @@ def test_breadcrumb_span_streaming(sentry_init, capture_events, send_default_pii
438436 assert SPANDATA .URL_FULL not in crumb ["data" ]
439437 assert SPANDATA .URL_QUERY not in crumb ["data" ]
440438 assert SPANDATA .URL_FRAGMENT not in crumb ["data" ]
439+
440+
441+ BUCKET_URL = "https://bucket.s3.amazonaws.com/"
442+
443+ # ``expected_query`` of ``None`` means no URL data is recorded at all; ``""``
444+ # means the URL is recorded without a query string.
445+ # Structure of the parameters is "init_kwargs, expected_query"
446+ URL_QUERY_PARAMS = [
447+ pytest .param (
448+ {"send_default_pii" : True },
449+ "list-type=2&prefix=foo&continuation-token=abc&encoding-type=url" ,
450+ id = "send_default_pii_true" ,
451+ ),
452+ pytest .param (
453+ {"send_default_pii" : False },
454+ None ,
455+ id = "send_default_pii_false" ,
456+ ),
457+ pytest .param (
458+ {},
459+ None ,
460+ id = "defaults" ,
461+ ),
462+ pytest .param (
463+ {"_experiments" : {"data_collection" : {}}},
464+ "list-type=2&prefix=foo&continuation-token=%5BFiltered%5D&encoding-type=url" ,
465+ id = "data_collection_denylist_default" ,
466+ ),
467+ pytest .param (
468+ {
469+ "_experiments" : {
470+ "data_collection" : {
471+ "url_query_params" : {"mode" : "denylist" , "terms" : ["prefix" ]}
472+ }
473+ }
474+ },
475+ "list-type=2&prefix=%5BFiltered%5D&continuation-token=%5BFiltered%5D&encoding-type=url" ,
476+ id = "data_collection_denylist_custom_terms" ,
477+ ),
478+ pytest .param (
479+ {
480+ "_experiments" : {
481+ "data_collection" : {
482+ "url_query_params" : {"mode" : "allowlist" , "terms" : ["prefix" ]}
483+ }
484+ }
485+ },
486+ "list-type=%5BFiltered%5D&prefix=foo&continuation-token=%5BFiltered%5D&encoding-type=%5BFiltered%5D" ,
487+ id = "data_collection_allowlist" ,
488+ ),
489+ pytest .param (
490+ {
491+ "_experiments" : {
492+ "data_collection" : {
493+ "url_query_params" : {
494+ "mode" : "allowlist" ,
495+ "terms" : ["continuation-token" ],
496+ }
497+ }
498+ }
499+ },
500+ "list-type=%5BFiltered%5D&prefix=%5BFiltered%5D&continuation-token=%5BFiltered%5D&encoding-type=%5BFiltered%5D" ,
501+ id = "data_collection_allowlist_sensitive_term" ,
502+ ),
503+ pytest .param (
504+ {"_experiments" : {"data_collection" : {"url_query_params" : {"mode" : "off" }}}},
505+ "" ,
506+ id = "data_collection_off" ,
507+ ),
508+ pytest .param (
509+ {
510+ "send_default_pii" : True ,
511+ "_experiments" : {"data_collection" : {"url_query_params" : {"mode" : "off" }}},
512+ },
513+ "" ,
514+ id = "data_collection_wins_over_send_default_pii" ,
515+ ),
516+ ]
517+
518+
519+ @pytest .mark .parametrize ("init_kwargs, expected_query" , URL_QUERY_PARAMS )
520+ def test_url_query_data_collection_span_streaming (
521+ sentry_init , capture_items , init_kwargs , expected_query
522+ ):
523+ sentry_init (
524+ traces_sample_rate = 1.0 ,
525+ integrations = [Boto3Integration ()],
526+ default_integrations = False ,
527+ trace_lifecycle = "stream" ,
528+ ** init_kwargs ,
529+ )
530+
531+ client = session .client ("s3" )
532+
533+ items = capture_items ("span" )
534+
535+ with sentry_sdk .traces .start_span (name = "custom parent" ), MockResponse (
536+ client , 200 , {}, read_fixture ("s3_list.xml" )
537+ ):
538+ client .list_objects_v2 (Bucket = "bucket" , Prefix = "foo" , ContinuationToken = "abc" )
539+
540+ sentry_sdk .flush ()
541+
542+ (span ,) = [
543+ item .payload
544+ for item in items
545+ if item .payload ["attributes" ].get ("sentry.op" ) == "http.client"
546+ ]
547+
548+ if expected_query is None :
549+ assert SPANDATA .URL_QUERY not in span ["attributes" ]
550+ assert SPANDATA .URL_FULL not in span ["attributes" ]
551+ elif expected_query == "" :
552+ assert SPANDATA .URL_QUERY not in span ["attributes" ]
553+ assert span ["attributes" ][SPANDATA .URL_FULL ] == BUCKET_URL
554+ else :
555+ assert span ["attributes" ][SPANDATA .URL_QUERY ] == expected_query
556+ assert (
557+ span ["attributes" ][SPANDATA .URL_FULL ] == BUCKET_URL + "?" + expected_query
558+ )
559+
560+
561+ @pytest .mark .parametrize ("init_kwargs, expected_query" , URL_QUERY_PARAMS )
562+ def test_url_query_data_collection_breadcrumb (
563+ sentry_init , capture_events , init_kwargs , expected_query
564+ ):
565+ sentry_init (
566+ integrations = [Boto3Integration ()],
567+ default_integrations = False ,
568+ trace_lifecycle = "stream" ,
569+ ** init_kwargs ,
570+ )
571+
572+ client = session .client ("s3" )
573+
574+ events = capture_events ()
575+
576+ with sentry_sdk .traces .start_span (name = "custom parent" ), MockResponse (
577+ client , 200 , {}, read_fixture ("s3_list.xml" )
578+ ):
579+ client .list_objects_v2 (Bucket = "bucket" , Prefix = "foo" , ContinuationToken = "abc" )
580+
581+ capture_message ("Testing!" )
582+
583+ (event ,) = events
584+ (crumb ,) = event ["breadcrumbs" ]["values" ]
585+
586+ if expected_query is None :
587+ assert SPANDATA .URL_QUERY not in crumb ["data" ]
588+ assert SPANDATA .URL_FULL not in crumb ["data" ]
589+ elif expected_query == "" :
590+ assert SPANDATA .URL_QUERY not in crumb ["data" ]
591+ assert crumb ["data" ][SPANDATA .URL_FULL ] == BUCKET_URL
592+ else :
593+ assert crumb ["data" ][SPANDATA .URL_QUERY ] == expected_query
594+ assert crumb ["data" ][SPANDATA .URL_FULL ] == BUCKET_URL + "?" + expected_query
0 commit comments