Skip to content

Commit 4ab8b2f

Browse files
authored
Merge pull request #2249 from aboutcode-org/prep_v38.1.0
Prepare v38.1.0 for release
2 parents 0142cf1 + 2c3d354 commit 4ab8b2f

File tree

11 files changed

+127
-29
lines changed

11 files changed

+127
-29
lines changed

CHANGELOG.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
Release notes
22
=============
33

4+
Version v38.1.0
5+
---------------------
6+
7+
- Throttle UI to 15 requests per minute to avoid abuse and improve performance.
8+
- Handle errors in unfurl_version_range pipeline.
9+
- Remove Todo pipeline from v1 pipelines.
10+
- Add openAPI documentation for Package and Advisory viewset.
11+
412
Version v38.0.0
513
---------------------
614

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = vulnerablecode
3-
version = 38.0.0
3+
version = 38.1.0
44
license = Apache-2.0 AND CC-BY-SA-4.0
55

66
# description must be on ONE line https://github.com/pypa/setuptools/issues/1390

vulnerabilities/api_v3.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from django.db.models import OuterRef
1515
from django.db.models import Prefetch
1616
from django_filters import rest_framework as filters
17+
from drf_spectacular.utils import extend_schema
1718
from packageurl import PackageURL
1819
from rest_framework import serializers
1920
from rest_framework import viewsets
@@ -422,6 +423,7 @@ class PackageV3ViewSet(viewsets.GenericViewSet):
422423
filter_backends = [filters.DjangoFilterBackend]
423424
throttle_classes = [AnonRateThrottle, PermissionBasedUserRateThrottle]
424425

426+
@extend_schema(request=PackageQuerySerializer)
425427
def create(self, request, *args, **kwargs):
426428
serializer = PackageQuerySerializer(data=request.data)
427429
serializer.is_valid(raise_exception=True)
@@ -528,8 +530,9 @@ class AdvisoryV3ViewSet(viewsets.GenericViewSet):
528530
filter_backends = [filters.DjangoFilterBackend]
529531
throttle_classes = [AnonRateThrottle, PermissionBasedUserRateThrottle]
530532

533+
@extend_schema(request=AdvisoryQuerySerializer)
531534
def create(self, request, *args, **kwargs):
532-
serializer = PackageQuerySerializer(data=request.data)
535+
serializer = AdvisoryQuerySerializer(data=request.data)
533536
serializer.is_valid(raise_exception=True)
534537

535538
purls = serializer.validated_data["purls"]

vulnerabilities/importers/__init__.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
from vulnerabilities.importers import github_osv
2222
from vulnerabilities.importers import istio
2323
from vulnerabilities.importers import mozilla
24-
from vulnerabilities.importers import openssl
2524
from vulnerabilities.importers import oss_fuzz
2625
from vulnerabilities.importers import postgresql
2726
from vulnerabilities.importers import project_kb_msr2019
@@ -38,7 +37,6 @@
3837
from vulnerabilities.pipelines import gitlab_importer
3938
from vulnerabilities.pipelines import nginx_importer
4039
from vulnerabilities.pipelines import npm_importer
41-
from vulnerabilities.pipelines import nvd_importer
4240
from vulnerabilities.pipelines import pypa_importer
4341
from vulnerabilities.pipelines import pysec_importer
4442
from vulnerabilities.pipelines.v2_importers import alpine_linux_importer as alpine_linux_importer_v2
@@ -118,7 +116,6 @@
118116
retiredotnet_importer_v2.RetireDotnetImporterPipeline,
119117
ubuntu_osv_importer_v2.UbuntuOSVImporterPipeline,
120118
alpine_linux_importer_v2.AlpineLinuxImporterPipeline,
121-
nvd_importer.NVDImporterPipeline,
122119
github_importer.GitHubAPIImporterPipeline,
123120
gitlab_importer.GitLabImporterPipeline,
124121
github_osv.GithubOSVImporter,
@@ -136,7 +133,6 @@
136133
alpine_linux_importer.AlpineLinuxImporterPipeline,
137134
ruby.RubyImporter,
138135
apache_kafka.ApacheKafkaImporter,
139-
openssl.OpensslImporter,
140136
openssl_importer_v2.OpenSSLImporterPipeline,
141137
redhat.RedhatImporter,
142138
archlinux.ArchlinuxImporter,

vulnerabilities/improvers/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from vulnerabilities.improvers import valid_versions
1111
from vulnerabilities.improvers import vulnerability_status
1212
from vulnerabilities.pipelines import add_cvss31_to_CVEs
13-
from vulnerabilities.pipelines import compute_advisory_todo
1413
from vulnerabilities.pipelines import compute_package_risk
1514
from vulnerabilities.pipelines import compute_package_version_rank
1615
from vulnerabilities.pipelines import enhance_with_exploitdb
@@ -70,7 +69,6 @@
7069
compute_package_risk_v2.ComputePackageRiskPipeline,
7170
compute_version_rank_v2.ComputeVersionRankPipeline,
7271
unfurl_version_range_v2.UnfurlVersionRangePipeline,
73-
compute_advisory_todo.ComputeToDo,
7472
collect_ssvc_trees.CollectSSVCPipeline,
7573
relate_severities.RelateSeveritiesPipeline,
7674
group_advisories_for_packages.GroupAdvisoriesForPackages,

vulnerabilities/pipelines/v2_improvers/unfurl_version_range.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def unfurl_version_range(self):
5252
if purl.type not in RANGE_CLASS_BY_SCHEMES:
5353
continue
5454

55-
versions = get_purl_versions(purl, cached_versions)
55+
versions = get_purl_versions(purl, cached_versions) or []
5656
affected_purls = get_affected_purls(
5757
versions=versions,
5858
affecting_vers=impact.affecting_vers,
@@ -79,6 +79,8 @@ def get_affected_purls(versions, affecting_vers, base_purl, logger):
7979
version_class = affecting_version_range.version_class
8080

8181
try:
82+
if not versions:
83+
return []
8284
versions = [version_class(v) for v in versions]
8385
except Exception as e:
8486
logger(
@@ -107,8 +109,10 @@ def get_affected_purls(versions, affecting_vers, base_purl, logger):
107109

108110
def get_purl_versions(purl, cached_versions):
109111
if not purl in cached_versions:
110-
cached_versions[purl] = get_versions(purl)
111-
return cached_versions[purl]
112+
purls = get_versions(purl)
113+
if purls is not None:
114+
cached_versions[purl] = purls
115+
return cached_versions.get(purl) or []
112116

113117

114118
def bulk_create_with_m2m(purls, impact, relation, logger):

vulnerabilities/tests/test_view.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111
import time
1212

1313
import pytest
14+
from django.core.cache import cache
1415
from django.test import Client
1516
from django.test import TestCase
17+
from django.urls import reverse
1618
from packageurl import PackageURL
1719
from univers import versions
1820

@@ -330,3 +332,33 @@ def test_aggregate_fixed_and_affected_packages(self):
330332
end_time = time.time()
331333
assert end_time - start_time < 0.05
332334
self.assertEqual(response.status_code, 200)
335+
336+
337+
class ThrottleTestCase(TestCase):
338+
def setUp(self):
339+
self.client = Client()
340+
cache.clear()
341+
342+
def test_throttle_after_15_requests(self):
343+
url = reverse("home")
344+
345+
responses = []
346+
347+
for i in range(16):
348+
response = self.client.get(
349+
url,
350+
HTTP_USER_AGENT="test-agent",
351+
)
352+
responses.append(response.status_code)
353+
354+
assert all(code == 200 for code in responses[:15])
355+
356+
assert responses[15] == 429
357+
358+
url = reverse("package_search")
359+
360+
response = self.client.get(
361+
url,
362+
HTTP_USER_AGENT="test-agent",
363+
)
364+
assert response.status_code == 429

vulnerabilities/throttling.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,19 @@ def get_throttle_rate(self, tier):
5151
raise ImproperlyConfigured(msg)
5252

5353

54+
class AnonUserUIThrottle(UserRateThrottle):
55+
scope = "ui"
56+
57+
def allow_request(self, request, view):
58+
self.rate = self.THROTTLE_RATES.get("ui")
59+
self.num_requests, self.duration = self.parse_rate(self.rate)
60+
return super().allow_request(request, view)
61+
62+
def get_cache_key(self, request, view):
63+
ident = self.get_ident(request)
64+
return f"throttle_ui_{ident}"
65+
66+
5467
def throttled_exception_handler(exception, context):
5568
"""
5669
Return this response whenever a request has been throttled

0 commit comments

Comments
 (0)