Skip to content

Commit

Permalink
Merge pull request #932 from TG1999/all_vulnerable_purls
Browse files Browse the repository at this point in the history
Add API endpoint to get all vulnerable packages #929
  • Loading branch information
TG1999 committed Oct 4, 2022
2 parents 4e6c4f0 + 20305dd commit ab9d3c4
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 3 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
Release notes
=============


Version v31.0.0
----------------

- We added a new "/packages/all" API endpoint to get all Package URLs know to be vulnerable.


Version v30.0.0
----------------

Expand Down Expand Up @@ -80,7 +87,6 @@ This is a major version that is not backward compatible.
- The data license is now CC-BY-SA-4.0 as this is the highest common
denominator license among all the data sources we collect and aggregate.


Other:

- We dropped calver to use a plain semver.
Expand Down
6 changes: 6 additions & 0 deletions vulnerabilities/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,12 @@ def bulk_search(self, request):

return Response(response)

@action(detail=False, methods=["get"])
def all(self, request):
vulnerable_packages = Package.objects.vulnerable().only(*PackageURL._fields)
vulnerable_purls = [str(package.purl) for package in vulnerable_packages]
return Response(vulnerable_purls)


class VulnerabilityFilterSet(filters.FilterSet):
class Meta:
Expand Down
8 changes: 7 additions & 1 deletion vulnerabilities/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def vulnerable_to(self):
"""
Return packages that are vulnerable to this vulnerability.
"""
return self.packages.filter(packagerelatedvulnerability__fix=False)
return self.packages.vulnerable()

@property
def resolved_to(self):
Expand Down Expand Up @@ -198,6 +198,12 @@ def for_package_url_object(self, purl):
else:
return self.none()

def vulnerable(self):
"""
Return all vulnerable packages.
"""
return Package.objects.filter(packagerelatedvulnerability__fix=False).distinct()


class Package(PackageURLMixin):
"""
Expand Down
25 changes: 24 additions & 1 deletion vulnerabilities/tests/test_fix_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from django.contrib.auth import get_user_model
from django.test import TestCase
from django.test import TransactionTestCase
from django.utils.http import int_to_base36
from packageurl import PackageURL
from rest_framework import status
from rest_framework.test import APIClient
Expand Down Expand Up @@ -109,6 +108,7 @@ def setUp(self):
summary="test-vuln",
)
self.vuln = vuln
self.vulnerable_packages = []
for i in range(0, 10):
query_kwargs = dict(
type="generic",
Expand Down Expand Up @@ -258,6 +258,29 @@ def test_api_with_single_vulnerability_and_vulnerable_package(self):
],
}

def test_api_with_all_vulnerable_packages(self):
with self.assertNumQueries(4):
# There are 4 queries:
# 1. SAVEPOINT
# 2. Authenticating user
# 3. Get all vulnerable packages
# 4. RELEASE SAVEPOINT
response = self.csrf_client.get(f"/api/packages/all", format="json").data
assert len(response) == 11
assert response == [
"pkg:generic/nginx/test@0",
"pkg:generic/nginx/test@1",
"pkg:generic/nginx/test@11",
"pkg:generic/nginx/test@2",
"pkg:generic/nginx/test@3",
"pkg:generic/nginx/test@4",
"pkg:generic/nginx/test@5",
"pkg:generic/nginx/test@6",
"pkg:generic/nginx/test@7",
"pkg:generic/nginx/test@8",
"pkg:generic/nginx/test@9",
]


class CPEApi(TestCase):
def setUp(self):
Expand Down
66 changes: 66 additions & 0 deletions vulnerabilities/tests/test_fix_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#
# Copyright (c) nexB Inc. and others. All rights reserved.
# VulnerableCode is a trademark of nexB Inc.
# SPDX-License-Identifier: Apache-2.0
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
# See https://github.com/nexB/vulnerablecode for support or download.
# See https://aboutcode.org for more information about nexB OSS projects.
#

from django.contrib.auth import get_user_model
from django.test import TestCase
from packageurl import PackageURL

from vulnerabilities.models import Package
from vulnerabilities.models import PackageRelatedVulnerability
from vulnerabilities.models import Vulnerability

User = get_user_model()


class TestPackageModel(TestCase):
def setUp(self):
vuln1 = Vulnerability.objects.create(
summary="test-vuln",
)
vuln2 = Vulnerability.objects.create(
summary="test-vuln1",
)
for i in range(0, 10):
query_kwargs = dict(
type="generic",
namespace="nginx",
name="test",
version=str(i),
qualifiers={},
subpath="",
)
vuln_package = Package.objects.create(**query_kwargs)
# Attaching same package to 2 vulnerabilities
PackageRelatedVulnerability.objects.create(
package=vuln_package,
vulnerability=vuln1,
fix=False,
)
PackageRelatedVulnerability.objects.create(
package=vuln_package,
vulnerability=vuln2,
fix=False,
)

def test_get_vulnerable_packages(self):
vuln_packages = Package.objects.vulnerable()
assert vuln_packages.count() == 10
vuln_purls = [pkg.purl for pkg in vuln_packages.only(*PackageURL._fields)]
assert vuln_purls == [
"pkg:generic/nginx/test@0",
"pkg:generic/nginx/test@1",
"pkg:generic/nginx/test@2",
"pkg:generic/nginx/test@3",
"pkg:generic/nginx/test@4",
"pkg:generic/nginx/test@5",
"pkg:generic/nginx/test@6",
"pkg:generic/nginx/test@7",
"pkg:generic/nginx/test@8",
"pkg:generic/nginx/test@9",
]

0 comments on commit ab9d3c4

Please sign in to comment.