Skip to content

Commit 5e3cbe5

Browse files
committed
Add tests for vulnerability endpoint
And address review comments Signed-off-by: Tushar Goel <[email protected]>
1 parent 1907ae4 commit 5e3cbe5

File tree

2 files changed

+66
-35
lines changed

2 files changed

+66
-35
lines changed

vulnerabilities/api.py

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
from urllib.parse import unquote
1111

12+
from django.db.models import Prefetch
13+
from django.db.models import Q
1214
from django_filters import rest_framework as filters
1315
from packageurl import PackageURL
1416
from rest_framework import serializers
@@ -50,34 +52,7 @@ class Meta:
5052
fields = ["url", "purl"]
5153

5254

53-
class FilteredPackageListSerializer(serializers.ListSerializer):
54-
def to_representation(self, data):
55-
params = self.context["request"].query_params
56-
name = params.get("name")
57-
if name:
58-
data = data.filter(name=name)
59-
namespace = params.get("namespace")
60-
if namespace:
61-
data = data.filter(namespace=namespace)
62-
type = params.get("type")
63-
if type:
64-
data = data.filter(type=type)
65-
return super(FilteredPackageListSerializer, self).to_representation(data)
66-
67-
68-
class FixedPackageSerializer(serializers.ModelSerializer):
69-
70-
purl = serializers.CharField(source="package_url")
71-
72-
class Meta:
73-
list_serializer_class = FilteredPackageListSerializer
74-
model = Package
75-
fields = ["url", "purl"]
76-
77-
78-
class MinimalVulnerabilitySerializerWithReferencesAndSummary(
79-
serializers.HyperlinkedModelSerializer
80-
):
55+
class VulnSerializerRefsAndSummary(serializers.HyperlinkedModelSerializer):
8156
"""
8257
Used for nesting inside package focused APIs.
8358
"""
@@ -99,7 +74,7 @@ class Meta:
9974
fields = ["url", "vulnerability_id"]
10075

10176

102-
class MinimalPackageSerializerWithFixedVulnerabilities(serializers.HyperlinkedModelSerializer):
77+
class PackageSerializerFixedVulns(serializers.HyperlinkedModelSerializer):
10378
"""
10479
Used for nesting inside vulnerability focused APIs.
10580
"""
@@ -126,7 +101,9 @@ class Meta:
126101

127102
class VulnerabilitySerializer(serializers.HyperlinkedModelSerializer):
128103

129-
fixed_packages = FixedPackageSerializer(many=True, source="resolved_to", read_only=True)
104+
fixed_packages = MinimalPackageSerializer(
105+
many=True, source="filtered_fixed_packages", read_only=True
106+
)
130107
affected_packages = MinimalPackageSerializer(many=True, source="vulnerable_to", read_only=True)
131108

132109
references = VulnerabilityReferenceSerializer(many=True, source="vulnerabilityreference_set")
@@ -152,13 +129,13 @@ def to_representation(self, instance):
152129
return data
153130

154131
purl = serializers.CharField(source="package_url")
155-
affected_by_vulnerabilities = MinimalVulnerabilitySerializerWithReferencesAndSummary(
132+
affected_by_vulnerabilities = VulnSerializerRefsAndSummary(
156133
many=True, source="vulnerable_to", read_only=True
157134
)
158-
fixing_vulnerabilities = MinimalVulnerabilitySerializerWithReferencesAndSummary(
135+
fixing_vulnerabilities = VulnSerializerRefsAndSummary(
159136
many=True, source="resolved_to", read_only=True
160137
)
161-
fixed_packages = MinimalPackageSerializerWithFixedVulnerabilities(many=True, read_only=True)
138+
fixed_packages = PackageSerializerFixedVulns(many=True, read_only=True)
162139

163140
class Meta:
164141
model = Package
@@ -247,7 +224,27 @@ class Meta:
247224

248225

249226
class VulnerabilityViewSet(viewsets.ReadOnlyModelViewSet):
250-
queryset = Vulnerability.objects.all()
227+
def get_queryset(self):
228+
params = self.request.query_params
229+
query = Q()
230+
name = params.get("name")
231+
if name:
232+
query &= Q(name=name)
233+
namespace = params.get("namespace")
234+
if namespace:
235+
query &= Q(namespace=namespace)
236+
type = params.get("type")
237+
if type:
238+
query &= Q(type=type)
239+
queryset = Vulnerability.objects.prefetch_related(
240+
Prefetch(
241+
"packages",
242+
queryset=Package.objects.filter(query, packagerelatedvulnerability__fix=True),
243+
to_attr="filtered_fixed_packages",
244+
)
245+
)
246+
return queryset
247+
251248
serializer_class = VulnerabilitySerializer
252249
paginate_by = 50
253250
filter_backends = (filters.DjangoFilterBackend,)

vulnerabilities/tests/test_fix_api.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ def setUp(self):
2626
summary=str(i),
2727
)
2828
self.vulnerability = Vulnerability.objects.create(summary="test")
29+
self.pkg1 = Package.objects.create(name="flask", type="pypi", version="0.1.2")
30+
self.pkg2 = Package.objects.create(name="flask", type="debian", version="0.1.2")
31+
for pkg in [self.pkg1, self.pkg2]:
32+
PackageRelatedVulnerability.objects.create(
33+
package=pkg, vulnerability=self.vulnerability, fix=True
34+
)
2935

3036
def test_api_status(self):
3137
response = self.client.get("/api/vulnerabilities/", format="json")
@@ -44,7 +50,35 @@ def test_api_with_single_vulnerability(self):
4450
"vulnerability_id": f"VULCOID-{int_to_base36(self.vulnerability.id).upper()}",
4551
"summary": "test",
4652
"aliases": [],
47-
"fixed_packages": [],
53+
"fixed_packages": [
54+
{
55+
"url": f"http://testserver/api/packages/{self.pkg1.id}",
56+
"purl": "pkg:pypi/[email protected]",
57+
},
58+
{
59+
"url": f"http://testserver/api/packages/{self.pkg2.id}",
60+
"purl": "pkg:debian/[email protected]",
61+
},
62+
],
63+
"affected_packages": [],
64+
"references": [],
65+
}
66+
67+
def test_api_with_single_vulnerability_with_filters(self):
68+
response = self.client.get(
69+
f"/api/vulnerabilities/{self.vulnerability.id}?type=pypi", format="json"
70+
).data
71+
assert response == {
72+
"url": f"http://testserver/api/vulnerabilities/{self.vulnerability.id}",
73+
"vulnerability_id": f"VULCOID-{int_to_base36(self.vulnerability.id).upper()}",
74+
"summary": "test",
75+
"aliases": [],
76+
"fixed_packages": [
77+
{
78+
"url": f"http://testserver/api/packages/{self.pkg1.id}",
79+
"purl": "pkg:pypi/[email protected]",
80+
},
81+
],
4882
"affected_packages": [],
4983
"references": [],
5084
}

0 commit comments

Comments
 (0)