diff --git a/vulnerabilities/api.py b/vulnerabilities/api.py index af8e5d889..9e0c347c2 100644 --- a/vulnerabilities/api.py +++ b/vulnerabilities/api.py @@ -22,6 +22,7 @@ from vulnerabilities.models import Vulnerability from vulnerabilities.models import VulnerabilityReference from vulnerabilities.models import VulnerabilitySeverity +from vulnerabilities.models import Weakness from vulnerabilities.models import get_purl_query_lookups from vulnerabilities.throttling import StaffUserRateThrottle @@ -96,8 +97,17 @@ class Meta: fields = ["url", "vulnerability_id", "summary", "references", "fixed_packages", "aliases"] -class VulnerabilitySerializer(serializers.HyperlinkedModelSerializer): +class WeaknessSerializer(serializers.HyperlinkedModelSerializer): + """ + Used for nesting inside weakness focused APIs. + """ + + class Meta: + model = Weakness + fields = ["cwe_id", "name", "description"] + +class VulnerabilitySerializer(serializers.HyperlinkedModelSerializer): fixed_packages = MinimalPackageSerializer( many=True, source="filtered_fixed_packages", read_only=True ) @@ -105,6 +115,7 @@ class VulnerabilitySerializer(serializers.HyperlinkedModelSerializer): references = VulnerabilityReferenceSerializer(many=True, source="vulnerabilityreference_set") aliases = AliasSerializer(many=True, source="alias") + weaknesses = WeaknessSerializer(many=True) class Meta: model = Vulnerability @@ -116,6 +127,7 @@ class Meta: "fixed_packages", "affected_packages", "references", + "weaknesses", ] @@ -336,11 +348,12 @@ def get_queryset(self): to a custom attribute `filtered_fixed_packages` """ return Vulnerability.objects.prefetch_related( + "weaknesses", Prefetch( "packages", queryset=self.get_fixed_packages_qs(), to_attr="filtered_fixed_packages", - ) + ), ) serializer_class = VulnerabilitySerializer diff --git a/vulnerabilities/tests/test_api.py b/vulnerabilities/tests/test_api.py index d02808e16..366951f9b 100644 --- a/vulnerabilities/tests/test_api.py +++ b/vulnerabilities/tests/test_api.py @@ -26,6 +26,7 @@ from vulnerabilities.models import Vulnerability from vulnerabilities.models import VulnerabilityReference from vulnerabilities.models import VulnerabilityRelatedReference +from vulnerabilities.models import Weakness BASE_DIR = os.path.dirname(os.path.abspath(__file__)) TEST_DATA = os.path.join(BASE_DIR, "test_data") @@ -197,6 +198,8 @@ def setUp(self): PackageRelatedVulnerability.objects.create( package=pkg, vulnerability=self.vulnerability, fix=True ) + self.weaknesses = Weakness.objects.create(cwe_id=119) + self.weaknesses.vulnerabilities.add(self.vulnerability) def test_api_status(self): response = self.csrf_client.get("/api/vulnerabilities/") @@ -229,6 +232,13 @@ def test_api_with_single_vulnerability(self): ], "affected_packages": [], "references": [], + "weaknesses": [ + { + "cwe_id": 119, + "name": "Improper Restriction of Operations within the Bounds of a Memory Buffer", + "description": "The software performs operations on a memory buffer, but it can read from or write to a memory location that is outside of the intended boundary of the buffer.", + } + ], } def test_api_with_single_vulnerability_with_filters(self): @@ -249,6 +259,13 @@ def test_api_with_single_vulnerability_with_filters(self): ], "affected_packages": [], "references": [], + "weaknesses": [ + { + "cwe_id": 119, + "name": "Improper Restriction of Operations within the Bounds of a Memory Buffer", + "description": "The software performs operations on a memory buffer, but it can read from or write to a memory location that is outside of the intended boundary of the buffer.", + } + ], }