@@ -1239,7 +1239,7 @@ class ProductTabVulnerabilitiesView(
12391239 ),
12401240 Header (
12411241 "triage_action" ,
1242- _ ("Recommended action " ),
1242+ _ ("Recommendation " ),
12431243 help_text = _ ("Action recommended by the triage engine for this vulnerability" ),
12441244 filter = "triage_action" ,
12451245 ),
@@ -1275,6 +1275,94 @@ class ProductTabVulnerabilitiesView(
12751275 ),
12761276 )
12771277
1278+ def attach_vulnerability_analyses (self , page_obj ):
1279+ """Set the matching VulnerabilityAnalysis instance on each prefetched vulnerability."""
1280+ for product_package in page_obj .object_list :
1281+ for vulnerability in product_package .package .affected_by_vulnerabilities .all ():
1282+ for analysis in vulnerability .vulnerability_analyses .all ():
1283+ if analysis .product_package_id == product_package .id :
1284+ vulnerability .vulnerability_analysis = analysis
1285+ continue
1286+
1287+ REACHABILITY_FILTER_MAP = {"yes" : True , "no" : False , "unknown" : None }
1288+
1289+ def get_vulnerability_display_filters (self ):
1290+ """Return the active per-vulnerability filters from the request."""
1291+ params = self .request .GET
1292+ prefix = self .tab_id
1293+ return {
1294+ "triage_action" : params .get (f"{ prefix } -triage_action" , "" ),
1295+ "state" : params .get (f"{ prefix } -vulnerability_analyses__state" , "" ),
1296+ "justification" : params .get (f"{ prefix } -vulnerability_analyses__justification" , "" ),
1297+ "is_reachable" : params .get (f"{ prefix } -is_reachable" , "" ),
1298+ }
1299+
1300+ def vulnerability_passes_display_filters (self , vulnerability , display_filters ):
1301+ """Return True if the vulnerability matches all active display filters."""
1302+ triage_action = display_filters .get ("triage_action" )
1303+ if triage_action :
1304+ record = getattr (vulnerability , "triage_record" , None )
1305+ if getattr (record , "action" , "" ) != triage_action :
1306+ return False
1307+ analysis = getattr (vulnerability , "vulnerability_analysis" , None )
1308+ state = display_filters .get ("state" )
1309+ if state :
1310+ if getattr (analysis , "state" , "" ) != state :
1311+ return False
1312+ justification = display_filters .get ("justification" )
1313+ if justification :
1314+ if getattr (analysis , "justification" , "" ) != justification :
1315+ return False
1316+ is_reachable_filter = display_filters .get ("is_reachable" )
1317+ if is_reachable_filter :
1318+ expected = self .REACHABILITY_FILTER_MAP [is_reachable_filter ]
1319+ if getattr (analysis , "is_reachable" , object ()) != expected :
1320+ return False
1321+ return True
1322+
1323+ def attach_triage_data (self , product , page_obj ):
1324+ """
1325+ Attach the winning TriageRecord to each vulnerability and build
1326+ display_vulnerabilities on each product_package, filtered by any
1327+ active per-vulnerability filters.
1328+ """
1329+ vulnerability_ids = {
1330+ vulnerability .id
1331+ for product_package in page_obj .object_list
1332+ for vulnerability in product_package .package .affected_by_vulnerabilities .all ()
1333+ }
1334+ action_labels = dict (TriageAction .choices )
1335+ triage_records = list (
1336+ TriageRecord .objects .filter (
1337+ product = product ,
1338+ vulnerability_id__in = vulnerability_ids ,
1339+ )
1340+ .primary_actions ()
1341+ .select_related ("ruleset" )
1342+ )
1343+ for record in triage_records :
1344+ record .action_label = action_labels .get (record .action , record .action )
1345+ badge_class , icon = TRIAGE_ACTION_STYLES .get (record .action , TRIAGE_ACTION_DEFAULT_STYLE )
1346+ record .action_badge_class = badge_class
1347+ record .action_icon = icon
1348+
1349+ triage_by_vulnerability = {record .vulnerability_id : record for record in triage_records }
1350+ display_filters = self .get_vulnerability_display_filters ()
1351+ has_display_filters = any (display_filters .values ())
1352+
1353+ for product_package in page_obj .object_list :
1354+ all_vulnerabilities = list (product_package .package .affected_by_vulnerabilities .all ())
1355+ for vulnerability in all_vulnerabilities :
1356+ vulnerability .triage_record = triage_by_vulnerability .get (vulnerability .id )
1357+ if has_display_filters :
1358+ product_package .display_vulnerabilities = [
1359+ vulnerability
1360+ for vulnerability in all_vulnerabilities
1361+ if self .vulnerability_passes_display_filters (vulnerability , display_filters )
1362+ ]
1363+ else :
1364+ product_package .display_vulnerabilities = all_vulnerabilities
1365+
12781366 def get_context_data (self , ** kwargs ):
12791367 product = self .object
12801368
@@ -1324,38 +1412,8 @@ def get_context_data(self, **kwargs):
13241412 page_number = self .request .GET .get (self .query_dict_page_param )
13251413 page_obj = paginator .get_page (page_number )
13261414
1327- # Set the proper VulnerabilityAnalysis instance on each vulnerability
1328- for product_package in page_obj .object_list :
1329- for vulnerability in product_package .package .affected_by_vulnerabilities .all ():
1330- for analysis in vulnerability .vulnerability_analyses .all ():
1331- if analysis .product_package_id == product_package .id :
1332- vulnerability .vulnerability_analysis = analysis
1333- continue
1334-
1335- # Attach the winning triage record to each vulnerability
1336- vulnerability_ids = {
1337- vulnerability .id
1338- for product_package in page_obj .object_list
1339- for vulnerability in product_package .package .affected_by_vulnerabilities .all ()
1340- }
1341- action_labels = dict (TriageAction .choices )
1342- triage_records = list (
1343- TriageRecord .objects .filter (
1344- product = product ,
1345- vulnerability_id__in = vulnerability_ids ,
1346- )
1347- .primary_actions ()
1348- .select_related ("ruleset" )
1349- )
1350- for record in triage_records :
1351- record .action_label = action_labels .get (record .action , record .action )
1352- badge_class , icon = TRIAGE_ACTION_STYLES .get (record .action , TRIAGE_ACTION_DEFAULT_STYLE )
1353- record .action_badge_class = badge_class
1354- record .action_icon = icon
1355- triage_by_vulnerability = {record .vulnerability_id : record for record in triage_records }
1356- for product_package in page_obj .object_list :
1357- for vulnerability in product_package .package .affected_by_vulnerabilities .all ():
1358- vulnerability .triage_record = triage_by_vulnerability .get (vulnerability .id )
1415+ self .attach_vulnerability_analyses (page_obj )
1416+ self .attach_triage_data (product , page_obj )
13591417
13601418 context_data .update (
13611419 {
0 commit comments