From c1364beee1a62bf0d21820142ba19e3b16310a81 Mon Sep 17 00:00:00 2001 From: Tushar Goel Date: Mon, 19 Feb 2024 11:07:05 +0530 Subject: [PATCH 1/6] Add vulnerability_url in API Signed-off-by: Tushar Goel --- vulnerabilities/api.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/vulnerabilities/api.py b/vulnerabilities/api.py index 30ca4cb9f..4157e6dab 100644 --- a/vulnerabilities/api.py +++ b/vulnerabilities/api.py @@ -20,6 +20,7 @@ from rest_framework import viewsets from rest_framework.decorators import action from rest_framework.response import Response +from rest_framework.reverse import reverse from rest_framework.throttling import AnonRateThrottle from rest_framework.throttling import UserRateThrottle @@ -154,10 +155,14 @@ class VulnerabilitySerializer(serializers.HyperlinkedModelSerializer): def to_representation(self, instance): representation = super().to_representation(instance) - # Exclude None values from the weaknesses list weaknesses = representation.get("weaknesses", []) representation["weaknesses"] = [weakness for weakness in weaknesses if weakness is not None] + request = self.context.get("request") + vulnerability_id = representation.get("vulnerability_id") + vulnerability_url = reverse("vulnerability_details", kwargs={"vulnerability_id": vulnerability_id}, request=request) + representation["vulnerability_url"] = vulnerability_url + return representation class Meta: From 00e9231f1f72ddaec7e41313e3311949b5200858 Mon Sep 17 00:00:00 2001 From: Tushar Goel Date: Mon, 19 Feb 2024 11:10:22 +0530 Subject: [PATCH 2/6] Add package_url in API Signed-off-by: Tushar Goel --- vulnerabilities/api.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vulnerabilities/api.py b/vulnerabilities/api.py index 4157e6dab..b5ff8dce7 100644 --- a/vulnerabilities/api.py +++ b/vulnerabilities/api.py @@ -187,6 +187,12 @@ class PackageSerializer(serializers.HyperlinkedModelSerializer): def to_representation(self, instance): data = super().to_representation(instance) data["qualifiers"] = normalize_qualifiers(data["qualifiers"], encode=False) + + request = self.context.get("request") + purl = data.get("purl") + package_url = reverse("package_details", kwargs={"purl": purl}, request=request) + data["package_url"] = package_url + return data next_non_vulnerable_version = serializers.SerializerMethodField("get_next_non_vulnerable") From f40b24e1bd8069cf169c8dd4ee965c8e328a361d Mon Sep 17 00:00:00 2001 From: Tushar Goel Date: Mon, 19 Feb 2024 12:41:57 +0530 Subject: [PATCH 3/6] Fix tests Signed-off-by: Tushar Goel --- vulnerabilities/api.py | 49 +++++++++++++++++++++++++------ vulnerabilities/tests/test_api.py | 15 ++++++++-- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/vulnerabilities/api.py b/vulnerabilities/api.py index b5ff8dce7..ed51b7c3a 100644 --- a/vulnerabilities/api.py +++ b/vulnerabilities/api.py @@ -54,6 +54,15 @@ class MinimalPackageSerializer(serializers.HyperlinkedModelSerializer): Used for nesting inside vulnerability focused APIs. """ + def to_representation(self, instance): + data = super().to_representation(instance) + + request = self.context.get("request") + package_url = get_package_details_url(data=data, request=request) + data["package_url"] = package_url + + return data + def get_affected_vulnerabilities(self, package): parent_affected_vulnerabilities = package.fixed_package_details.get("vulnerabilities") or [] @@ -85,6 +94,13 @@ class MinimalVulnerabilitySerializer(serializers.HyperlinkedModelSerializer): Lookup vulnerabilities by aliases (such as a CVE). """ + def to_representation(self, instance): + data = super().to_representation(instance) + request = self.context.get("request") + vulnerability_url = get_vulnerability_details_url(request=request, data=data) + data["vulnerability_url"] = vulnerability_url + return data + class Meta: model = Vulnerability fields = ["url", "vulnerability_id"] @@ -109,6 +125,9 @@ def to_representation(self, instance): data = super().to_representation(instance) aliases = [alias["alias"] for alias in data["aliases"]] data["aliases"] = aliases + request = self.context.get("request") + vulnerability_url = get_vulnerability_details_url(request=request, data=data) + data["vulnerability_url"] = vulnerability_url return data fixed_packages = MinimalPackageSerializer( @@ -153,17 +172,16 @@ class VulnerabilitySerializer(serializers.HyperlinkedModelSerializer): weaknesses = WeaknessSerializer(many=True) def to_representation(self, instance): - representation = super().to_representation(instance) + data = super().to_representation(instance) - weaknesses = representation.get("weaknesses", []) - representation["weaknesses"] = [weakness for weakness in weaknesses if weakness is not None] + weaknesses = data.get("weaknesses", []) + data["weaknesses"] = [weakness for weakness in weaknesses if weakness is not None] request = self.context.get("request") - vulnerability_id = representation.get("vulnerability_id") - vulnerability_url = reverse("vulnerability_details", kwargs={"vulnerability_id": vulnerability_id}, request=request) - representation["vulnerability_url"] = vulnerability_url + vulnerability_url = get_vulnerability_details_url(request=request, data=data) + data["vulnerability_url"] = vulnerability_url - return representation + return data class Meta: model = Vulnerability @@ -189,8 +207,7 @@ def to_representation(self, instance): data["qualifiers"] = normalize_qualifiers(data["qualifiers"], encode=False) request = self.context.get("request") - purl = data.get("purl") - package_url = reverse("package_details", kwargs={"purl": purl}, request=request) + package_url = get_package_details_url(request=request, data=data) data["package_url"] = package_url return data @@ -611,3 +628,17 @@ class AliasViewSet(viewsets.ReadOnlyModelViewSet): filter_backends = (filters.DjangoFilterBackend,) filterset_class = AliasFilterSet throttle_classes = [StaffUserRateThrottle, AnonRateThrottle] + + +def get_package_details_url(request, data): + purl = data.get("purl") + package_url = reverse("package_details", kwargs={"purl": purl}, request=request) + return package_url + + +def get_vulnerability_details_url(request, data): + vulnerability_id = data.get("vulnerability_id") + vulnerability_url = reverse( + "vulnerability_details", kwargs={"vulnerability_id": vulnerability_id}, request=request + ) + return vulnerability_url diff --git a/vulnerabilities/tests/test_api.py b/vulnerabilities/tests/test_api.py index f94fe80cb..9189099fe 100644 --- a/vulnerabilities/tests/test_api.py +++ b/vulnerabilities/tests/test_api.py @@ -223,18 +223,21 @@ def test_api_with_single_vulnerability(self): "vulnerability_id": self.vulnerability.vulnerability_id, "summary": "test", "aliases": [], + "vulnerability_url": f"http://testserver/vulnerabilities/{self.vulnerability.vulnerability_id}", "fixed_packages": [ { "url": f"http://testserver/api/packages/{self.pkg2.id}", "purl": "pkg:deb/flask@0.1.2", "is_vulnerable": False, "affected_by_vulnerabilities": [], + "package_url": f"http://testserver/packages/{self.pkg2.purl}", }, { "url": f"http://testserver/api/packages/{self.pkg1.id}", "purl": "pkg:pypi/flask@0.1.2", "is_vulnerable": False, "affected_by_vulnerabilities": [], + "package_url": f"http://testserver/packages/{self.pkg1.purl}", }, ], "affected_packages": [], @@ -257,11 +260,13 @@ def test_api_with_single_vulnerability_with_filters(self): "vulnerability_id": self.vulnerability.vulnerability_id, "summary": "test", "aliases": [], + "vulnerability_url": f"http://testserver/vulnerabilities/{self.vulnerability.vulnerability_id}", "fixed_packages": [ { "url": f"http://testserver/api/packages/{self.pkg1.id}", "purl": "pkg:pypi/flask@0.1.2", "is_vulnerable": False, + "package_url": f"http://testserver/packages/{self.pkg1.purl}", "affected_by_vulnerabilities": [], }, ], @@ -434,6 +439,7 @@ def test_api_with_lesser_and_greater_fixed_by_packages(self): expected_response = { "url": f"http://testserver/api/packages/{self.package_maven_jackson_databind_2_13_1.id}", "purl": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.1", + "package_url": f"http://testserver/packages/{self.package_maven_jackson_databind_2_13_1.purl}", "type": "maven", "namespace": "com.fasterxml.jackson.core", "name": "jackson-databind", @@ -444,15 +450,17 @@ def test_api_with_lesser_and_greater_fixed_by_packages(self): "latest_non_vulnerable_version": "2.14.0-rc1", "affected_by_vulnerabilities": [ { - "url": f"http://testserver/api/vulnerabilities/{self.vuln_VCID_2nyb_8rwu_aaag.id}", + "url": f"http://testserver/api/vulnerabilities/VCID-2nyb-8rwu-aaag", "vulnerability_id": "VCID-2nyb-8rwu-aaag", "summary": "This is VCID-2nyb-8rwu-aaag", + "vulnerability_url": "http://testserver/vulnerabilities/VCID-2nyb-8rwu-aaag", "references": [], "fixed_packages": [ { - "url": f"http://testserver/api/packages/{self.package_maven_jackson_databind_2_13_2.id}", + "url": f"http://testserver/api/packages/pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.2", "purl": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.2", "is_vulnerable": True, + "package_url": "http://testserver/packages/pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.2", "affected_by_vulnerabilities": [ {"vulnerability": "VCID-gqhw-ngh8-aaap"} ], @@ -467,17 +475,20 @@ def test_api_with_lesser_and_greater_fixed_by_packages(self): "vulnerability_id": "VCID-ftmk-wbwx-aaar", "summary": "This is VCID-ftmk-wbwx-aaar", "references": [], + "vulnerability_url": "http://testserver/vulnerabilities/VCID-ftmk-wbwx-aaar", "fixed_packages": [ { "url": f"http://testserver/api/packages/{self.package_maven_jackson_databind_2_12_6.id}", "purl": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.12.6", "is_vulnerable": False, + "package_url": "http://testserver/packages/pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.12.6", "affected_by_vulnerabilities": [], }, { "url": f"http://testserver/api/packages/{self.package_maven_jackson_databind_2_13_1.id}", "purl": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.1", "is_vulnerable": True, + "package_url": "http://testserver/packages/pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.1", "affected_by_vulnerabilities": [ {"vulnerability": "VCID-2nyb-8rwu-aaag"} ], From 2995f5c27ee7c2ed54eef84f23ff3467db5435f9 Mon Sep 17 00:00:00 2001 From: Tushar Goel Date: Tue, 20 Feb 2024 02:36:33 +0530 Subject: [PATCH 4/6] Address review comments Signed-off-by: Tushar Goel --- vulnerabilities/api.py | 31 ++----- vulnerabilities/models.py | 20 +++++ vulnerabilities/tests/test_api.py | 137 +++++++++++++++++++----------- 3 files changed, 114 insertions(+), 74 deletions(-) diff --git a/vulnerabilities/api.py b/vulnerabilities/api.py index ed51b7c3a..eddcc56c0 100644 --- a/vulnerabilities/api.py +++ b/vulnerabilities/api.py @@ -58,8 +58,7 @@ def to_representation(self, instance): data = super().to_representation(instance) request = self.context.get("request") - package_url = get_package_details_url(data=data, request=request) - data["package_url"] = package_url + data["resource_url"] = instance.get_details_url(request=request) return data @@ -97,8 +96,7 @@ class MinimalVulnerabilitySerializer(serializers.HyperlinkedModelSerializer): def to_representation(self, instance): data = super().to_representation(instance) request = self.context.get("request") - vulnerability_url = get_vulnerability_details_url(request=request, data=data) - data["vulnerability_url"] = vulnerability_url + data["resource_url"] = instance.get_details_url(request=request) return data class Meta: @@ -126,8 +124,7 @@ def to_representation(self, instance): aliases = [alias["alias"] for alias in data["aliases"]] data["aliases"] = aliases request = self.context.get("request") - vulnerability_url = get_vulnerability_details_url(request=request, data=data) - data["vulnerability_url"] = vulnerability_url + data["resource_url"] = instance.get_details_url(request=request) return data fixed_packages = MinimalPackageSerializer( @@ -178,8 +175,7 @@ def to_representation(self, instance): data["weaknesses"] = [weakness for weakness in weaknesses if weakness is not None] request = self.context.get("request") - vulnerability_url = get_vulnerability_details_url(request=request, data=data) - data["vulnerability_url"] = vulnerability_url + data["resource_url"] = instance.get_details_url(request=request) return data @@ -207,8 +203,9 @@ def to_representation(self, instance): data["qualifiers"] = normalize_qualifiers(data["qualifiers"], encode=False) request = self.context.get("request") - package_url = get_package_details_url(request=request, data=data) - data["package_url"] = package_url + + request = self.context.get("request") + data["resource_url"] = instance.get_details_url(request=request) return data @@ -628,17 +625,3 @@ class AliasViewSet(viewsets.ReadOnlyModelViewSet): filter_backends = (filters.DjangoFilterBackend,) filterset_class = AliasFilterSet throttle_classes = [StaffUserRateThrottle, AnonRateThrottle] - - -def get_package_details_url(request, data): - purl = data.get("purl") - package_url = reverse("package_details", kwargs={"purl": purl}, request=request) - return package_url - - -def get_vulnerability_details_url(request, data): - vulnerability_id = data.get("vulnerability_id") - vulnerability_url = reverse( - "vulnerability_details", kwargs={"vulnerability_id": vulnerability_id}, request=request - ) - return vulnerability_url diff --git a/vulnerabilities/models.py b/vulnerabilities/models.py index 3dca94cc5..a0fd63a44 100644 --- a/vulnerabilities/models.py +++ b/vulnerabilities/models.py @@ -257,6 +257,18 @@ def get_absolute_url(self): """ return reverse("vulnerability_details", args=[self.vulnerability_id]) + def get_details_url(self, request): + """ + Return this Package details URL. + """ + from rest_framework.reverse import reverse + + return reverse( + "vulnerability_details", + kwargs={"vulnerability_id": self.vulnerability_id}, + request=request, + ) + def get_related_cpes(self): """ Return a list of CPE strings of this vulnerability. @@ -633,6 +645,14 @@ def get_absolute_url(self): """ return reverse("package_details", args=[self.purl]) + def get_details_url(self, request): + """ + Return this Package details URL. + """ + from rest_framework.reverse import reverse + + return reverse("package_details", kwargs={"purl": self.purl}, request=request) + def sort_by_version(self, packages): """ Return a list of `packages` sorted by version. diff --git a/vulnerabilities/tests/test_api.py b/vulnerabilities/tests/test_api.py index 9189099fe..b9b5710f6 100644 --- a/vulnerabilities/tests/test_api.py +++ b/vulnerabilities/tests/test_api.py @@ -9,6 +9,7 @@ import json import os +from collections import OrderedDict from urllib.parse import quote from django.test import TestCase @@ -223,21 +224,21 @@ def test_api_with_single_vulnerability(self): "vulnerability_id": self.vulnerability.vulnerability_id, "summary": "test", "aliases": [], - "vulnerability_url": f"http://testserver/vulnerabilities/{self.vulnerability.vulnerability_id}", + "resource_url": f"http://testserver/vulnerabilities/{self.vulnerability.vulnerability_id}", "fixed_packages": [ { "url": f"http://testserver/api/packages/{self.pkg2.id}", "purl": "pkg:deb/flask@0.1.2", "is_vulnerable": False, "affected_by_vulnerabilities": [], - "package_url": f"http://testserver/packages/{self.pkg2.purl}", + "resource_url": f"http://testserver/packages/{self.pkg2.purl}", }, { "url": f"http://testserver/api/packages/{self.pkg1.id}", "purl": "pkg:pypi/flask@0.1.2", "is_vulnerable": False, "affected_by_vulnerabilities": [], - "package_url": f"http://testserver/packages/{self.pkg1.purl}", + "resource_url": f"http://testserver/packages/{self.pkg1.purl}", }, ], "affected_packages": [], @@ -260,13 +261,13 @@ def test_api_with_single_vulnerability_with_filters(self): "vulnerability_id": self.vulnerability.vulnerability_id, "summary": "test", "aliases": [], - "vulnerability_url": f"http://testserver/vulnerabilities/{self.vulnerability.vulnerability_id}", + "resource_url": f"http://testserver/vulnerabilities/{self.vulnerability.vulnerability_id}", "fixed_packages": [ { "url": f"http://testserver/api/packages/{self.pkg1.id}", "purl": "pkg:pypi/flask@0.1.2", "is_vulnerable": False, - "package_url": f"http://testserver/packages/{self.pkg1.purl}", + "resource_url": f"http://testserver/packages/{self.pkg1.purl}", "affected_by_vulnerabilities": [], }, ], @@ -437,9 +438,8 @@ def test_api_with_lesser_and_greater_fixed_by_packages(self): ).data expected_response = { - "url": f"http://testserver/api/packages/{self.package_maven_jackson_databind_2_13_1.id}", + "url": "http://testserver/api/packages/1", "purl": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.1", - "package_url": f"http://testserver/packages/{self.package_maven_jackson_databind_2_13_1.purl}", "type": "maven", "namespace": "com.fasterxml.jackson.core", "name": "jackson-databind", @@ -449,54 +449,91 @@ def test_api_with_lesser_and_greater_fixed_by_packages(self): "next_non_vulnerable_version": "2.14.0-rc1", "latest_non_vulnerable_version": "2.14.0-rc1", "affected_by_vulnerabilities": [ - { - "url": f"http://testserver/api/vulnerabilities/VCID-2nyb-8rwu-aaag", - "vulnerability_id": "VCID-2nyb-8rwu-aaag", - "summary": "This is VCID-2nyb-8rwu-aaag", - "vulnerability_url": "http://testserver/vulnerabilities/VCID-2nyb-8rwu-aaag", - "references": [], - "fixed_packages": [ - { - "url": f"http://testserver/api/packages/pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.2", - "purl": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.2", - "is_vulnerable": True, - "package_url": "http://testserver/packages/pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.2", - "affected_by_vulnerabilities": [ - {"vulnerability": "VCID-gqhw-ngh8-aaap"} + OrderedDict( + [ + ("url", "http://testserver/api/vulnerabilities/1"), + ("vulnerability_id", "VCID-2nyb-8rwu-aaag"), + ("summary", "This is VCID-2nyb-8rwu-aaag"), + ("references", []), + ( + "fixed_packages", + [ + OrderedDict( + [ + ("url", "http://testserver/api/packages/3"), + ( + "purl", + "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.2", + ), + ("is_vulnerable", True), + ( + "affected_by_vulnerabilities", + [{"vulnerability": "VCID-gqhw-ngh8-aaap"}], + ), + ( + "resource_url", + "http://testserver/packages/pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.2", + ), + ] + ) ], - } - ], - "aliases": ["CVE-2020-36518", "GHSA-57j2-w4cx-62h2"], - } + ), + ("aliases", ["CVE-2020-36518", "GHSA-57j2-w4cx-62h2"]), + ("resource_url", "http://testserver/vulnerabilities/VCID-2nyb-8rwu-aaag"), + ] + ) ], "fixing_vulnerabilities": [ - { - "url": f"http://testserver/api/vulnerabilities/{self.vuln_VCID_ftmk_wbwx_aaar.id}", - "vulnerability_id": "VCID-ftmk-wbwx-aaar", - "summary": "This is VCID-ftmk-wbwx-aaar", - "references": [], - "vulnerability_url": "http://testserver/vulnerabilities/VCID-ftmk-wbwx-aaar", - "fixed_packages": [ - { - "url": f"http://testserver/api/packages/{self.package_maven_jackson_databind_2_12_6.id}", - "purl": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.12.6", - "is_vulnerable": False, - "package_url": "http://testserver/packages/pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.12.6", - "affected_by_vulnerabilities": [], - }, - { - "url": f"http://testserver/api/packages/{self.package_maven_jackson_databind_2_13_1.id}", - "purl": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.1", - "is_vulnerable": True, - "package_url": "http://testserver/packages/pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.1", - "affected_by_vulnerabilities": [ - {"vulnerability": "VCID-2nyb-8rwu-aaag"} + OrderedDict( + [ + ("url", "http://testserver/api/vulnerabilities/3"), + ("vulnerability_id", "VCID-ftmk-wbwx-aaar"), + ("summary", "This is VCID-ftmk-wbwx-aaar"), + ("references", []), + ( + "fixed_packages", + [ + OrderedDict( + [ + ("url", "http://testserver/api/packages/4"), + ( + "purl", + "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.12.6", + ), + ("is_vulnerable", False), + ("affected_by_vulnerabilities", []), + ( + "resource_url", + "http://testserver/packages/pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.12.6", + ), + ] + ), + OrderedDict( + [ + ("url", "http://testserver/api/packages/1"), + ( + "purl", + "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.1", + ), + ("is_vulnerable", True), + ( + "affected_by_vulnerabilities", + [{"vulnerability": "VCID-2nyb-8rwu-aaag"}], + ), + ( + "resource_url", + "http://testserver/packages/pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.1", + ), + ] + ), ], - }, - ], - "aliases": ["CVE-2021-46877", "GHSA-3x8x-79m2-3w2w"], - }, + ), + ("aliases", ["CVE-2021-46877", "GHSA-3x8x-79m2-3w2w"]), + ("resource_url", "http://testserver/vulnerabilities/VCID-ftmk-wbwx-aaar"), + ] + ) ], + "resource_url": "http://testserver/packages/pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.1", } assert response == expected_response From cdd566d5f61daa81fd6fedacb1813b27607ca9d3 Mon Sep 17 00:00:00 2001 From: Tushar Goel Date: Fri, 23 Feb 2024 17:45:41 +0530 Subject: [PATCH 5/6] Address review comments Signed-off-by: Tushar Goel --- vulnerabilities/api.py | 55 +++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/vulnerabilities/api.py b/vulnerabilities/api.py index eddcc56c0..f51998b87 100644 --- a/vulnerabilities/api.py +++ b/vulnerabilities/api.py @@ -49,18 +49,35 @@ class Meta: fields = ["reference_url", "reference_id", "scores", "url"] -class MinimalPackageSerializer(serializers.HyperlinkedModelSerializer): +class BaseResourceSerializer(serializers.HyperlinkedModelSerializer): """ - Used for nesting inside vulnerability focused APIs. + Base serializer containing common methods. """ - def to_representation(self, instance): - data = super().to_representation(instance) + def get_fields(self): + fields = super().get_fields() + fields["resource_url"] = serializers.SerializerMethodField(method_name="get_resource_url") + return fields - request = self.context.get("request") - data["resource_url"] = instance.get_details_url(request=request) + def get_resource_url(self, instance): + """ + Return the instance fully qualified URL including the schema and domain. - return data + Usage: + resource_url = serializers.SerializerMethodField() + """ + resource_url = instance.get_absolute_url() + + if request := self.context.get("request", None): + return request.build_absolute_uri(location=resource_url) + + return resource_url + + +class MinimalPackageSerializer(BaseResourceSerializer): + """ + Used for nesting inside vulnerability focused APIs. + """ def get_affected_vulnerabilities(self, package): parent_affected_vulnerabilities = package.fixed_package_details.get("vulnerabilities") or [] @@ -88,17 +105,11 @@ class Meta: fields = ["url", "purl", "is_vulnerable", "affected_by_vulnerabilities"] -class MinimalVulnerabilitySerializer(serializers.HyperlinkedModelSerializer): +class MinimalVulnerabilitySerializer(BaseResourceSerializer): """ Lookup vulnerabilities by aliases (such as a CVE). """ - def to_representation(self, instance): - data = super().to_representation(instance) - request = self.context.get("request") - data["resource_url"] = instance.get_details_url(request=request) - return data - class Meta: model = Vulnerability fields = ["url", "vulnerability_id"] @@ -114,7 +125,7 @@ class Meta: fields = ["alias"] -class VulnSerializerRefsAndSummary(serializers.HyperlinkedModelSerializer): +class VulnSerializerRefsAndSummary(BaseResourceSerializer): """ Lookup vulnerabilities references by aliases (such as a CVE). """ @@ -123,8 +134,6 @@ def to_representation(self, instance): data = super().to_representation(instance) aliases = [alias["alias"] for alias in data["aliases"]] data["aliases"] = aliases - request = self.context.get("request") - data["resource_url"] = instance.get_details_url(request=request) return data fixed_packages = MinimalPackageSerializer( @@ -158,7 +167,7 @@ def to_representation(self, instance): return representation -class VulnerabilitySerializer(serializers.HyperlinkedModelSerializer): +class VulnerabilitySerializer(BaseResourceSerializer): fixed_packages = MinimalPackageSerializer( many=True, source="filtered_fixed_packages", read_only=True ) @@ -174,9 +183,6 @@ def to_representation(self, instance): weaknesses = data.get("weaknesses", []) data["weaknesses"] = [weakness for weakness in weaknesses if weakness is not None] - request = self.context.get("request") - data["resource_url"] = instance.get_details_url(request=request) - return data class Meta: @@ -193,7 +199,7 @@ class Meta: ] -class PackageSerializer(serializers.HyperlinkedModelSerializer): +class PackageSerializer(BaseResourceSerializer): """ Lookup software package using Package URLs """ @@ -202,11 +208,6 @@ def to_representation(self, instance): data = super().to_representation(instance) data["qualifiers"] = normalize_qualifiers(data["qualifiers"], encode=False) - request = self.context.get("request") - - request = self.context.get("request") - data["resource_url"] = instance.get_details_url(request=request) - return data next_non_vulnerable_version = serializers.SerializerMethodField("get_next_non_vulnerable") From 0dc0fe36e4acb06facca61b7ccfe5c35f8eae39b Mon Sep 17 00:00:00 2001 From: Tushar Goel Date: Fri, 23 Feb 2024 18:00:14 +0530 Subject: [PATCH 6/6] Fix tests Signed-off-by: Tushar Goel --- vulnerabilities/tests/test_api.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/vulnerabilities/tests/test_api.py b/vulnerabilities/tests/test_api.py index b9b5710f6..197707a01 100644 --- a/vulnerabilities/tests/test_api.py +++ b/vulnerabilities/tests/test_api.py @@ -438,7 +438,7 @@ def test_api_with_lesser_and_greater_fixed_by_packages(self): ).data expected_response = { - "url": "http://testserver/api/packages/1", + "url": f"http://testserver/api/packages/{self.package_maven_jackson_databind_2_13_1.id}", "purl": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.1", "type": "maven", "namespace": "com.fasterxml.jackson.core", @@ -451,7 +451,10 @@ def test_api_with_lesser_and_greater_fixed_by_packages(self): "affected_by_vulnerabilities": [ OrderedDict( [ - ("url", "http://testserver/api/vulnerabilities/1"), + ( + "url", + f"http://testserver/api/vulnerabilities/{self.vuln_VCID_2nyb_8rwu_aaag.id}", + ), ("vulnerability_id", "VCID-2nyb-8rwu-aaag"), ("summary", "This is VCID-2nyb-8rwu-aaag"), ("references", []), @@ -460,7 +463,10 @@ def test_api_with_lesser_and_greater_fixed_by_packages(self): [ OrderedDict( [ - ("url", "http://testserver/api/packages/3"), + ( + "url", + f"http://testserver/api/packages/{self.package_maven_jackson_databind_2_13_2.id}", + ), ( "purl", "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.2", @@ -486,7 +492,10 @@ def test_api_with_lesser_and_greater_fixed_by_packages(self): "fixing_vulnerabilities": [ OrderedDict( [ - ("url", "http://testserver/api/vulnerabilities/3"), + ( + "url", + f"http://testserver/api/vulnerabilities/{self.vuln_VCID_ftmk_wbwx_aaar.id}", + ), ("vulnerability_id", "VCID-ftmk-wbwx-aaar"), ("summary", "This is VCID-ftmk-wbwx-aaar"), ("references", []), @@ -495,7 +504,10 @@ def test_api_with_lesser_and_greater_fixed_by_packages(self): [ OrderedDict( [ - ("url", "http://testserver/api/packages/4"), + ( + "url", + f"http://testserver/api/packages/{self.package_maven_jackson_databind_2_12_6.id}", + ), ( "purl", "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.12.6", @@ -510,7 +522,10 @@ def test_api_with_lesser_and_greater_fixed_by_packages(self): ), OrderedDict( [ - ("url", "http://testserver/api/packages/1"), + ( + "url", + f"http://testserver/api/packages/{self.package_maven_jackson_databind_2_13_1.id}", + ), ( "purl", "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.1",