Skip to content

Commit d5baac8

Browse files
committed
Add V2 API endpoints
Reference: #1572 Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
1 parent 590c91a commit d5baac8

2 files changed

Lines changed: 116 additions & 0 deletions

File tree

vulnerabilities/api.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,3 +690,112 @@ class AliasViewSet(VulnerabilityViewSet):
690690
"""
691691

692692
filterset_class = AliasFilterSet
693+
694+
class WeaknessV2Serializer(serializers.ModelSerializer):
695+
cwe_id = serializers.CharField()
696+
name = serializers.CharField()
697+
description = serializers.CharField()
698+
699+
class Meta:
700+
model = Weakness
701+
fields = ["cwe_id", "name", "description"]
702+
703+
704+
class VulnerabilityReferenceV2Serializer(serializers.ModelSerializer):
705+
url = serializers.CharField()
706+
reference_type = serializers.CharField()
707+
reference_id = serializers.CharField()
708+
709+
class Meta:
710+
model = VulnerabilityReference
711+
fields = ["url", "reference_type", "reference_id"]
712+
713+
class VulnerabilityV2Serializer(serializers.ModelSerializer):
714+
aliases = serializers.SerializerMethodField()
715+
severities = serializers.SerializerMethodField()
716+
weaknesses = WeaknessV2Serializer(many=True)
717+
references = VulnerabilityReferenceV2Serializer(many=True, source='vulnerabilityreference_set')
718+
719+
class Meta:
720+
model = Vulnerability
721+
fields = [
722+
"vulnerability_id",
723+
"aliases",
724+
"summary",
725+
"severities",
726+
"weaknesses",
727+
"references",
728+
]
729+
730+
def get_aliases(self, obj):
731+
return [alias.alias for alias in obj.aliases.all()]
732+
733+
def get_severities(self, obj):
734+
#TODO: Need data model changes
735+
return []
736+
737+
738+
class VulnerabilityV2ViewSet(viewsets.ReadOnlyModelViewSet):
739+
queryset = Vulnerability.objects.all()
740+
serializer_class = VulnerabilityV2Serializer
741+
742+
def list(self, request, *args, **kwargs):
743+
queryset = self.get_queryset()
744+
# Apply pagination
745+
page = self.paginate_queryset(queryset)
746+
if page is not None:
747+
serializer = self.get_serializer(page, many=True)
748+
data = serializer.data
749+
vulnerabilities = {item['vulnerability_id']: item for item in data}
750+
# Use 'self.get_paginated_response' to include pagination data
751+
return self.get_paginated_response({'vulnerabilities': vulnerabilities})
752+
753+
# If pagination is not applied
754+
serializer = self.get_serializer(queryset, many=True)
755+
data = serializer.data
756+
vulnerabilities = {item['vulnerability_id']: item for item in data}
757+
return Response({'vulnerabilities': vulnerabilities})
758+
759+
760+
class PackageV2Serializer(serializers.ModelSerializer):
761+
purl = serializers.CharField(source='package_url')
762+
affected_by_vulnerabilities = serializers.SerializerMethodField()
763+
fixing_vulnerabilities = serializers.SerializerMethodField()
764+
next_non_vulnerable_version = serializers.CharField(read_only=True)
765+
latest_non_vulnerable_version = serializers.CharField(read_only=True)
766+
767+
class Meta:
768+
model = Package
769+
fields = [
770+
'purl',
771+
'affected_by_vulnerabilities',
772+
'fixing_vulnerabilities',
773+
'next_non_vulnerable_version',
774+
'latest_non_vulnerable_version',
775+
]
776+
777+
def get_affected_by_vulnerabilities(self, obj):
778+
return [vuln.vulnerability_id for vuln in obj.affected_by_vulnerabilities.all()]
779+
780+
def get_fixing_vulnerabilities(self, obj):
781+
return [vuln.vulnerability_id for vuln in obj.fixing_vulnerabilities.all()]
782+
783+
784+
class PackageV2ViewSet(viewsets.ReadOnlyModelViewSet):
785+
queryset = Package.objects.all()
786+
serializer_class = PackageV2Serializer
787+
788+
def list(self, request, *args, **kwargs):
789+
queryset = self.get_queryset().with_is_vulnerable()
790+
# Apply pagination
791+
page = self.paginate_queryset(queryset)
792+
if page is not None:
793+
serializer = self.get_serializer(page, many=True)
794+
data = serializer.data
795+
# Use 'self.get_paginated_response' to include pagination data
796+
return self.get_paginated_response({'purls': data})
797+
798+
# If pagination is not applied
799+
serializer = self.get_serializer(queryset, many=True)
800+
data = serializer.data
801+
return Response({'purls': data})

vulnerablecode/urls.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
from vulnerabilities.api import CPEViewSet
2121
from vulnerabilities.api import PackageViewSet
2222
from vulnerabilities.api import VulnerabilityViewSet
23+
from vulnerabilities.api import PackageV2ViewSet
24+
from vulnerabilities.api import VulnerabilityV2ViewSet
2325
from vulnerabilities.views import ApiUserCreateView
2426
from vulnerabilities.views import HomePage
2527
from vulnerabilities.views import PackageDetails
@@ -43,6 +45,10 @@ def __init__(self, *args, **kwargs):
4345
api_router.register("cpes", CPEViewSet, basename="cpe")
4446
api_router.register("aliases", AliasViewSet, basename="alias")
4547

48+
api_v2_router = OptionalSlashRouter()
49+
api_v2_router.register("vulnerabilities", VulnerabilityV2ViewSet, basename="vulnerability-v2")
50+
api_v2_router.register("packages", PackageV2ViewSet, basename="package-v2")
51+
4652
urlpatterns = [
4753
path(
4854
"robots.txt",
@@ -98,6 +104,7 @@ def __init__(self, *args, **kwargs):
98104
TemplateView.as_view(template_name="tos.html"),
99105
name="api_tos",
100106
),
107+
path('api/v2/', include(api_v2_router.urls)),
101108
path(
102109
"admin/",
103110
admin.site.urls,

0 commit comments

Comments
 (0)