Skip to content

Commit da67512

Browse files
authored
Merge branch 'main' into release_v34.2.0
2 parents f143920 + 611c708 commit da67512

File tree

3 files changed

+507
-0
lines changed

3 files changed

+507
-0
lines changed

vulnerabilities/api_v2.py

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
#
2+
# Copyright (c) nexB Inc. and others. All rights reserved.
3+
# VulnerableCode is a trademark of nexB Inc.
4+
# SPDX-License-Identifier: Apache-2.0
5+
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
6+
# See https://github.com/aboutcode-org/vulnerablecode for support or download.
7+
# See https://aboutcode.org for more information about nexB OSS projects.
8+
#
9+
10+
11+
from rest_framework import serializers
12+
from rest_framework import viewsets
13+
from rest_framework.response import Response
14+
from rest_framework.reverse import reverse
15+
16+
from vulnerabilities.api import VulnerabilitySeveritySerializer
17+
from vulnerabilities.models import Package
18+
from vulnerabilities.models import Vulnerability
19+
from vulnerabilities.models import VulnerabilityReference
20+
from vulnerabilities.models import VulnerabilitySeverity
21+
from vulnerabilities.models import Weakness
22+
23+
24+
class WeaknessV2Serializer(serializers.ModelSerializer):
25+
cwe_id = serializers.CharField()
26+
name = serializers.CharField()
27+
description = serializers.CharField()
28+
29+
class Meta:
30+
model = Weakness
31+
fields = ["cwe_id", "name", "description"]
32+
33+
34+
class VulnerabilityReferenceV2Serializer(serializers.ModelSerializer):
35+
url = serializers.CharField()
36+
reference_type = serializers.CharField()
37+
reference_id = serializers.CharField()
38+
39+
class Meta:
40+
model = VulnerabilityReference
41+
fields = ["url", "reference_type", "reference_id"]
42+
43+
44+
class VulnerabilityV2Serializer(serializers.ModelSerializer):
45+
aliases = serializers.SerializerMethodField()
46+
weaknesses = WeaknessV2Serializer(many=True)
47+
references = VulnerabilityReferenceV2Serializer(many=True, source="vulnerabilityreference_set")
48+
severities = VulnerabilitySeveritySerializer(many=True)
49+
50+
class Meta:
51+
model = Vulnerability
52+
fields = [
53+
"vulnerability_id",
54+
"aliases",
55+
"summary",
56+
"severities",
57+
"weaknesses",
58+
"references",
59+
]
60+
61+
def get_aliases(self, obj):
62+
return [alias.alias for alias in obj.aliases.all()]
63+
64+
def get_severities(self, obj):
65+
return obj.severities
66+
67+
68+
class VulnerabilityListSerializer(serializers.ModelSerializer):
69+
url = serializers.SerializerMethodField()
70+
71+
class Meta:
72+
model = Vulnerability
73+
fields = ["vulnerability_id", "url"]
74+
75+
def get_url(self, obj):
76+
request = self.context.get("request")
77+
return reverse(
78+
"vulnerability-v2-detail",
79+
kwargs={"vulnerability_id": obj.vulnerability_id},
80+
request=request,
81+
)
82+
83+
84+
class VulnerabilityV2ViewSet(viewsets.ReadOnlyModelViewSet):
85+
queryset = Vulnerability.objects.all()
86+
serializer_class = VulnerabilityV2Serializer
87+
lookup_field = "vulnerability_id"
88+
89+
def get_queryset(self):
90+
queryset = super().get_queryset()
91+
vulnerability_ids = self.request.query_params.getlist("vulnerability_id")
92+
aliases = self.request.query_params.getlist("alias")
93+
94+
if vulnerability_ids:
95+
queryset = queryset.filter(vulnerability_id__in=vulnerability_ids)
96+
97+
if aliases:
98+
queryset = queryset.filter(aliases__alias__in=aliases).distinct()
99+
100+
return queryset
101+
102+
def get_serializer_class(self):
103+
if self.action == "list":
104+
return VulnerabilityListSerializer
105+
return super().get_serializer_class()
106+
107+
def list(self, request, *args, **kwargs):
108+
queryset = self.get_queryset()
109+
vulnerability_ids = request.query_params.getlist("vulnerability_id")
110+
111+
# If exactly one vulnerability_id is provided, return the serialized data
112+
if len(vulnerability_ids) == 1:
113+
try:
114+
vulnerability = queryset.get(vulnerability_id=vulnerability_ids[0])
115+
serializer = self.get_serializer(vulnerability)
116+
return Response(serializer.data)
117+
except Vulnerability.DoesNotExist:
118+
return Response({"detail": "Not found."}, status=404)
119+
120+
# Otherwise, return a dictionary of vulnerabilities keyed by vulnerability_id
121+
page = self.paginate_queryset(queryset)
122+
if page is not None:
123+
serializer = self.get_serializer(page, many=True)
124+
data = serializer.data
125+
vulnerabilities = {item["vulnerability_id"]: item for item in data}
126+
return self.get_paginated_response({"vulnerabilities": vulnerabilities})
127+
128+
serializer = self.get_serializer(queryset, many=True)
129+
data = serializer.data
130+
vulnerabilities = {item["vulnerability_id"]: item for item in data}
131+
return Response({"vulnerabilities": vulnerabilities})
132+
133+
134+
class PackageV2Serializer(serializers.ModelSerializer):
135+
purl = serializers.CharField(source="package_url")
136+
affected_by_vulnerabilities = serializers.SerializerMethodField()
137+
fixing_vulnerabilities = serializers.SerializerMethodField()
138+
next_non_vulnerable_version = serializers.CharField(read_only=True)
139+
latest_non_vulnerable_version = serializers.CharField(read_only=True)
140+
141+
class Meta:
142+
model = Package
143+
fields = [
144+
"purl",
145+
"affected_by_vulnerabilities",
146+
"fixing_vulnerabilities",
147+
"next_non_vulnerable_version",
148+
"latest_non_vulnerable_version",
149+
]
150+
151+
def get_affected_by_vulnerabilities(self, obj):
152+
return [vuln.vulnerability_id for vuln in obj.affected_by_vulnerabilities.all()]
153+
154+
def get_fixing_vulnerabilities(self, obj):
155+
return [vuln.vulnerability_id for vuln in obj.fixing_vulnerabilities.all()]
156+
157+
158+
class PackageV2ViewSet(viewsets.ReadOnlyModelViewSet):
159+
queryset = Package.objects.all()
160+
serializer_class = PackageV2Serializer
161+
162+
def get_queryset(self):
163+
queryset = super().get_queryset()
164+
package_purls = self.request.query_params.getlist("purl")
165+
affected_by_vulnerability = self.request.query_params.get("affected_by_vulnerability")
166+
fixing_vulnerability = self.request.query_params.get("fixing_vulnerability")
167+
168+
if package_purls:
169+
queryset = queryset.filter(package_url__in=package_purls)
170+
if affected_by_vulnerability:
171+
queryset = queryset.filter(
172+
affected_by_vulnerabilities__vulnerability_id=affected_by_vulnerability
173+
)
174+
if fixing_vulnerability:
175+
queryset = queryset.filter(
176+
fixing_vulnerabilities__vulnerability_id=fixing_vulnerability
177+
)
178+
return queryset.with_is_vulnerable()
179+
180+
def list(self, request, *args, **kwargs):
181+
queryset = self.get_queryset()
182+
# Apply pagination
183+
page = self.paginate_queryset(queryset)
184+
if page is not None:
185+
serializer = self.get_serializer(page, many=True)
186+
data = serializer.data
187+
# Use 'self.get_paginated_response' to include pagination data
188+
return self.get_paginated_response({"packages": data})
189+
190+
# If pagination is not applied
191+
serializer = self.get_serializer(queryset, many=True)
192+
data = serializer.data
193+
return Response({"packages": data})

0 commit comments

Comments
 (0)