Skip to content

Commit 515cd70

Browse files
authored
Merge branch 'main' into 1287-resume-combining-affected-fixed-tabs
2 parents 76c5eda + a7b002f commit 515cd70

File tree

73 files changed

+6208
-608
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+6208
-608
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

.github/workflows/pypi-release.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ jobs:
5151

5252
steps:
5353
- name: Download built archives
54-
uses: actions/download-artifact@v3
54+
uses: actions/download-artifact@v4.1.7
5555
with:
5656
name: pypi_archives
5757
path: dist
@@ -71,7 +71,7 @@ jobs:
7171

7272
steps:
7373
- name: Download built archives
74-
uses: actions/download-artifact@v3
74+
uses: actions/download-artifact@v4.1.7
7575
with:
7676
name: pypi_archives
7777
path: dist

CHANGELOG.rst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,36 @@
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+
20+
Version v34.0.0rc5
21+
-------------------
22+
23+
- Add safetydb importer.
24+
- Add missing width setting for the table in the vulnerability details UI.
25+
- Add KEV support.
26+
- Add UI template for API.
27+
- Use VersionRange.normalize to compare advisory.
28+
- Use integer column to display score.
29+
- Add support for CVSSv4 & SSVC and import the data using vulnrichment.
30+
- Add support for reference_type in the API.
31+
- Add API improvements for the package endpoint.
32+
33+
434
Version v34.0.0rc4
535
-------------------
636

requirements.txt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
aboutcode.pipeline==0.1.0
12
aiosignal==1.2.0
23
alabaster==0.7.12
3-
asgiref==3.5.2
4+
asgiref==3.6.0
45
asttokens==2.0.5
56
async-timeout==4.0.2
67
attrs==21.4.0
@@ -10,22 +11,23 @@ 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
1618
chardet==4.0.0
1719
charset-normalizer==2.0.12
1820
click==8.1.2
19-
cryptography==42.0.4
21+
cryptography==43.0.1
2022
decorator==5.1.1
2123
defusedxml==0.7.1
2224
distro==1.7.0
23-
Django==4.1.13
25+
Django==4.2.15
2426
django-crispy-forms==1.10.0
2527
django-environ==0.8.1
2628
django-filter==21.1
2729
django-widget-tweaks==1.4.12
28-
djangorestframework==3.13.1
30+
djangorestframework==3.15.2
2931
doc8==0.11.1
3032
docker==5.0.3
3133
dockerpty==0.4.1
@@ -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")

0 commit comments

Comments
 (0)