Skip to content

Commit 65230b5

Browse files
committed
Merge latest main branch
Signed-off-by: Philippe Ombredanne <[email protected]>
2 parents 066c8c5 + 5b982c6 commit 65230b5

33 files changed

+1175
-204
lines changed

.github/workflows/docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
strategy:
1010
max-parallel: 4
1111
matrix:
12-
python-version: [3.8]
12+
python-version: [3.9]
1313

1414
steps:
1515
- name: Checkout code

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
strategy:
3030
max-parallel: 4
3131
matrix:
32-
python-version: ["3.8", "3.9", "3.10"]
32+
python-version: ["3.9", "3.10", "3.11"]
3333

3434
steps:
3535
- name: Checkout code

CHANGELOG.rst

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

4+
Version (next)
5+
-------------------
6+
7+
- Add Pipeline to flag ghost packages (#1533)
8+
- Add logging configuration (#1533)
9+
- Drop support for python 3.8 (#1533)
10+
11+
12+
Version v34.0.0
13+
-------------------
14+
15+
- Improve API performance.
16+
- Add severity range score in API.
17+
- Refactor GitlabDataSource to work with browser extension
18+
19+
420
Version v34.0.0rc5
521
-------------------
622

requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
aboutcode.pipeline==0.1.0
12
aiosignal==1.2.0
23
alabaster==0.7.12
34
asgiref==3.5.2
@@ -10,6 +11,7 @@ bcrypt==3.2.0
1011
beautifulsoup4==4.10.0
1112
binaryornot==0.4.4
1213
black==22.3.0
14+
bleach==6.1.0
1315
boolean.py==3.8
1416
certifi==2024.7.4
1517
cffi==1.15.0
@@ -49,6 +51,7 @@ jsonschema==3.2.0
4951
license-expression==21.6.14
5052
lxml==4.9.1
5153
Markdown==3.3.4
54+
markdown-it-py==3.0.0
5255
MarkupSafe==2.1.1
5356
matplotlib-inline==0.1.3
5457
multidict==6.0.2

setup.cfg

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = vulnerablecode
3-
version = 33.6.3
3+
version = 34.0.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
@@ -48,7 +48,7 @@ license_files =
4848
README.rst
4949

5050
[options]
51-
python_requires = >=3.8
51+
python_requires = >=3.9
5252

5353
packages=find:
5454
include_package_data = true
@@ -92,6 +92,9 @@ install_requires =
9292
requests>=2.25.1
9393
fetchcode>=0.3.0
9494

95+
#pipeline
96+
aboutcode.pipeline>=0.1.0
97+
9598
#vulntotal
9699
python-dotenv
97100
texttable

vulnerabilities/api.py

Lines changed: 55 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99

1010
from urllib.parse import unquote
1111

12+
from cvss.exceptions import CVSS2MalformedError
13+
from cvss.exceptions import CVSS3MalformedError
14+
from cvss.exceptions import CVSS4MalformedError
1215
from django.db.models import Prefetch
1316
from django_filters import rest_framework as filters
1417
from drf_spectacular.utils import extend_schema
15-
from drf_spectacular.utils import inline_serializer
1618
from packageurl import PackageURL
1719
from packageurl import normalize_qualifiers
1820
from rest_framework import serializers
@@ -32,7 +34,10 @@
3234
from vulnerabilities.models import VulnerabilitySeverity
3335
from vulnerabilities.models import Weakness
3436
from vulnerabilities.models import get_purl_query_lookups
37+
from vulnerabilities.severity_systems import EPSS
38+
from vulnerabilities.severity_systems import SCORING_SYSTEMS
3539
from vulnerabilities.throttling import StaffUserRateThrottle
40+
from vulnerabilities.utils import get_severity_range
3641

3742

3843
class VulnerabilitySeveritySerializer(serializers.ModelSerializer):
@@ -82,29 +87,23 @@ def get_resource_url(self, instance):
8287
return resource_url
8388

8489

85-
class MinimalPackageSerializer(BaseResourceSerializer):
90+
class VulnVulnIDSerializer(serializers.Serializer):
8691
"""
87-
Used for nesting inside vulnerability focused APIs.
92+
Serializer for the series of vulnerability IDs.
8893
"""
8994

90-
def get_affected_vulnerabilities(self, package):
91-
parent_affected_vulnerabilities = package.fixed_package_details.get("vulnerabilities") or []
92-
93-
affected_vulnerabilities = [
94-
self.get_vulnerability(vuln) for vuln in parent_affected_vulnerabilities
95-
]
95+
vulnerability = serializers.CharField(source="vulnerability_id")
9696

97-
return affected_vulnerabilities
97+
class Meta:
98+
fields = ["vulnerability"]
9899

99-
def get_vulnerability(self, vuln):
100-
affected_vulnerability = {}
101100

102-
vulnerability = vuln.get("vulnerability")
103-
if vulnerability:
104-
affected_vulnerability["vulnerability"] = vulnerability.vulnerability_id
105-
return affected_vulnerability
101+
class MinimalPackageSerializer(BaseResourceSerializer):
102+
"""
103+
Used for nesting inside vulnerability focused APIs.
104+
"""
106105

107-
affected_by_vulnerabilities = serializers.SerializerMethodField("get_affected_vulnerabilities")
106+
affected_by_vulnerabilities = VulnVulnIDSerializer(source="affecting_vulns", many=True)
108107

109108
purl = serializers.CharField(source="package_url")
110109

@@ -140,18 +139,17 @@ class VulnSerializerRefsAndSummary(BaseResourceSerializer):
140139
Lookup vulnerabilities references by aliases (such as a CVE).
141140
"""
142141

143-
def to_representation(self, instance):
144-
data = super().to_representation(instance)
145-
aliases = [alias["alias"] for alias in data["aliases"]]
146-
data["aliases"] = aliases
147-
return data
148-
149142
fixed_packages = MinimalPackageSerializer(
150143
many=True, source="filtered_fixed_packages", read_only=True
151144
)
152145

153146
references = VulnerabilityReferenceSerializer(many=True, source="vulnerabilityreference_set")
154-
aliases = AliasSerializer(many=True, source="alias")
147+
148+
aliases = serializers.SerializerMethodField()
149+
150+
def get_aliases(self, obj):
151+
# Assuming `obj.aliases` is a queryset of `Alias` objects
152+
return [alias.alias for alias in obj.aliases.all()]
155153

156154
class Meta:
157155
model = Vulnerability
@@ -193,6 +191,7 @@ class VulnerabilitySerializer(BaseResourceSerializer):
193191
aliases = AliasSerializer(many=True, source="alias")
194192
kev = KEVSerializer(read_only=True)
195193
weaknesses = WeaknessSerializer(many=True)
194+
severity_range_score = serializers.SerializerMethodField()
196195

197196
def to_representation(self, instance):
198197
data = super().to_representation(instance)
@@ -206,6 +205,30 @@ def to_representation(self, instance):
206205

207206
return data
208207

208+
def get_severity_range_score(self, instance):
209+
severity_vectors = []
210+
severity_values = set()
211+
for s in instance.severities:
212+
if s.scoring_system == EPSS.identifier:
213+
continue
214+
215+
if s.scoring_elements and s.scoring_system in SCORING_SYSTEMS:
216+
try:
217+
vector_values = SCORING_SYSTEMS[s.scoring_system].get(s.scoring_elements)
218+
severity_vectors.append(vector_values)
219+
except (
220+
CVSS2MalformedError,
221+
CVSS3MalformedError,
222+
CVSS4MalformedError,
223+
NotImplementedError,
224+
):
225+
pass
226+
227+
if s.value:
228+
severity_values.add(s.value)
229+
severity_range = get_severity_range(severity_values)
230+
return severity_range
231+
209232
class Meta:
210233
model = Vulnerability
211234
fields = [
@@ -218,6 +241,7 @@ class Meta:
218241
"references",
219242
"weaknesses",
220243
"kev",
244+
"severity_range_score",
221245
]
222246

223247

@@ -226,34 +250,22 @@ class PackageSerializer(BaseResourceSerializer):
226250
Lookup software package using Package URLs
227251
"""
228252

229-
def to_representation(self, instance):
230-
data = super().to_representation(instance)
231-
data["qualifiers"] = normalize_qualifiers(data["qualifiers"], encode=False)
232-
233-
return data
234-
235-
next_non_vulnerable_version = serializers.SerializerMethodField("get_next_non_vulnerable")
236-
237-
def get_next_non_vulnerable(self, package):
238-
next_non_vulnerable = package.fixed_package_details.get("next_non_vulnerable", None)
239-
if next_non_vulnerable:
240-
return next_non_vulnerable.version
241-
242-
latest_non_vulnerable_version = serializers.SerializerMethodField("get_latest_non_vulnerable")
243-
244-
def get_latest_non_vulnerable(self, package):
245-
latest_non_vulnerable = package.fixed_package_details.get("latest_non_vulnerable", None)
246-
if latest_non_vulnerable:
247-
return latest_non_vulnerable.version
253+
next_non_vulnerable_version = serializers.CharField(read_only=True)
254+
latest_non_vulnerable_version = serializers.CharField(read_only=True)
248255

249256
purl = serializers.CharField(source="package_url")
250257

251258
affected_by_vulnerabilities = serializers.SerializerMethodField("get_affected_vulnerabilities")
252259

253260
fixing_vulnerabilities = serializers.SerializerMethodField("get_fixing_vulnerabilities")
254261

262+
qualifiers = serializers.SerializerMethodField()
263+
255264
is_vulnerable = serializers.BooleanField()
256265

266+
def get_qualifiers(self, package):
267+
return normalize_qualifiers(package.qualifiers, encode=False)
268+
257269
def get_fixed_packages(self, package):
258270
"""
259271
Return a queryset of all packages that fix a vulnerability with
@@ -337,8 +349,6 @@ class Meta:
337349
"fixing_vulnerabilities",
338350
]
339351

340-
is_vulnerable = serializers.BooleanField()
341-
342352

343353
class PackageFilterSet(filters.FilterSet):
344354
purl = filters.CharFilter(method="filter_purl")

vulnerabilities/import_runner.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
from vulnerabilities.importer import AdvisoryData
2020
from vulnerabilities.importer import Importer
21-
from vulnerabilities.importers import IMPORTERS_REGISTRY
2221
from vulnerabilities.improver import Inference
2322
from vulnerabilities.improvers.default import DefaultImporter
2423
from vulnerabilities.models import Advisory

vulnerabilities/importers/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
from vulnerabilities.importers import oss_fuzz
3131
from vulnerabilities.importers import postgresql
3232
from vulnerabilities.importers import project_kb_msr2019
33-
from vulnerabilities.importers import pypa
3433
from vulnerabilities.importers import pysec
3534
from vulnerabilities.importers import redhat
3635
from vulnerabilities.importers import retiredotnet
@@ -40,13 +39,13 @@
4039
from vulnerabilities.importers import ubuntu_usn
4140
from vulnerabilities.importers import vulnrichment
4241
from vulnerabilities.importers import xen
42+
from vulnerabilities.pipelines import pypa_importer
4343

4444
IMPORTERS_REGISTRY = [
4545
nvd.NVDImporter,
4646
github.GitHubAPIImporter,
4747
gitlab.GitLabAPIImporter,
4848
npm.NpmImporter,
49-
pypa.PyPaImporter,
5049
nginx.NginxImporter,
5150
pysec.PyPIImporter,
5251
alpine_linux.AlpineImporter,
@@ -75,6 +74,7 @@
7574
github_osv.GithubOSVImporter,
7675
epss.EPSSImporter,
7776
vulnrichment.VulnrichImporter,
77+
pypa_importer.PyPaImporterPipeline,
7878
]
7979

8080
IMPORTERS_REGISTRY = {x.qualified_name: x for x in IMPORTERS_REGISTRY}

vulnerabilities/importers/pypa.py

Lines changed: 0 additions & 66 deletions
This file was deleted.

vulnerabilities/improvers/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from vulnerabilities.improvers import valid_versions
1111
from vulnerabilities.improvers import vulnerability_kev
1212
from vulnerabilities.improvers import vulnerability_status
13+
from vulnerabilities.pipelines import flag_ghost_packages
1314

1415
IMPROVERS_REGISTRY = [
1516
valid_versions.GitHubBasicImprover,
@@ -29,6 +30,7 @@
2930
valid_versions.GithubOSVImprover,
3031
vulnerability_status.VulnerabilityStatusImprover,
3132
vulnerability_kev.VulnerabilityKevImprover,
33+
flag_ghost_packages.FlagGhostPackagePipeline,
3234
]
3335

3436
IMPROVERS_REGISTRY = {x.qualified_name: x for x in IMPROVERS_REGISTRY}

0 commit comments

Comments
 (0)