3131from vulnerabilities .models import AdvisoryWeakness
3232from vulnerabilities .models import CodeFix
3333from vulnerabilities .models import CodeFixV2
34+ from vulnerabilities .models import ImpactedPackage
3435from vulnerabilities .models import Package
3536from vulnerabilities .models import PackageV2
3637from vulnerabilities .models import PipelineRun
@@ -320,36 +321,28 @@ class Meta:
320321 "risk_score" ,
321322 ]
322323
323- def get_affected_by_vulnerabilities (self , obj ):
324- """
325- Return a dictionary with vulnerabilities as keys and their details, including fixed_by_packages.
326- """
324+ def get_affected_by_vulnerabilities (self , package ):
325+ """Return a dictionary with advisory as keys and their details, including fixed_by_packages."""
327326 result = {}
328327 request = self .context .get ("request" )
329- for adv in getattr (obj , "prefetched_affected_advisories" , []):
330- fixed_by_package = adv .fixed_by_packages .first ()
331- purl = None
332- if fixed_by_package :
333- purl = fixed_by_package .package_url
334- # Get code fixed for a vulnerability
335- code_fixes = CodeFixV2 .objects .filter (advisory = adv ).distinct ()
328+ for impact in package .affected_in_impacts .all ():
329+ advisory = impact .advisory
330+ fixed_by_packages = [pkg .purl for pkg in impact .fixed_by_packages .all ()]
331+ code_fixes = CodeFixV2 .objects .filter (advisory = advisory ).distinct ()
336332 code_fix_urls = [
337333 reverse ("advisory-codefix-detail" , args = [code_fix .id ], request = request )
338334 for code_fix in code_fixes
339335 ]
340-
341- result [adv .avid ] = {
342- "advisory_id" : adv .avid ,
343- "fixed_by_packages" : purl ,
336+ result [advisory .avid ] = {
337+ "advisory_id" : advisory .avid ,
338+ "fixed_by_packages" : fixed_by_packages ,
344339 "code_fixes" : code_fix_urls ,
345340 }
341+
346342 return result
347343
348- def get_fixing_vulnerabilities (self , obj ):
349- # Ghost package should not fix any vulnerability.
350- if obj .is_ghost :
351- return []
352- return [adv .avid for adv in obj .fixing_advisories .all ()]
344+ def get_fixing_vulnerabilities (self , package ):
345+ return [impact .advisory .avid for impact in package .fixed_in_impacts .all ()]
353346
354347
355348class PackageurlListSerializer (serializers .Serializer ):
@@ -968,12 +961,21 @@ def get_view_name(self):
968961
969962
970963class AdvisoriesPackageV2ViewSet (viewsets .ReadOnlyModelViewSet ):
971- queryset = PackageV2 .objects .all ().prefetch_related (
972- Prefetch (
973- "affected_by_advisories" ,
974- queryset = AdvisoryV2 .objects .prefetch_related ("fixed_by_packages" ),
975- to_attr = "prefetched_affected_advisories" ,
964+ queryset = (
965+ PackageV2 .objects .all ()
966+ .prefetch_related (
967+ Prefetch (
968+ "affected_in_impacts" ,
969+ queryset = ImpactedPackage .objects .select_related ("advisory" ).prefetch_related (
970+ "fixed_by_packages" ,
971+ ),
972+ ),
973+ Prefetch (
974+ "fixed_in_impacts" ,
975+ queryset = ImpactedPackage .objects .select_related ("advisory" ),
976+ ),
976977 )
978+ .with_is_vulnerable ()
977979 )
978980 serializer_class = AdvisoryPackageV2Serializer
979981 filter_backends = (filters .DjangoFilterBackend ,)
@@ -994,30 +996,28 @@ def get_queryset(self):
994996
995997 def list (self , request , * args , ** kwargs ):
996998 queryset = self .get_queryset ()
997- # Apply pagination
998999 page = self .paginate_queryset (queryset )
1000+
1001+ advisories = set ()
9991002 if page is not None :
1000- # Collect only vulnerabilities for packages in the current page
1001- advisories = set ()
10021003 for package in page :
1003- advisories .update (package .affected_by_advisories .all ())
1004- advisories .update (package .fixing_advisories .all ())
1004+ advisories .update ({ impact . advisory for impact in package .affected_in_impacts .all ()} )
1005+ advisories .update ({ impact . advisory for impact in package .fixed_in_impacts .all ()} )
10051006
10061007 # Serialize the vulnerabilities with advisory_id and advisory label as keys
10071008 advisory_data = {f"{ adv .avid } " : AdvisoryV2Serializer (adv ).data for adv in advisories }
10081009
10091010 # Serialize the current page of packages
10101011 serializer = self .get_serializer (page , many = True )
10111012 data = serializer .data
1012- print ( data )
1013+
10131014 # Use 'self.get_paginated_response' to include pagination data
10141015 return self .get_paginated_response ({"advisories" : advisory_data , "packages" : data })
10151016
10161017 # If pagination is not applied, collect vulnerabilities for all packages
1017- advisories = set ()
10181018 for package in queryset :
1019- advisories .update (package .affected_by_vulnerabilities .all ())
1020- advisories .update (package .fixing_vulnerabilities .all ())
1019+ advisories .update ({ impact . advisory for impact in package .affected_in_impacts .all ()} )
1020+ advisories .update ({ impact . advisory for impact in package .fixed_in_impacts .all ()} )
10211021
10221022 advisory_data = {f"{ adv .avid } " : AdvisoryV2Serializer (adv ).data for adv in advisories }
10231023
@@ -1053,13 +1053,28 @@ def bulk_lookup(self, request):
10531053 purls = validated_data .get ("purls" )
10541054
10551055 # Fetch packages matching the provided purls
1056- packages = PackageV2 .objects .for_purls (purls ).with_is_vulnerable ()
1056+ packages = (
1057+ PackageV2 .objects .for_purls (purls )
1058+ .prefetch_related (
1059+ Prefetch (
1060+ "affected_in_impacts" ,
1061+ queryset = ImpactedPackage .objects .select_related ("advisory" ).prefetch_related (
1062+ "fixed_by_packages" ,
1063+ ),
1064+ ),
1065+ Prefetch (
1066+ "fixed_in_impacts" ,
1067+ queryset = ImpactedPackage .objects .select_related ("advisory" ),
1068+ ),
1069+ )
1070+ .with_is_vulnerable ()
1071+ )
10571072
10581073 # Collect vulnerabilities associated with these packages
10591074 advisories = set ()
10601075 for package in packages :
1061- advisories .update (package .affected_by_advisories .all ())
1062- advisories .update (package .fixing_advisories .all ())
1076+ advisories .update ({ impact . advisory for impact in package .affected_in_impacts .all ()} )
1077+ advisories .update ({ impact . advisory for impact in package .fixed_in_impacts .all ()} )
10631078
10641079 # Serialize vulnerabilities with vulnerability_id as keys
10651080 advisory_data = {adv .avid : AdvisoryV2Serializer (adv ).data for adv in advisories }
@@ -1124,6 +1139,20 @@ def bulk_search(self, request):
11241139 PackageV2 .objects .filter (plain_package_url__in = plain_purls )
11251140 .order_by ("plain_package_url" )
11261141 .distinct ("plain_package_url" )
1142+ .prefetch_related (
1143+ Prefetch (
1144+ "affected_in_impacts" ,
1145+ queryset = ImpactedPackage .objects .select_related (
1146+ "advisory"
1147+ ).prefetch_related (
1148+ "fixed_by_packages" ,
1149+ ),
1150+ ),
1151+ Prefetch (
1152+ "fixed_in_impacts" ,
1153+ queryset = ImpactedPackage .objects .select_related ("advisory" ),
1154+ ),
1155+ )
11271156 .with_is_vulnerable ()
11281157 )
11291158
@@ -1132,14 +1161,16 @@ def bulk_search(self, request):
11321161 # Collect vulnerabilities associated with these packages
11331162 advisories = set ()
11341163 for package in packages :
1135- advisories .update (package .affected_by_advisories .all ())
1136- advisories .update (package .fixing_advisories .all ())
1164+ advisories .update ({ impact . advisory for impact in package .affected_in_impacts .all ()} )
1165+ advisories .update ({ impact . advisory for impact in package .fixed_in_impacts .all ()} )
11371166
11381167 advisory_data = {adv .avid : AdvisoryV2Serializer (adv ).data for adv in advisories }
11391168
11401169 if not purl_only :
11411170 package_data = AdvisoryPackageV2Serializer (
1142- packages , many = True , context = {"request" : request }
1171+ packages ,
1172+ many = True ,
1173+ context = {"request" : request },
11431174 ).data
11441175 return Response (
11451176 {
@@ -1154,20 +1185,38 @@ def bulk_search(self, request):
11541185 vulnerable_purls = [str (package .plain_package_url ) for package in vulnerable_purls ]
11551186 return Response (data = vulnerable_purls )
11561187
1157- query = PackageV2 .objects .filter (package_url__in = purls ).distinct ().with_is_vulnerable ()
1188+ query = (
1189+ PackageV2 .objects .filter (package_url__in = purls )
1190+ .distinct ()
1191+ .prefetch_related (
1192+ Prefetch (
1193+ "affected_in_impacts" ,
1194+ queryset = ImpactedPackage .objects .select_related ("advisory" ).prefetch_related (
1195+ "fixed_by_packages" ,
1196+ ),
1197+ ),
1198+ Prefetch (
1199+ "fixed_in_impacts" ,
1200+ queryset = ImpactedPackage .objects .select_related ("advisory" ),
1201+ ),
1202+ )
1203+ .with_is_vulnerable ()
1204+ )
11581205 packages = query
11591206
11601207 # Collect vulnerabilities associated with these packages
11611208 advisories = set ()
11621209 for package in packages :
1163- advisories .update (package .affected_by_advisories .all ())
1164- advisories .update (package .fixing_advisories .all ())
1210+ advisories .update ({ impact . advisory for impact in package .affected_in_impacts .all ()} )
1211+ advisories .update ({ impact . advisory for impact in package .fixed_in_impacts .all ()} )
11651212
11661213 advisory_data = {adv .advisory_id : AdvisoryV2Serializer (adv ).data for adv in advisories }
11671214
11681215 if not purl_only :
11691216 package_data = AdvisoryPackageV2Serializer (
1170- packages , many = True , context = {"request" : request }
1217+ packages ,
1218+ many = True ,
1219+ context = {"request" : request },
11711220 ).data
11721221 return Response (
11731222 {
0 commit comments