1111from urllib .parse import urlencode
1212
1313from django .contrib .postgres .aggregates import ArrayAgg
14- from django .contrib .postgres .aggregates import JSONBAgg
1514from django .db .models import Exists
16- from django .db .models import F
1715from django .db .models import Max
1816from django .db .models import OuterRef
1917from django .db .models import Prefetch
2018from django .db .models import Q
21- from django .db .models .functions import JSONObject
2219from django_filters import rest_framework as filters
2320from drf_spectacular .utils import extend_schema
2421from packageurl import PackageURL
3128from vulnerabilities .models import AdvisoryAlias
3229from vulnerabilities .models import AdvisoryReference
3330from vulnerabilities .models import AdvisorySet
31+ from vulnerabilities .models import AdvisorySetMember
3432from vulnerabilities .models import AdvisorySeverity
3533from vulnerabilities .models import AdvisoryV2
3634from vulnerabilities .models import AdvisoryWeakness
@@ -503,7 +501,10 @@ def get_affected_advisories_bulk(packages, max_advisories, base_url):
503501 )
504502 .select_related ("primary_advisory" )
505503 .prefetch_related (
506- Prefetch ("aliases" , queryset = AdvisoryAlias .objects .only ("alias" )),
504+ Prefetch (
505+ "aliases" ,
506+ queryset = AdvisoryAlias .objects .only ("alias" ),
507+ ),
507508 )
508509 .annotate (
509510 max_severity = Max (
@@ -512,16 +513,6 @@ def get_affected_advisories_bulk(packages, max_advisories, base_url):
512513 max_exploitability = Max (
513514 "members__advisory__exploitability" ,
514515 ),
515- ssvc_trees = JSONBAgg (
516- JSONObject (
517- vector = F ("members__advisory__related_ssvcs__vector" ),
518- decision = F ("members__advisory__related_ssvcs__decision" ),
519- options = F ("members__advisory__related_ssvcs__options" ),
520- source_url = F ("members__advisory__related_ssvcs__source_advisory__url" ),
521- ),
522- filter = Q (members__advisory__related_ssvcs__decision__isnull = False ),
523- distinct = True ,
524- ),
525516 )
526517 .only (
527518 "id" ,
@@ -532,10 +523,88 @@ def get_affected_advisories_bulk(packages, max_advisories, base_url):
532523 )
533524 )
534525
526+ advisory_set_ids = [a .id for a in advisory_sets ]
527+
528+ member_rows = AdvisorySetMember .objects .filter (
529+ advisory_set_id__in = advisory_set_ids ,
530+ ).values (
531+ "advisory_set_id" ,
532+ "advisory_id" ,
533+ )
534+
535+ advisory_ids_by_set = defaultdict (set )
536+ all_advisory_ids = set ()
537+
538+ for row in member_rows :
539+ advisory_set_id = row ["advisory_set_id" ]
540+ advisory_id = row ["advisory_id" ]
541+
542+ advisory_ids_by_set [advisory_set_id ].add (advisory_id )
543+ all_advisory_ids .add (advisory_id )
544+
545+ ssvc_rows = (
546+ SSVC .objects .filter (
547+ related_advisories__id__in = all_advisory_ids ,
548+ decision__isnull = False ,
549+ )
550+ .select_related (
551+ "source_advisory" ,
552+ )
553+ .values (
554+ "related_advisories__id" ,
555+ "vector" ,
556+ "decision" ,
557+ "options" ,
558+ "source_advisory__url" ,
559+ )
560+ )
561+
562+ ssvc_by_advisory = defaultdict (list )
563+
564+ for row in ssvc_rows :
565+ advisory_id = row ["related_advisories__id" ]
566+
567+ ssvc_by_advisory [advisory_id ].append (
568+ {
569+ "vector" : row ["vector" ],
570+ "decision" : row ["decision" ],
571+ "options" : row ["options" ],
572+ "source_url" : row ["source_advisory__url" ],
573+ }
574+ )
575+
535576 package_map = defaultdict (list )
536577
537578 for adv in advisory_sets :
538579 adv ._aliases_cache = [a .alias for a in adv .aliases .all ()]
580+
581+ advisory_ids = advisory_ids_by_set .get (adv .id , set ())
582+
583+ seen = set ()
584+ ssvc_trees = []
585+
586+ for advisory_id in advisory_ids :
587+ for ssvc in ssvc_by_advisory .get (advisory_id , []):
588+
589+ key = (
590+ ssvc ["vector" ],
591+ ssvc ["decision" ],
592+ (
593+ tuple (sorted (ssvc ["options" ].items ()))
594+ if isinstance (ssvc ["options" ], dict )
595+ else str (ssvc ["options" ])
596+ ),
597+ ssvc ["source_url" ],
598+ )
599+
600+ if key in seen :
601+ continue
602+
603+ seen .add (key )
604+ ssvc_trees .append (ssvc )
605+
606+ adv .ssvc_trees = ssvc_trees
607+
539608 package_map [adv .package_id ].append (adv )
540609
541610 for package in packages :
@@ -549,6 +618,7 @@ def get_affected_advisories_bulk(packages, max_advisories, base_url):
549618 (package .id , primary .id ),
550619 [],
551620 )
621+
552622 max_sev = adv .max_severity or 0.0
553623 max_exp = adv .max_exploitability or 0.0
554624
@@ -577,7 +647,7 @@ def get_affected_advisories_bulk(packages, max_advisories, base_url):
577647 "exploitability" : exploitability ,
578648 "risk_score" : risk_score ,
579649 "fixed_by_packages" : fixed_by_packages ,
580- "ssvc_trees" : adv .ssvc_trees or [] ,
650+ "ssvc_trees" : adv .ssvc_trees ,
581651 "resource_url" : resource_url ,
582652 }
583653 )
0 commit comments