Skip to content

Commit

Permalink
Add advisories API in V2
Browse files Browse the repository at this point in the history
Signed-off-by: Tushar Goel <[email protected]>
  • Loading branch information
TG1999 committed Jan 23, 2025
1 parent 56eb442 commit 9c5dee8
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 0 deletions.
22 changes: 22 additions & 0 deletions vulnerabilities/api_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from rest_framework.response import Response
from rest_framework.reverse import reverse

from vulnerabilities.models import Advisory
from vulnerabilities.models import CodeFix
from vulnerabilities.models import Package
from vulnerabilities.models import Vulnerability
Expand Down Expand Up @@ -606,3 +607,24 @@ def get_queryset(self):
affected_package_vulnerability__vulnerability__vulnerability_id=vulnerability_id
)
return queryset


class AdvisorySerializer(serializers.ModelSerializer):
class Meta:
model = Advisory
fields = ["aliases", "summary", "affected_packages", "references", "date_published", "url"]


class AdvisoryViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = AdvisorySerializer

def get_queryset(self):
return Advisory.objects.only(
"aliases", "summary", "affected_packages", "references", "date_published", "url"
).order_by("-date_published")

def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
page = self.paginate_queryset(queryset)
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
59 changes: 59 additions & 0 deletions vulnerabilities/tests/test_api_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@
#

from django.db.models import Prefetch
from django.test import TestCase
from django.urls import reverse
from django.utils import timezone
from packageurl import PackageURL
from rest_framework import status
from rest_framework.test import APIClient
from rest_framework.test import APITestCase

from vulnerabilities.api_v2 import PackageV2Serializer
from vulnerabilities.api_v2 import VulnerabilityListSerializer
from vulnerabilities.models import Advisory
from vulnerabilities.models import Alias
from vulnerabilities.models import ApiUser
from vulnerabilities.models import Package
Expand Down Expand Up @@ -662,3 +665,59 @@ def test_lookup_with_invalid_purl_format(self):
self.assertEqual(response.status_code, status.HTTP_200_OK)
# No packages or vulnerabilities should be returned
self.assertEqual(len(response.data), 0)


class AdvisoryAPITest(TestCase):
def setUp(self):
self.user = ApiUser.objects.create_api_user(username="[email protected]")
self.auth = f"Token {self.user.auth_token.key}"
self.client = APIClient(enforce_csrf_checks=True)
self.client.credentials(HTTP_AUTHORIZATION=self.auth)

self.now = timezone.now()
self.advisories = []
for i in range(10):
advisory = Advisory.objects.create(
aliases=[f"CVE-2020-{i}"],
summary=f"Test Advisory {i}",
affected_packages=[{"package_url": f"pkg:npm/package{i}@1.0.0"}],
references=[{"url": f"https://example.com/vuln/{i}"}],
date_published=self.now,
date_collected=self.now,
created_by="test_importer",
url=f"https://example.com/{i}",
)
self.advisories.append(advisory)

def test_advisory_list(self):
with self.assertNumQueries(5): # save + auth + count + data + release
response = self.client.get("/api/v2/advisories/", format="json")
self.assertEqual(200, response.status_code)
data = response.json()
self.assertEqual(10, data["count"])
self.assertEqual(10, len(data["results"]))

first_result = data["results"][0]
expected_fields = {
"aliases",
"summary",
"affected_packages",
"references",
"date_published",
"url",
}
self.assertEqual(expected_fields, set(first_result.keys()))

def test_advisory_pagination(self):
with self.assertNumQueries(5):
response = self.client.get("/api/v2/advisories/?page_size=5", format="json")
self.assertEqual(200, response.status_code)
data = response.json()
self.assertEqual(10, data["count"])
self.assertEqual(5, len(data["results"]))
self.assertIsNotNone(data["next"])
self.assertIsNone(data["previous"])

def test_advisory_invalid_page(self):
response = self.client.get("/api/v2/advisories/?page=999", format="json")
self.assertEqual(404, response.status_code)
2 changes: 2 additions & 0 deletions vulnerablecode/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from vulnerabilities.api import CPEViewSet
from vulnerabilities.api import PackageViewSet
from vulnerabilities.api import VulnerabilityViewSet
from vulnerabilities.api_v2 import AdvisoryViewSet
from vulnerabilities.api_v2 import CodeFixViewSet
from vulnerabilities.api_v2 import PackageV2ViewSet
from vulnerabilities.api_v2 import VulnerabilityV2ViewSet
Expand Down Expand Up @@ -50,6 +51,7 @@ def __init__(self, *args, **kwargs):
api_v2_router.register("packages", PackageV2ViewSet, basename="package-v2")
api_v2_router.register("vulnerabilities", VulnerabilityV2ViewSet, basename="vulnerability-v2")
api_v2_router.register("codefixes", CodeFixViewSet, basename="codefix")
api_v2_router.register("advisories", AdvisoryViewSet, basename="advisory")


urlpatterns = [
Expand Down

0 comments on commit 9c5dee8

Please sign in to comment.