Skip to content

Commit 9ab1c2f

Browse files
committed
Trim api response and add documentation for the bulk endpoints
Signed-off-by: Shivam Sandbhor <shivam.sandbhor@gmail.com>
1 parent 8df1bf2 commit 9ab1c2f

2 files changed

Lines changed: 43 additions & 40 deletions

File tree

vulnerabilities/api.py

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
2323

2424
from urllib.parse import unquote
25+
from typing import List
2526

2627
from django.db.models import Q
2728
from django.urls import reverse
@@ -31,11 +32,17 @@
3132
from rest_framework import viewsets
3233
from rest_framework.decorators import action
3334
from rest_framework.response import Response
35+
from drf_spectacular.utils import extend_schema, inline_serializer
36+
from drf_spectacular.types import OpenApiTypes
3437

3538
from vulnerabilities.models import Package
3639
from vulnerabilities.models import Vulnerability
3740
from vulnerabilities.models import VulnerabilityReference
3841

42+
# This serializer is used for the bulk apis, to prevent wrong auto documentation
43+
# TODO: Fix the swagger documentation for bulk apis
44+
placeholder_serializer = inline_serializer(name="Placeholder", fields={})
45+
3946

4047
class VulnerabilityReferenceSerializer(serializers.ModelSerializer):
4148
class Meta:
@@ -63,45 +70,52 @@ class Meta:
6370
fields = ["url", "vulnerability_id"]
6471

6572

66-
class VulnerabilitySerializer(serializers.HyperlinkedModelSerializer):
67-
references = VulnerabilityReferenceSerializer(many=True, source="vulnerabilityreference_set")
73+
class MinimalVulnerabilitySerializer(serializers.HyperlinkedModelSerializer):
74+
6875
resolved_packages = HyperLinkedPackageSerializer(
6976
many=True, source="resolved_to", read_only=True
7077
)
7178
unresolved_packages = HyperLinkedPackageSerializer(
7279
many=True, source="vulnerable_to", read_only=True
7380
)
7481

82+
class Meta:
83+
model = Vulnerability
84+
fields = ["url", "unresolved_packages", "resolved_packages"]
85+
86+
87+
class VulnerabilitySerializer(MinimalVulnerabilitySerializer):
88+
references = VulnerabilityReferenceSerializer(many=True, source="vulnerabilityreference_set")
89+
7590
class Meta:
7691
model = Vulnerability
7792
fields = "__all__"
7893

7994

80-
class PackageSerializer(serializers.HyperlinkedModelSerializer):
95+
class MinimalPackageSerializer(serializers.HyperlinkedModelSerializer):
8196
unresolved_vulnerabilities = HyperLinkedVulnerabilitySerializer(
8297
many=True, source="vulnerable_to", read_only=True
8398
)
8499
resolved_vulnerabilities = HyperLinkedVulnerabilitySerializer(
85100
many=True, source="resolved_to", read_only=True
86101
)
87-
purl = serializers.CharField(source="package_url")
88102

89103
class Meta:
90104
model = Package
91105
fields = [
92-
"url",
93-
"type",
94-
"namespace",
95-
"name",
96-
"version",
97-
"qualifiers",
98-
"subpath",
99-
"purl",
100106
"resolved_vulnerabilities",
101107
"unresolved_vulnerabilities",
102108
]
103109

104110

111+
class PackageSerializer(MinimalPackageSerializer):
112+
purl = serializers.CharField(source="package_url")
113+
114+
class Meta:
115+
model = Package
116+
exclude = ["vulnerabilities"]
117+
118+
105119
class PackageFilterSet(filters.FilterSet):
106120
purl = filters.CharFilter(method="filter_purl")
107121

@@ -129,8 +143,13 @@ class PackageViewSet(viewsets.ReadOnlyModelViewSet):
129143
filter_backends = (filters.DjangoFilterBackend,)
130144
filterset_class = PackageFilterSet
131145

146+
# TODO: Fix the swagger documentation for this endpoint
147+
@extend_schema(request=placeholder_serializer, responses=placeholder_serializer)
132148
@action(detail=False, methods=["post"])
133149
def bulk_search(self, request):
150+
"""
151+
See https://github.com/nexB/vulnerablecode/pull/303#issuecomment-761801639 for docs
152+
"""
134153
filter_list = Q()
135154
response = {}
136155
if not isinstance(request.data.get("packages"), list):
@@ -152,7 +171,7 @@ def bulk_search(self, request):
152171
response[purl] = {}
153172
res = Package.objects.filter(filter_list)
154173
for p in res:
155-
response[p.package_url] = PackageSerializer(p, context={"request": request}).data
174+
response[p.package_url] = MinimalPackageSerializer(p, context={"request": request}).data
156175

157176
return Response(response)
158177

@@ -172,8 +191,13 @@ class VulnerabilityViewSet(viewsets.ReadOnlyModelViewSet):
172191
filter_backends = (filters.DjangoFilterBackend,)
173192
filterset_class = VulnerabilityFilterSet
174193

194+
# TODO: Fix the swagger documentation for this endpoint
195+
@extend_schema(request=placeholder_serializer, responses=placeholder_serializer)
175196
@action(detail=False, methods=["post"])
176197
def bulk_search(self, request):
198+
"""
199+
See https://github.com/nexB/vulnerablecode/pull/303#issuecomment-761801619 for docs
200+
"""
177201
filter_list = []
178202
response = {}
179203
if not isinstance(request.data.get("vulnerabilities"), list):
@@ -190,5 +214,7 @@ def bulk_search(self, request):
190214
response[cve_id] = {}
191215
res = Vulnerability.objects.filter(cve_id__in=filter_list)
192216
for vuln in res:
193-
response[vuln.cve_id] = VulnerabilitySerializer(vuln, context={"request": request}).data
217+
response[vuln.cve_id] = MinimalVulnerabilitySerializer(
218+
vuln, context={"request": request}
219+
).data
194220
return Response(response)

vulnerabilities/tests/test_api.py

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,6 @@ def test_bulk_vulnerabilities_api(self):
200200
request_body = {"vulnerabilities": ["CVE-2009-1382", "CVE-2014-8242", "RANDOM-CVE"]}
201201
expected_response = {
202202
"CVE-2009-1382": {
203-
"url": "http://testserver/api/vulnerabilities/2/",
204-
"references": [],
205203
"resolved_packages": [
206204
OrderedDict(
207205
[
@@ -217,13 +215,9 @@ def test_bulk_vulnerabilities_api(self):
217215
),
218216
],
219217
"unresolved_packages": [],
220-
"cve_id": "CVE-2009-1382",
221-
"summary": "",
222-
"cvss": None,
218+
"url": "http://testserver/api/vulnerabilities/2/",
223219
},
224220
"CVE-2014-8242": {
225-
"url": "http://testserver/api/vulnerabilities/1/",
226-
"references": [],
227221
"resolved_packages": [],
228222
"unresolved_packages": [
229223
OrderedDict(
@@ -233,12 +227,11 @@ def test_bulk_vulnerabilities_api(self):
233227
]
234228
)
235229
],
236-
"cve_id": "CVE-2014-8242",
237-
"summary": "",
238-
"cvss": None,
230+
"url": "http://testserver/api/vulnerabilities/1/",
239231
},
240232
"RANDOM-CVE": {},
241233
}
234+
242235
response = self.client.post(
243236
"/api/vulnerabilities/bulk_search/", data=request_body, content_type="application/json"
244237
).data
@@ -256,14 +249,6 @@ def test_bulk_packages_api(self):
256249
).data
257250
expected_response = {
258251
"pkg:deb/debian/librsync@0.9.7-10?distro=jessie": {
259-
"url": "http://testserver/api/packages/1/",
260-
"type": "deb",
261-
"namespace": "debian",
262-
"name": "librsync",
263-
"version": "0.9.7-10",
264-
"qualifiers": {"distro": "jessie"},
265-
"subpath": "",
266-
"purl": "pkg:deb/debian/librsync@0.9.7-10?distro=jessie",
267252
"resolved_vulnerabilities": [],
268253
"unresolved_vulnerabilities": [
269254
OrderedDict(
@@ -275,14 +260,6 @@ def test_bulk_packages_api(self):
275260
],
276261
},
277262
"pkg:deb/debian/mimetex@1.50-1.1?distro=jessie": {
278-
"url": "http://testserver/api/packages/3/",
279-
"type": "deb",
280-
"namespace": "debian",
281-
"name": "mimetex",
282-
"version": "1.50-1.1",
283-
"qualifiers": {"distro": "jessie"},
284-
"subpath": "",
285-
"purl": "pkg:deb/debian/mimetex@1.50-1.1?distro=jessie",
286263
"resolved_vulnerabilities": [
287264
OrderedDict(
288265
[

0 commit comments

Comments
 (0)