55
66from rest_framework .request import Request
77from rest_framework .response import Response
8+ from sentry_protos .snuba .v1 .endpoint_trace_item_attributes_pb2 import TraceItemAttributeNamesRequest
89from sentry_protos .snuba .v1 .endpoint_trace_item_stats_pb2 import (
910 AttributeDistributionsRequest ,
1011 StatsType ,
1112 TraceItemStatsRequest ,
1213)
14+ from sentry_protos .snuba .v1 .trace_item_attribute_pb2 import AttributeKey
1315
1416from sentry import features
1517from sentry .api .api_owners import ApiOwner
2729from sentry .seer .workflows .compare import keyed_rrf_score
2830from sentry .snuba .referrer import Referrer
2931from sentry .snuba .spans_rpc import Spans
30- from sentry .utils .snuba_rpc import trace_item_stats_rpc
32+ from sentry .utils .snuba_rpc import attribute_names_rpc , trace_item_stats_rpc
3133
3234logger = logging .getLogger (__name__ )
3335
@@ -120,6 +122,20 @@ def get(self, request: Request, organization: Organization) -> Response:
120122 if query_1 == query_2 :
121123 return Response ({"rankedAttributes" : []})
122124
125+ # First, fetch attribute names to use as an allowlist
126+ attribute_names_request = TraceItemAttributeNamesRequest (
127+ meta = meta ,
128+ type = AttributeKey .Type .TYPE_STRING ,
129+ limit = 1000 ,
130+ )
131+ attribute_names_response = attribute_names_rpc (attribute_names_request )
132+
133+ allowed_attribute_names = {
134+ attr .name
135+ for attr in attribute_names_response .attributes
136+ if attr .name and can_expose_attribute (attr .name , SupportedTraceItemType .SPANS )
137+ }
138+
123139 cohort_1 , _ , _ = resolver .resolve_query (query_1 )
124140 cohort_1_request = TraceItemStatsRequest (
125141 filter = cohort_1 ,
@@ -199,7 +215,10 @@ def get(self, request: Request, organization: Organization) -> Response:
199215 processed_cohort_2_buckets = set ()
200216
201217 for attribute in cohort_2_data .results [0 ].attribute_distributions .attributes :
202- if not can_expose_attribute (attribute .attribute_name , SupportedTraceItemType .SPANS ):
218+ # Filter attributes to only those in the allowlist
219+ if attribute .attribute_name not in allowed_attribute_names or not can_expose_attribute (
220+ attribute .attribute_name , SupportedTraceItemType .SPANS
221+ ):
203222 continue
204223
205224 for bucket in attribute .buckets :
@@ -208,7 +227,10 @@ def get(self, request: Request, organization: Organization) -> Response:
208227 )
209228
210229 for attribute in cohort_1_data .results [0 ].attribute_distributions .attributes :
211- if not can_expose_attribute (attribute .attribute_name , SupportedTraceItemType .SPANS ):
230+ # Filter attributes to only those in the allowlist
231+ if attribute .attribute_name not in allowed_attribute_names or not can_expose_attribute (
232+ attribute .attribute_name , SupportedTraceItemType .SPANS
233+ ):
212234 continue
213235 for bucket in attribute .buckets :
214236 cohort_1_distribution .append ((attribute .attribute_name , bucket .label , bucket .value ))
0 commit comments