Skip to content

Commit 55b2ecb

Browse files
authored
Merge branch 'main' into docs/v2-pipeline-identifiers-2143
2 parents 212cddc + 74172c4 commit 55b2ecb

File tree

16 files changed

+256
-60
lines changed

16 files changed

+256
-60
lines changed

.github/workflows/pypi-release.yml

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@ on:
2121
jobs:
2222
build-pypi-distribs:
2323
name: Build and publish library to PyPI
24-
runs-on: ubuntu-22.04
24+
runs-on: ubuntu-24.04
2525

2626
steps:
27-
- uses: actions/checkout@master
27+
- uses: actions/checkout@v4
2828
- name: Set up Python
29-
uses: actions/setup-python@v1
29+
uses: actions/setup-python@v5
3030
with:
3131
python-version: 3.12
3232

@@ -37,7 +37,7 @@ jobs:
3737
run: python -m build --sdist --wheel --outdir dist/
3838

3939
- name: Upload built archives
40-
uses: actions/upload-artifact@v4
40+
uses: actions/upload-artifact@v7
4141
with:
4242
name: pypi_archives
4343
path: dist/*
@@ -47,37 +47,39 @@ jobs:
4747
name: Create GH release
4848
needs:
4949
- build-pypi-distribs
50-
runs-on: ubuntu-22.04
50+
runs-on: ubuntu-24.04
5151

5252
steps:
5353
- name: Download built archives
54-
uses: actions/download-artifact@v4
54+
uses: actions/download-artifact@v8
5555
with:
5656
name: pypi_archives
5757
path: dist
5858

5959
- name: Create GH release
60-
uses: softprops/action-gh-release@v1
60+
uses: softprops/action-gh-release@v2
6161
with:
62-
draft: true
62+
draft: false
63+
generate_release_notes: true
6364
files: dist/*
6465

6566

6667
create-pypi-release:
6768
name: Create PyPI release
6869
needs:
6970
- create-gh-release
70-
runs-on: ubuntu-22.04
71+
runs-on: ubuntu-24.04
72+
environment: pypi-publish
73+
permissions:
74+
id-token: write
7175

7276
steps:
7377
- name: Download built archives
74-
uses: actions/download-artifact@v4
78+
uses: actions/download-artifact@v8
7579
with:
7680
name: pypi_archives
7781
path: dist
7882

7983
- name: Publish to PyPI
80-
if: startsWith(github.ref, 'refs/tags')
81-
uses: pypa/gh-action-pypi-publish@master
82-
with:
83-
password: ${{ secrets.PYPI_API_TOKEN }}
84+
if: startsWith(github.ref, 'refs/tags/')
85+
uses: pypa/gh-action-pypi-publish@release/v1

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ docutils==0.17.1
4040
drf-spectacular==0.24.2
4141
drf-spectacular-sidecar==2022.10.1
4242
executing==0.8.3
43-
fetchcode==0.6.0
43+
fetchcode==0.8.2
4444
freezegun==1.2.1
4545
frozenlist==1.3.0
4646
gitdb==4.0.9

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ install_requires =
9191
# networking
9292
GitPython>=3.1.17
9393
requests>=2.25.1
94-
fetchcode>=0.6.0
94+
fetchcode>=0.8.2
9595

9696
#pipeline
9797
aboutcode.pipeline>=0.1.0

vulnerabilities/improvers/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from vulnerabilities.pipelines import populate_vulnerability_summary_pipeline
2121
from vulnerabilities.pipelines import remove_duplicate_advisories
2222
from vulnerabilities.pipelines.v2_improvers import collect_ssvc_trees
23+
from vulnerabilities.pipelines.v2_improvers import compute_advisory_content_hash
2324
from vulnerabilities.pipelines.v2_improvers import compute_advisory_todo as compute_advisory_todo_v2
2425
from vulnerabilities.pipelines.v2_improvers import compute_package_risk as compute_package_risk_v2
2526
from vulnerabilities.pipelines.v2_improvers import (
@@ -74,5 +75,6 @@
7475
compute_advisory_todo.ComputeToDo,
7576
collect_ssvc_trees.CollectSSVCPipeline,
7677
relate_severities.RelateSeveritiesPipeline,
78+
compute_advisory_content_hash.ComputeAdvisoryContentHash,
7779
]
7880
)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Generated by Django 5.2.11 on 2026-03-11 08:46
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("vulnerabilities", "0115_impactedpackageaffecting_and_more"),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name="advisoryv2",
15+
name="advisory_content_hash",
16+
field=models.CharField(
17+
blank=True,
18+
help_text="A unique hash computed from the content of the advisory used to identify advisories with the same content.",
19+
max_length=64,
20+
null=True,
21+
),
22+
),
23+
]

vulnerabilities/models.py

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3010,6 +3010,13 @@ class AdvisoryV2(models.Model):
30103010
help_text="Related advisories that are used to calculate the severity of this advisory.",
30113011
)
30123012

3013+
advisory_content_hash = models.CharField(
3014+
max_length=64,
3015+
blank=True,
3016+
null=True,
3017+
help_text="A unique hash computed from the content of the advisory used to identify advisories with the same content.",
3018+
)
3019+
30133020
@property
30143021
def risk_score(self):
30153022
"""
@@ -3078,35 +3085,6 @@ def get_aliases(self):
30783085
"""
30793086
return self.aliases.all()
30803087

3081-
def compute_advisory_content(self):
3082-
"""
3083-
Compute a unique content hash for an advisory by normalizing its data and hashing it.
3084-
3085-
:param advisory: An Advisory object
3086-
:return: SHA-256 hash digest as content hash
3087-
"""
3088-
normalized_data = {
3089-
"summary": normalize_text(self.summary),
3090-
"impacted_packages": sorted(
3091-
[impact.to_dict() for impact in self.impacted_packages.all()],
3092-
key=lambda x: json.dumps(x, sort_keys=True),
3093-
),
3094-
"patches": sorted(
3095-
[patch.to_patch_data().to_dict() for patch in self.patches.all()],
3096-
key=lambda x: json.dumps(x, sort_keys=True),
3097-
),
3098-
"severities": sorted(
3099-
[sev.to_vulnerability_severity_data().to_dict() for sev in self.severities.all()],
3100-
key=lambda x: (x.get("system"), x.get("value")),
3101-
),
3102-
"weaknesses": normalize_list([weakness.cwe_id for weakness in self.weaknesses.all()]),
3103-
}
3104-
3105-
normalized_json = json.dumps(normalized_data, separators=(",", ":"), sort_keys=True)
3106-
content_hash = hashlib.sha256(normalized_json.encode("utf-8")).hexdigest()
3107-
3108-
return content_hash
3109-
31103088
alias = get_aliases
31113089

31123090

vulnerabilities/pipelines/v2_importers/alpine_linux_importer.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ def load_advisories(
193193

194194
fixed_version_range = None
195195
try:
196-
fixed_version_range = AlpineLinuxVersionRange.from_versions([version])
196+
if version:
197+
fixed_version_range = AlpineLinuxVersionRange.from_versions([version])
197198
except InvalidVersion as e:
198199
logger(
199200
f"{version!r} is not a valid AlpineVersion {e!r}",

vulnerabilities/pipelines/v2_importers/apache_httpd_importer.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -330,19 +330,20 @@ def to_version_ranges(self, versions_data, fixed_versions):
330330
"=": "=",
331331
}
332332
comparator = comparator_by_range_expression.get(range_expression)
333-
if comparator:
333+
if comparator and version_value and version_value not in self.ignorable_versions:
334334
constraints.append(
335335
VersionConstraint(comparator=comparator, version=SemverVersion(version_value))
336336
)
337337

338338
for fixed_version in fixed_versions:
339339
# The VersionConstraint method `invert()` inverts the fixed_version's comparator,
340340
# enabling inclusion of multiple fixed versions with the `affected_version_range` values.
341-
constraints.append(
342-
VersionConstraint(
343-
comparator="=",
344-
version=SemverVersion(fixed_version),
345-
).invert()
346-
)
341+
if fixed_version and fixed_version not in self.ignorable_versions:
342+
constraints.append(
343+
VersionConstraint(
344+
comparator="=",
345+
version=SemverVersion(fixed_version),
346+
).invert()
347+
)
347348

348349
return ApacheVersionRange(constraints=constraints)

vulnerabilities/pipelines/v2_importers/elixir_security_importer.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class ElixirSecurityImporterPipeline(VulnerableCodeBaseImporterPipelineV2):
3535
spdx_license_expression = "CC0-1.0"
3636
license_url = "https://github.com/dependabot/elixir-security-advisories/blob/master/LICENSE.txt"
3737
repo_url = "git+https://github.com/dependabot/elixir-security-advisories"
38+
run_once = True
3839

3940
precedence = 200
4041

vulnerabilities/pipelines/v2_importers/gitlab_importer.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ def parse_gitlab_advisory(
252252
original_advisory_text=json.dumps(gitlab_advisory, indent=2, ensure_ascii=False),
253253
)
254254
affected_version_range = None
255+
fixed_version_range = None
255256
fixed_versions = gitlab_advisory.get("fixed_versions") or []
256257
affected_range = gitlab_advisory.get("affected_range")
257258
gitlab_native_schemes = set(["pypi", "gem", "npm", "go", "packagist", "conan"])
@@ -285,7 +286,8 @@ def parse_gitlab_advisory(
285286
if affected_version_range:
286287
vrc = affected_version_range.__class__
287288

288-
fixed_version_range = vrc.from_versions(parsed_fixed_versions)
289+
if parsed_fixed_versions:
290+
fixed_version_range = vrc.from_versions(parsed_fixed_versions)
289291
if not fixed_version_range and not affected_version_range:
290292
return
291293

0 commit comments

Comments
 (0)