Skip to content

Commit 9c5dee8

Browse files
committed
Add advisories API in V2
Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
1 parent 56eb442 commit 9c5dee8

File tree

3 files changed

+83
-0
lines changed

3 files changed

+83
-0
lines changed

vulnerabilities/api_v2.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from rest_framework.response import Response
2222
from rest_framework.reverse import reverse
2323

24+
from vulnerabilities.models import Advisory
2425
from vulnerabilities.models import CodeFix
2526
from vulnerabilities.models import Package
2627
from vulnerabilities.models import Vulnerability
@@ -606,3 +607,24 @@ def get_queryset(self):
606607
affected_package_vulnerability__vulnerability__vulnerability_id=vulnerability_id
607608
)
608609
return queryset
610+
611+
612+
class AdvisorySerializer(serializers.ModelSerializer):
613+
class Meta:
614+
model = Advisory
615+
fields = ["aliases", "summary", "affected_packages", "references", "date_published", "url"]
616+
617+
618+
class AdvisoryViewSet(viewsets.ReadOnlyModelViewSet):
619+
serializer_class = AdvisorySerializer
620+
621+
def get_queryset(self):
622+
return Advisory.objects.only(
623+
"aliases", "summary", "affected_packages", "references", "date_published", "url"
624+
).order_by("-date_published")
625+
626+
def list(self, request, *args, **kwargs):
627+
queryset = self.get_queryset()
628+
page = self.paginate_queryset(queryset)
629+
serializer = self.get_serializer(page, many=True)
630+
return self.get_paginated_response(serializer.data)

vulnerabilities/tests/test_api_v2.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@
88
#
99

1010
from django.db.models import Prefetch
11+
from django.test import TestCase
1112
from django.urls import reverse
13+
from django.utils import timezone
1214
from packageurl import PackageURL
1315
from rest_framework import status
1416
from rest_framework.test import APIClient
1517
from rest_framework.test import APITestCase
1618

1719
from vulnerabilities.api_v2 import PackageV2Serializer
1820
from vulnerabilities.api_v2 import VulnerabilityListSerializer
21+
from vulnerabilities.models import Advisory
1922
from vulnerabilities.models import Alias
2023
from vulnerabilities.models import ApiUser
2124
from vulnerabilities.models import Package
@@ -662,3 +665,59 @@ def test_lookup_with_invalid_purl_format(self):
662665
self.assertEqual(response.status_code, status.HTTP_200_OK)
663666
# No packages or vulnerabilities should be returned
664667
self.assertEqual(len(response.data), 0)
668+
669+
670+
class AdvisoryAPITest(TestCase):
671+
def setUp(self):
672+
self.user = ApiUser.objects.create_api_user(username="test@test.com")
673+
self.auth = f"Token {self.user.auth_token.key}"
674+
self.client = APIClient(enforce_csrf_checks=True)
675+
self.client.credentials(HTTP_AUTHORIZATION=self.auth)
676+
677+
self.now = timezone.now()
678+
self.advisories = []
679+
for i in range(10):
680+
advisory = Advisory.objects.create(
681+
aliases=[f"CVE-2020-{i}"],
682+
summary=f"Test Advisory {i}",
683+
affected_packages=[{"package_url": f"pkg:npm/package{i}@1.0.0"}],
684+
references=[{"url": f"https://example.com/vuln/{i}"}],
685+
date_published=self.now,
686+
date_collected=self.now,
687+
created_by="test_importer",
688+
url=f"https://example.com/{i}",
689+
)
690+
self.advisories.append(advisory)
691+
692+
def test_advisory_list(self):
693+
with self.assertNumQueries(5): # save + auth + count + data + release
694+
response = self.client.get("/api/v2/advisories/", format="json")
695+
self.assertEqual(200, response.status_code)
696+
data = response.json()
697+
self.assertEqual(10, data["count"])
698+
self.assertEqual(10, len(data["results"]))
699+
700+
first_result = data["results"][0]
701+
expected_fields = {
702+
"aliases",
703+
"summary",
704+
"affected_packages",
705+
"references",
706+
"date_published",
707+
"url",
708+
}
709+
self.assertEqual(expected_fields, set(first_result.keys()))
710+
711+
def test_advisory_pagination(self):
712+
with self.assertNumQueries(5):
713+
response = self.client.get("/api/v2/advisories/?page_size=5", format="json")
714+
self.assertEqual(200, response.status_code)
715+
data = response.json()
716+
self.assertEqual(10, data["count"])
717+
self.assertEqual(5, len(data["results"]))
718+
self.assertIsNotNone(data["next"])
719+
self.assertIsNone(data["previous"])
720+
721+
def test_advisory_invalid_page(self):
722+
response = self.client.get("/api/v2/advisories/?page=999", format="json")
723+
self.assertEqual(404, response.status_code)

vulnerablecode/urls.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from vulnerabilities.api import CPEViewSet
2121
from vulnerabilities.api import PackageViewSet
2222
from vulnerabilities.api import VulnerabilityViewSet
23+
from vulnerabilities.api_v2 import AdvisoryViewSet
2324
from vulnerabilities.api_v2 import CodeFixViewSet
2425
from vulnerabilities.api_v2 import PackageV2ViewSet
2526
from vulnerabilities.api_v2 import VulnerabilityV2ViewSet
@@ -50,6 +51,7 @@ def __init__(self, *args, **kwargs):
5051
api_v2_router.register("packages", PackageV2ViewSet, basename="package-v2")
5152
api_v2_router.register("vulnerabilities", VulnerabilityV2ViewSet, basename="vulnerability-v2")
5253
api_v2_router.register("codefixes", CodeFixViewSet, basename="codefix")
54+
api_v2_router.register("advisories", AdvisoryViewSet, basename="advisory")
5355

5456

5557
urlpatterns = [

0 commit comments

Comments
 (0)