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