Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add advisories API in V2 #1757

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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="test@test.com")
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