3838class VulnerabilitySeveritySerializer (serializers .ModelSerializer ):
3939 class Meta :
4040 model = VulnerabilitySeverity
41- fields = ["value" , "scoring_system" , "scoring_elements" ]
41+ fields = ["value" , "scoring_system" , "scoring_elements" , "published_at" ]
42+
43+ def to_representation (self , instance ):
44+ data = super ().to_representation (instance )
45+ published_at = data .get ("published_at" , None )
46+ if not published_at :
47+ data .pop ("published_at" )
48+ return data
4249
4350
4451class VulnerabilityReferenceSerializer (serializers .ModelSerializer ):
@@ -47,7 +54,7 @@ class VulnerabilityReferenceSerializer(serializers.ModelSerializer):
4754
4855 class Meta :
4956 model = VulnerabilityReference
50- fields = ["reference_url" , "reference_id" , "scores" , "url" ]
57+ fields = ["reference_url" , "reference_id" , "reference_type" , " scores" , "url" ]
5158
5259
5360class BaseResourceSerializer (serializers .HyperlinkedModelSerializer ):
@@ -101,6 +108,8 @@ def get_vulnerability(self, vuln):
101108
102109 purl = serializers .CharField (source = "package_url" )
103110
111+ is_vulnerable = serializers .BooleanField ()
112+
104113 class Meta :
105114 model = Package
106115 fields = ["url" , "purl" , "is_vulnerable" , "affected_by_vulnerabilities" ]
@@ -241,21 +250,27 @@ def get_latest_non_vulnerable(self, package):
241250
242251 affected_by_vulnerabilities = serializers .SerializerMethodField ("get_affected_vulnerabilities" )
243252
244- fixing_vulnerabilities = serializers .SerializerMethodField ("get_fixed_vulnerabilities" )
253+ fixing_vulnerabilities = serializers .SerializerMethodField ("get_fixing_vulnerabilities" )
254+
255+ is_vulnerable = serializers .BooleanField ()
245256
246257 def get_fixed_packages (self , package ):
247258 """
248259 Return a queryset of all packages that fix a vulnerability with
249260 same type, namespace, name, subpath and qualifiers of the `package`
250261 """
251- return Package .objects .filter (
252- name = package .name ,
253- namespace = package .namespace ,
254- type = package .type ,
255- qualifiers = package .qualifiers ,
256- subpath = package .subpath ,
257- packagerelatedvulnerability__fix = True ,
258- ).distinct ()
262+ return (
263+ Package .objects .filter (
264+ name = package .name ,
265+ namespace = package .namespace ,
266+ type = package .type ,
267+ qualifiers = package .qualifiers ,
268+ subpath = package .subpath ,
269+ packagerelatedvulnerability__fix = True ,
270+ )
271+ .with_is_vulnerable ()
272+ .distinct ()
273+ )
259274
260275 def get_vulnerabilities_for_a_package (self , package , fix ) -> dict :
261276 """
@@ -278,7 +293,7 @@ def get_vulnerabilities_for_a_package(self, package, fix) -> dict:
278293 context = {"request" : self .context ["request" ]},
279294 ).data
280295
281- def get_fixed_vulnerabilities (self , package ) -> dict :
296+ def get_fixing_vulnerabilities (self , package ) -> dict :
282297 """
283298 Return a mapping of vulnerabilities fixed in the given `package`.
284299 """
@@ -315,12 +330,15 @@ class Meta:
315330 "version" ,
316331 "qualifiers" ,
317332 "subpath" ,
333+ "is_vulnerable" ,
318334 "next_non_vulnerable_version" ,
319335 "latest_non_vulnerable_version" ,
320336 "affected_by_vulnerabilities" ,
321337 "fixing_vulnerabilities" ,
322338 ]
323339
340+ is_vulnerable = serializers .BooleanField ()
341+
324342
325343class PackageFilterSet (filters .FilterSet ):
326344 purl = filters .CharFilter (method = "filter_purl" )
@@ -383,6 +401,9 @@ class PackageViewSet(viewsets.ReadOnlyModelViewSet):
383401 filterset_class = PackageFilterSet
384402 throttle_classes = [StaffUserRateThrottle , AnonRateThrottle ]
385403
404+ def get_queryset (self ):
405+ return super ().get_queryset ().with_is_vulnerable ()
406+
386407 @extend_schema (
387408 request = PackageBulkSearchRequestSerializer ,
388409 responses = {200 : PackageSerializer (many = True )},
@@ -429,6 +450,7 @@ def bulk_search(self, request):
429450 Package .objects .filter (plain_package_url__in = plain_purls )
430451 .order_by ("plain_package_url" )
431452 .distinct ("plain_package_url" )
453+ .with_is_vulnerable ()
432454 )
433455
434456 if not purl_only :
@@ -442,7 +464,7 @@ def bulk_search(self, request):
442464 vulnerable_purls = [str (package .plain_package_url ) for package in vulnerable_purls ]
443465 return Response (data = vulnerable_purls )
444466
445- query = Package .objects .filter (package_url__in = purls ).distinct ()
467+ query = Package .objects .filter (package_url__in = purls ).distinct (). with_is_vulnerable ()
446468
447469 if not purl_only :
448470 return Response (PackageSerializer (query , many = True , context = {"request" : request }).data )
@@ -456,7 +478,9 @@ def all(self, request):
456478 """
457479 Return the Package URLs of all packages known to be vulnerable.
458480 """
459- vulnerable_packages = Package .objects .vulnerable ().only ("package_url" ).distinct ()
481+ vulnerable_packages = (
482+ Package .objects .vulnerable ().only ("package_url" ).distinct ().with_is_vulnerable ()
483+ )
460484 vulnerable_purls = [str (package .package_url ) for package in vulnerable_packages ]
461485 return Response (vulnerable_purls )
462486
@@ -487,11 +511,8 @@ def lookup(self, request):
487511 validated_data = serializer .validated_data
488512 purl = validated_data .get ("purl" )
489513
490- return Response (
491- PackageSerializer (
492- Package .objects .for_purls ([purl ]), many = True , context = {"request" : request }
493- ).data
494- )
514+ qs = self .get_queryset ().for_purls ([purl ]).with_is_vulnerable ()
515+ return Response (PackageSerializer (qs , many = True , context = {"request" : request }).data )
495516
496517 @extend_schema (
497518 request = PackageurlListSerializer ,
@@ -522,7 +543,7 @@ def bulk_lookup(self, request):
522543
523544 return Response (
524545 PackageSerializer (
525- Package .objects .for_purls (purls ),
546+ Package .objects .for_purls (purls ). with_is_vulnerable () ,
526547 many = True ,
527548 context = {"request" : request },
528549 ).data
@@ -540,33 +561,47 @@ class VulnerabilityViewSet(viewsets.ReadOnlyModelViewSet):
540561 Lookup for vulnerabilities affecting packages.
541562 """
542563
564+ queryset = Vulnerability .objects .all ()
565+
543566 def get_fixed_packages_qs (self ):
544567 """
545568 Filter the packages that fixes a vulnerability
546569 on fields like name, namespace and type.
547570 """
548- package_filter_data = { " packagerelatedvulnerability__fix" : True }
571+ return self . get_packages_qs (). filter ( packagerelatedvulnerability__fix = True )
549572
573+ def get_packages_qs (self ):
574+ """
575+ Filter the packages on type, namespace and name.
576+ """
550577 query_params = self .request .query_params
551- for field_name in [ "name" , "namespace" , "type" ]:
552- value = query_params . get ( field_name )
553- if value :
578+ package_filter_data = {}
579+ for field_name in ( "type" , "namespace" , "name" ):
580+ if value := query_params . get ( field_name ) :
554581 package_filter_data [field_name ] = value
555582
556- return PackageFilterSet (package_filter_data ).qs
583+ return PackageFilterSet (package_filter_data ).qs . with_is_vulnerable ()
557584
558585 def get_queryset (self ):
559586 """
560587 Assign filtered packages queryset from `get_fixed_packages_qs`
561588 to a custom attribute `filtered_fixed_packages`
562589 """
563- return Vulnerability .objects .prefetch_related (
564- "weaknesses" ,
565- Prefetch (
566- "packages" ,
567- queryset = self .get_fixed_packages_qs (),
568- to_attr = "filtered_fixed_packages" ,
569- ),
590+ return (
591+ super ()
592+ .get_queryset ()
593+ .prefetch_related (
594+ Prefetch (
595+ "packages" ,
596+ queryset = self .get_packages_qs (),
597+ ),
598+ "weaknesses" ,
599+ Prefetch (
600+ "packages" ,
601+ queryset = self .get_fixed_packages_qs (),
602+ to_attr = "filtered_fixed_packages" ,
603+ ),
604+ )
570605 )
571606
572607 serializer_class = VulnerabilitySerializer
0 commit comments