From 33691f8ebb8bf197ea794cf3ee84e1dd0a475573 Mon Sep 17 00:00:00 2001 From: Shivam Sandbhor Date: Mon, 21 Dec 2020 22:27:43 +0530 Subject: [PATCH 1/7] Add endpoints for bulk requesting vulnerabilities and packages Signed-off-by: Shivam Sandbhor --- vulnerabilities/api.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/vulnerabilities/api.py b/vulnerabilities/api.py index 7b9d383ce..5962f151e 100644 --- a/vulnerabilities/api.py +++ b/vulnerabilities/api.py @@ -23,11 +23,14 @@ from urllib.parse import unquote +from django.db.models import Q from django.urls import reverse from django_filters import rest_framework as filters from packageurl import PackageURL from rest_framework import serializers from rest_framework import viewsets +from rest_framework.decorators import action +from rest_framework.response import Response from vulnerabilities.models import Package from vulnerabilities.models import Vulnerability @@ -126,6 +129,26 @@ class PackageViewSet(viewsets.ReadOnlyModelViewSet): filter_backends = (filters.DjangoFilterBackend,) filterset_class = PackageFilterSet + @action(detail=False, methods=["post"]) + def fetch(self, request): + + filter_list = Q() + # TODO: Do some validation here + for purl in request.data["packages"]: + filter_list |= Q( + **{k: v for k, v in PackageURL.from_string(purl).to_dict().items() if v} + ) + + res = Package.objects.filter(filter_list) + response = {} + for purl in request.data["packages"]: + response[purl] = {} + for p in res: + if p.package_url == purl: + response[purl] = PackageSerializer(p, context={"request": request}).data + + return Response(response) + class VulnerabilityFilterSet(filters.FilterSet): vulnerability_id = filters.CharFilter(field_name="cve_id") @@ -141,3 +164,20 @@ class VulnerabilityViewSet(viewsets.ReadOnlyModelViewSet): paginate_by = 50 filter_backends = (filters.DjangoFilterBackend,) filterset_class = VulnerabilityFilterSet + + @action(detail=False, methods=["post"]) + def fetch(self, request): + filter_list = Q() + # TODO: Do some validation here + for cve_id in request.data["vulnerabilities"]: + filter_list |= Q(cve_id=cve_id) + + res = Vulnerability.objects.filter(filter_list) + response = {} + for cve in request.data["vulnerabilities"]: + response[cve] = {} + for vuln in res: + if vuln.cve_id == cve: + response[cve] = VulnerabilitySerializer(vuln, context={"request": request}).data + + return Response(response) From b832385897f70f3ee823d1dfab66cfe3ce8a62f6 Mon Sep 17 00:00:00 2001 From: Shivam Sandbhor Date: Mon, 21 Dec 2020 22:30:53 +0530 Subject: [PATCH 2/7] Add comment for clarity Signed-off-by: Shivam Sandbhor --- vulnerabilities/api.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vulnerabilities/api.py b/vulnerabilities/api.py index 5962f151e..4746941ba 100644 --- a/vulnerabilities/api.py +++ b/vulnerabilities/api.py @@ -129,6 +129,8 @@ class PackageViewSet(viewsets.ReadOnlyModelViewSet): filter_backends = (filters.DjangoFilterBackend,) filterset_class = PackageFilterSet + # `fetch` is a placeholder + # TODO: Find a good name for this endpoint @action(detail=False, methods=["post"]) def fetch(self, request): @@ -165,6 +167,8 @@ class VulnerabilityViewSet(viewsets.ReadOnlyModelViewSet): filter_backends = (filters.DjangoFilterBackend,) filterset_class = VulnerabilityFilterSet + # `fetch` is a placeholder + # TODO: Find a good name for this endpoint @action(detail=False, methods=["post"]) def fetch(self, request): filter_list = Q() From e39ae02bd477f812fd0258085091827eb5552b5f Mon Sep 17 00:00:00 2001 From: Shivam Sandbhor Date: Mon, 21 Dec 2020 22:44:59 +0530 Subject: [PATCH 3/7] Reduce the time complexity of bulk api request fetch Signed-off-by: Shivam Sandbhor --- vulnerabilities/api.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/vulnerabilities/api.py b/vulnerabilities/api.py index 4746941ba..e515c8bd9 100644 --- a/vulnerabilities/api.py +++ b/vulnerabilities/api.py @@ -133,21 +133,21 @@ class PackageViewSet(viewsets.ReadOnlyModelViewSet): # TODO: Find a good name for this endpoint @action(detail=False, methods=["post"]) def fetch(self, request): - filter_list = Q() - # TODO: Do some validation here + response = {} + # TODO: Do some validation here of request body + for purl in request.data["packages"]: filter_list |= Q( **{k: v for k, v in PackageURL.from_string(purl).to_dict().items() if v} ) - res = Package.objects.filter(filter_list) - response = {} - for purl in request.data["packages"]: + # This handles the case when the said purl doesnt exist in db response[purl] = {} - for p in res: - if p.package_url == purl: - response[purl] = PackageSerializer(p, context={"request": request}).data + + res = Package.objects.filter(filter_list) + for p in res: + response[p.package_url] = PackageSerializer(p, context={"request": request}).data return Response(response) @@ -172,16 +172,16 @@ class VulnerabilityViewSet(viewsets.ReadOnlyModelViewSet): @action(detail=False, methods=["post"]) def fetch(self, request): filter_list = Q() - # TODO: Do some validation here + response = {} + # TODO: Do some validation here of request body for cve_id in request.data["vulnerabilities"]: filter_list |= Q(cve_id=cve_id) + # This handles the case when the said cve doesnt exist in db + response[cve_id] = {} + res = Vulnerability.objects.filter(filter_list) - response = {} - for cve in request.data["vulnerabilities"]: - response[cve] = {} - for vuln in res: - if vuln.cve_id == cve: - response[cve] = VulnerabilitySerializer(vuln, context={"request": request}).data + for vuln in res: + response[vuln.cve_id] = VulnerabilitySerializer(vuln, context={"request": request}).data return Response(response) From ee4bd144fc4ba8a12fb22f9512a79fede3d7d29c Mon Sep 17 00:00:00 2001 From: Shivam Sandbhor Date: Thu, 24 Dec 2020 15:40:52 +0530 Subject: [PATCH 4/7] Don't use Q object for bulk vulnerability api Signed-off-by: Shivam Sandbhor --- vulnerabilities/api.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/vulnerabilities/api.py b/vulnerabilities/api.py index e515c8bd9..ff463e2f1 100644 --- a/vulnerabilities/api.py +++ b/vulnerabilities/api.py @@ -171,16 +171,15 @@ class VulnerabilityViewSet(viewsets.ReadOnlyModelViewSet): # TODO: Find a good name for this endpoint @action(detail=False, methods=["post"]) def fetch(self, request): - filter_list = Q() + filter_list = [] response = {} # TODO: Do some validation here of request body for cve_id in request.data["vulnerabilities"]: - filter_list |= Q(cve_id=cve_id) - + filter_list.append(cve_id) # This handles the case when the said cve doesnt exist in db response[cve_id] = {} - res = Vulnerability.objects.filter(filter_list) + res = Vulnerability.objects.filter(cve_id__in=[cve_id]) for vuln in res: response[vuln.cve_id] = VulnerabilitySerializer(vuln, context={"request": request}).data From 434d65e2aef108a34ae93a25472edd4f6b8db865 Mon Sep 17 00:00:00 2001 From: Shivam Sandbhor Date: Sat, 16 Jan 2021 11:50:02 +0530 Subject: [PATCH 5/7] Add tests for bulk api endpoints Signed-off-by: Shivam Sandbhor --- vulnerabilities/api.py | 17 ++--- vulnerabilities/fixtures/debian.json | 2 +- vulnerabilities/tests/test_api.py | 110 +++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 12 deletions(-) diff --git a/vulnerabilities/api.py b/vulnerabilities/api.py index ff463e2f1..b65b00a43 100644 --- a/vulnerabilities/api.py +++ b/vulnerabilities/api.py @@ -129,15 +129,13 @@ class PackageViewSet(viewsets.ReadOnlyModelViewSet): filter_backends = (filters.DjangoFilterBackend,) filterset_class = PackageFilterSet - # `fetch` is a placeholder - # TODO: Find a good name for this endpoint @action(detail=False, methods=["post"]) - def fetch(self, request): + def bulk_search(self, request): filter_list = Q() response = {} # TODO: Do some validation here of request body - for purl in request.data["packages"]: + for purl in request.POST.getlist("packages"): filter_list |= Q( **{k: v for k, v in PackageURL.from_string(purl).to_dict().items() if v} ) @@ -167,20 +165,17 @@ class VulnerabilityViewSet(viewsets.ReadOnlyModelViewSet): filter_backends = (filters.DjangoFilterBackend,) filterset_class = VulnerabilityFilterSet - # `fetch` is a placeholder - # TODO: Find a good name for this endpoint @action(detail=False, methods=["post"]) - def fetch(self, request): + def bulk_search(self, request): filter_list = [] response = {} # TODO: Do some validation here of request body - for cve_id in request.data["vulnerabilities"]: + + for cve_id in request.POST.getlist("vulnerabilities"): filter_list.append(cve_id) # This handles the case when the said cve doesnt exist in db response[cve_id] = {} - - res = Vulnerability.objects.filter(cve_id__in=[cve_id]) + res = Vulnerability.objects.filter(cve_id__in=filter_list) for vuln in res: response[vuln.cve_id] = VulnerabilitySerializer(vuln, context={"request": request}).data - return Response(response) diff --git a/vulnerabilities/fixtures/debian.json b/vulnerabilities/fixtures/debian.json index 35a160128..27fdd0e72 100644 --- a/vulnerabilities/fixtures/debian.json +++ b/vulnerabilities/fixtures/debian.json @@ -73,7 +73,7 @@ }, { "model": "vulnerabilities.packagerelatedvulnerability", - "pk": 1, + "pk": 10, "fields": { "vulnerability": 2, "package": 2, diff --git a/vulnerabilities/tests/test_api.py b/vulnerabilities/tests/test_api.py index 967830718..4f0f35096 100644 --- a/vulnerabilities/tests/test_api.py +++ b/vulnerabilities/tests/test_api.py @@ -22,6 +22,7 @@ # Visit https://github.com/nexB/vulnerablecode/ for support and download. import os +from collections import OrderedDict from random import choices from unittest.mock import MagicMock from urllib.parse import quote @@ -31,6 +32,8 @@ from vulnerabilities.api import PackageSerializer from vulnerabilities.models import Package +from rest_framework.test import APIRequestFactory +from rest_framework.test import APIClient BASE_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -188,3 +191,110 @@ def test_package_serializer(self): purls = {r["purl"] for r in response} self.assertIn("pkg:deb/debian/mimetex@1.50-1.1?distro=jessie", purls) self.assertIn("pkg:deb/debian/mimetex@1.74-1?distro=jessie", purls) + + +class TestBulkAPIResponse(TestCase): + fixtures = ["debian.json"] + + def test_bulk_vulnerabilities_api(self): + request_body = {"vulnerabilities": ["CVE-2009-1382", "CVE-2014-8242", "RANDOM-CVE"]} + expected_response = { + "CVE-2009-1382": { + "url": "http://testserver/api/vulnerabilities/2/", + "references": [], + "resolved_packages": [ + OrderedDict( + [ + ("url", "http://testserver/api/packages/2/"), + ("purl", "pkg:deb/debian/mimetex@1.74-1?distro=jessie"), + ] + ), + OrderedDict( + [ + ("url", "http://testserver/api/packages/3/"), + ("purl", "pkg:deb/debian/mimetex@1.50-1.1?distro=jessie"), + ] + ), + ], + "unresolved_packages": [], + "cve_id": "CVE-2009-1382", + "summary": "", + "cvss": None, + }, + "CVE-2014-8242": { + "url": "http://testserver/api/vulnerabilities/1/", + "references": [], + "resolved_packages": [], + "unresolved_packages": [ + OrderedDict( + [ + ("url", "http://testserver/api/packages/1/"), + ("purl", "pkg:deb/debian/librsync@0.9.7-10?distro=jessie"), + ] + ) + ], + "cve_id": "CVE-2014-8242", + "summary": "", + "cvss": None, + }, + "RANDOM-CVE": {}, + } + response = self.client.post("/api/vulnerabilities/bulk_search/", request_body).data + assert response == expected_response + + def test_bulk_packages_api(self): + request_body = { + "packages": [ + "pkg:deb/debian/librsync@0.9.7-10?distro=jessie", + "pkg:deb/debian/mimetex@1.50-1.1?distro=jessie", + ] + } + response = self.client.post("/api/packages/bulk_search/", request_body).data + expected_response = { + "pkg:deb/debian/librsync@0.9.7-10?distro=jessie": { + "url": "http://testserver/api/packages/1/", + "type": "deb", + "namespace": "debian", + "name": "librsync", + "version": "0.9.7-10", + "qualifiers": {"distro": "jessie"}, + "subpath": "", + "purl": "pkg:deb/debian/librsync@0.9.7-10?distro=jessie", + "resolved_vulnerabilities": [], + "unresolved_vulnerabilities": [ + OrderedDict( + [ + ("url", "http://testserver/api/vulnerabilities/1/"), + ("vulnerability_id", "CVE-2014-8242"), + ] + ) + ], + }, + "pkg:deb/debian/mimetex@1.50-1.1?distro=jessie": { + "url": "http://testserver/api/packages/3/", + "type": "deb", + "namespace": "debian", + "name": "mimetex", + "version": "1.50-1.1", + "qualifiers": {"distro": "jessie"}, + "subpath": "", + "purl": "pkg:deb/debian/mimetex@1.50-1.1?distro=jessie", + "resolved_vulnerabilities": [ + OrderedDict( + [ + ("url", "http://testserver/api/vulnerabilities/2/"), + ("vulnerability_id", "CVE-2009-1382"), + ] + ), + OrderedDict( + [ + ("url", "http://testserver/api/vulnerabilities/3/"), + ("vulnerability_id", "CVE-2009-2459"), + ] + ), + ], + "unresolved_vulnerabilities": [], + }, + } + + assert response == expected_response From 8df1bf2049a45946de6d42e3cb5171371802ea72 Mon Sep 17 00:00:00 2001 From: Shivam Sandbhor Date: Sat, 16 Jan 2021 21:18:17 +0530 Subject: [PATCH 6/7] Handle erroneous requests and add tests for this for bulk api Signed-off-by: Shivam Sandbhor --- vulnerabilities/api.py | 29 ++++++++++---- vulnerabilities/tests/test_api.py | 65 ++++++++++++++++++++++++++++++- 2 files changed, 84 insertions(+), 10 deletions(-) diff --git a/vulnerabilities/api.py b/vulnerabilities/api.py index b65b00a43..2d8fecc32 100644 --- a/vulnerabilities/api.py +++ b/vulnerabilities/api.py @@ -133,16 +133,23 @@ class PackageViewSet(viewsets.ReadOnlyModelViewSet): def bulk_search(self, request): filter_list = Q() response = {} - # TODO: Do some validation here of request body - - for purl in request.POST.getlist("packages"): - filter_list |= Q( - **{k: v for k, v in PackageURL.from_string(purl).to_dict().items() if v} + if not isinstance(request.data.get("packages"), list): + return Response( + status=400, + data={ + "Error": "Request needs to contain a key 'packages' which has the value of a list of package urls" # nopep8 + }, ) + for purl in request.data["packages"]: + try: + filter_list |= Q( + **{k: v for k, v in PackageURL.from_string(purl).to_dict().items() if v} + ) + except ValueError as ve: + return Response(status=400, data={"Error": str(ve)}) # This handles the case when the said purl doesnt exist in db response[purl] = {} - res = Package.objects.filter(filter_list) for p in res: response[p.package_url] = PackageSerializer(p, context={"request": request}).data @@ -169,9 +176,15 @@ class VulnerabilityViewSet(viewsets.ReadOnlyModelViewSet): def bulk_search(self, request): filter_list = [] response = {} - # TODO: Do some validation here of request body + if not isinstance(request.data.get("vulnerabilities"), list): + return Response( + status=400, + data={ + "Error": "Request needs to contain a key 'vulnerabilities' which has the value of a list of vulnerability ids" # nopep8 + }, + ) - for cve_id in request.POST.getlist("vulnerabilities"): + for cve_id in request.data["vulnerabilities"]: filter_list.append(cve_id) # This handles the case when the said cve doesnt exist in db response[cve_id] = {} diff --git a/vulnerabilities/tests/test_api.py b/vulnerabilities/tests/test_api.py index 4f0f35096..37153d890 100644 --- a/vulnerabilities/tests/test_api.py +++ b/vulnerabilities/tests/test_api.py @@ -239,7 +239,9 @@ def test_bulk_vulnerabilities_api(self): }, "RANDOM-CVE": {}, } - response = self.client.post("/api/vulnerabilities/bulk_search/", request_body).data + response = self.client.post( + "/api/vulnerabilities/bulk_search/", data=request_body, content_type="application/json" + ).data assert response == expected_response def test_bulk_packages_api(self): @@ -249,7 +251,9 @@ def test_bulk_packages_api(self): "pkg:deb/debian/mimetex@1.50-1.1?distro=jessie", ] } - response = self.client.post("/api/packages/bulk_search/", request_body).data + response = self.client.post( + "/api/packages/bulk_search/", data=request_body, content_type="application/json" + ).data expected_response = { "pkg:deb/debian/librsync@0.9.7-10?distro=jessie": { "url": "http://testserver/api/packages/1/", @@ -298,3 +302,60 @@ def test_bulk_packages_api(self): } assert response == expected_response + + def test_invalid_request_bulk_packages(self): + error_response = { + "Error": "Request needs to contain a key 'packages' which has the value of a list of package urls" # nopep8 + } + invalid_key_request_data = {"pkg": []} + response = self.client.post( + "/api/packages/bulk_search/", + data=invalid_key_request_data, + content_type="application/json", + ).data + assert response == error_response + + valid_key_invalid_datatype_request_data = {"packages": {}} + response = self.client.post( + "/api/packages/bulk_search/", + data=valid_key_invalid_datatype_request_data, + content_type="application/json", + ).data + assert response == error_response + + invalid_purl_request_data = { + "packages": [ + "pkg:deb/debian/librsync@0.9.7-10?distro=jessie", + "pg:deb/debian/mimetex@1.50-1.1?distro=jessie", + ] + } + response = self.client.post( + "/api/packages/bulk_search/", + data=invalid_purl_request_data, + content_type="application/json", + ).data + purl_error_respones = { + "Error": "purl is missing the required \"pkg\" scheme component: 'pg:deb/debian/mimetex@1.50-1.1?distro=jessie'." # nopep8 + } + assert response == purl_error_respones + + def test_invalid_request_bulk_vulnerabilities(self): + error_response = { + "Error": "Request needs to contain a key 'vulnerabilities' which has the value of a list of vulnerability ids" # nopep8 + } + + wrong_key_data = {"xyz": []} + response = self.client.post( + "/api/vulnerabilities/bulk_search/", + data=wrong_key_data, + content_type="application/json", + ).data + assert response == error_response + + wrong_type_data = {"vulnerabilities": {}} + response = self.client.post( + "/api/vulnerabilities/bulk_search/", + data=wrong_key_data, + content_type="application/json", + ).data + assert response == error_response From 9ab1c2f2088fd7d0373838835c999d7dda1a7997 Mon Sep 17 00:00:00 2001 From: Shivam Sandbhor Date: Sun, 17 Jan 2021 17:42:12 +0530 Subject: [PATCH 7/7] Trim api response and add documentation for the bulk endpoints Signed-off-by: Shivam Sandbhor --- vulnerabilities/api.py | 54 +++++++++++++++++++++++-------- vulnerabilities/tests/test_api.py | 29 ++--------------- 2 files changed, 43 insertions(+), 40 deletions(-) diff --git a/vulnerabilities/api.py b/vulnerabilities/api.py index 2d8fecc32..8eb02ca77 100644 --- a/vulnerabilities/api.py +++ b/vulnerabilities/api.py @@ -22,6 +22,7 @@ # Visit https://github.com/nexB/vulnerablecode/ for support and download. from urllib.parse import unquote +from typing import List from django.db.models import Q from django.urls import reverse @@ -31,11 +32,17 @@ from rest_framework import viewsets from rest_framework.decorators import action from rest_framework.response import Response +from drf_spectacular.utils import extend_schema, inline_serializer +from drf_spectacular.types import OpenApiTypes from vulnerabilities.models import Package from vulnerabilities.models import Vulnerability from vulnerabilities.models import VulnerabilityReference +# This serializer is used for the bulk apis, to prevent wrong auto documentation +# TODO: Fix the swagger documentation for bulk apis +placeholder_serializer = inline_serializer(name="Placeholder", fields={}) + class VulnerabilityReferenceSerializer(serializers.ModelSerializer): class Meta: @@ -63,8 +70,8 @@ class Meta: fields = ["url", "vulnerability_id"] -class VulnerabilitySerializer(serializers.HyperlinkedModelSerializer): - references = VulnerabilityReferenceSerializer(many=True, source="vulnerabilityreference_set") +class MinimalVulnerabilitySerializer(serializers.HyperlinkedModelSerializer): + resolved_packages = HyperLinkedPackageSerializer( many=True, source="resolved_to", read_only=True ) @@ -72,36 +79,43 @@ class VulnerabilitySerializer(serializers.HyperlinkedModelSerializer): many=True, source="vulnerable_to", read_only=True ) + class Meta: + model = Vulnerability + fields = ["url", "unresolved_packages", "resolved_packages"] + + +class VulnerabilitySerializer(MinimalVulnerabilitySerializer): + references = VulnerabilityReferenceSerializer(many=True, source="vulnerabilityreference_set") + class Meta: model = Vulnerability fields = "__all__" -class PackageSerializer(serializers.HyperlinkedModelSerializer): +class MinimalPackageSerializer(serializers.HyperlinkedModelSerializer): unresolved_vulnerabilities = HyperLinkedVulnerabilitySerializer( many=True, source="vulnerable_to", read_only=True ) resolved_vulnerabilities = HyperLinkedVulnerabilitySerializer( many=True, source="resolved_to", read_only=True ) - purl = serializers.CharField(source="package_url") class Meta: model = Package fields = [ - "url", - "type", - "namespace", - "name", - "version", - "qualifiers", - "subpath", - "purl", "resolved_vulnerabilities", "unresolved_vulnerabilities", ] +class PackageSerializer(MinimalPackageSerializer): + purl = serializers.CharField(source="package_url") + + class Meta: + model = Package + exclude = ["vulnerabilities"] + + class PackageFilterSet(filters.FilterSet): purl = filters.CharFilter(method="filter_purl") @@ -129,8 +143,13 @@ class PackageViewSet(viewsets.ReadOnlyModelViewSet): filter_backends = (filters.DjangoFilterBackend,) filterset_class = PackageFilterSet + # TODO: Fix the swagger documentation for this endpoint + @extend_schema(request=placeholder_serializer, responses=placeholder_serializer) @action(detail=False, methods=["post"]) def bulk_search(self, request): + """ + See https://github.com/nexB/vulnerablecode/pull/303#issuecomment-761801639 for docs + """ filter_list = Q() response = {} if not isinstance(request.data.get("packages"), list): @@ -152,7 +171,7 @@ def bulk_search(self, request): response[purl] = {} res = Package.objects.filter(filter_list) for p in res: - response[p.package_url] = PackageSerializer(p, context={"request": request}).data + response[p.package_url] = MinimalPackageSerializer(p, context={"request": request}).data return Response(response) @@ -172,8 +191,13 @@ class VulnerabilityViewSet(viewsets.ReadOnlyModelViewSet): filter_backends = (filters.DjangoFilterBackend,) filterset_class = VulnerabilityFilterSet + # TODO: Fix the swagger documentation for this endpoint + @extend_schema(request=placeholder_serializer, responses=placeholder_serializer) @action(detail=False, methods=["post"]) def bulk_search(self, request): + """ + See https://github.com/nexB/vulnerablecode/pull/303#issuecomment-761801619 for docs + """ filter_list = [] response = {} if not isinstance(request.data.get("vulnerabilities"), list): @@ -190,5 +214,7 @@ def bulk_search(self, request): response[cve_id] = {} res = Vulnerability.objects.filter(cve_id__in=filter_list) for vuln in res: - response[vuln.cve_id] = VulnerabilitySerializer(vuln, context={"request": request}).data + response[vuln.cve_id] = MinimalVulnerabilitySerializer( + vuln, context={"request": request} + ).data return Response(response) diff --git a/vulnerabilities/tests/test_api.py b/vulnerabilities/tests/test_api.py index 37153d890..092349e42 100644 --- a/vulnerabilities/tests/test_api.py +++ b/vulnerabilities/tests/test_api.py @@ -200,8 +200,6 @@ def test_bulk_vulnerabilities_api(self): request_body = {"vulnerabilities": ["CVE-2009-1382", "CVE-2014-8242", "RANDOM-CVE"]} expected_response = { "CVE-2009-1382": { - "url": "http://testserver/api/vulnerabilities/2/", - "references": [], "resolved_packages": [ OrderedDict( [ @@ -217,13 +215,9 @@ def test_bulk_vulnerabilities_api(self): ), ], "unresolved_packages": [], - "cve_id": "CVE-2009-1382", - "summary": "", - "cvss": None, + "url": "http://testserver/api/vulnerabilities/2/", }, "CVE-2014-8242": { - "url": "http://testserver/api/vulnerabilities/1/", - "references": [], "resolved_packages": [], "unresolved_packages": [ OrderedDict( @@ -233,12 +227,11 @@ def test_bulk_vulnerabilities_api(self): ] ) ], - "cve_id": "CVE-2014-8242", - "summary": "", - "cvss": None, + "url": "http://testserver/api/vulnerabilities/1/", }, "RANDOM-CVE": {}, } + response = self.client.post( "/api/vulnerabilities/bulk_search/", data=request_body, content_type="application/json" ).data @@ -256,14 +249,6 @@ def test_bulk_packages_api(self): ).data expected_response = { "pkg:deb/debian/librsync@0.9.7-10?distro=jessie": { - "url": "http://testserver/api/packages/1/", - "type": "deb", - "namespace": "debian", - "name": "librsync", - "version": "0.9.7-10", - "qualifiers": {"distro": "jessie"}, - "subpath": "", - "purl": "pkg:deb/debian/librsync@0.9.7-10?distro=jessie", "resolved_vulnerabilities": [], "unresolved_vulnerabilities": [ OrderedDict( @@ -275,14 +260,6 @@ def test_bulk_packages_api(self): ], }, "pkg:deb/debian/mimetex@1.50-1.1?distro=jessie": { - "url": "http://testserver/api/packages/3/", - "type": "deb", - "namespace": "debian", - "name": "mimetex", - "version": "1.50-1.1", - "qualifiers": {"distro": "jessie"}, - "subpath": "", - "purl": "pkg:deb/debian/mimetex@1.50-1.1?distro=jessie", "resolved_vulnerabilities": [ OrderedDict( [