Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions doc/changes/unreleased.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Unreleased

## Bugfixes

* #965: Added additional parameters to ``format:fix`` tools to run with the minimum Python version
* #983: Deduplicated vulnerable dependencies in Nox session ``release:prepare``

## Features

* #940: Added shared validation for packaged agent skills and the `skills:check` Nox session.
Expand All @@ -14,7 +19,3 @@
* #972: Switched from ravsamhq/notify-slack-action to maintained slackapi/slack-github-action & removed workflow versioned header
* #967: Refactored skill installation into reusable filesystem helpers.
* #965: Removed support for Python 3.10 (reach end-of-life October 2026), updated to Ubuntu-26.04 for GitHub actions, and updated default databases

## Bugfixes

* #965: Added additional parameters to ``format:fix`` tools to run with the minimum Python version
5 changes: 4 additions & 1 deletion exasol/toolbox/util/dependencies/track_vulnerabilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,8 @@ def formatted(vuln: Vulnerability) -> str:
)
return f'| {" | ".join(columns)} |'

body = "\n".join(formatted(v) for v in resolved)
# pip-audit can return the same vulnerability more than once. Keep
# distinct table rows, but only render each row once.
rows = sorted({formatted(vuln) for vuln in resolved})
body = "\n".join(rows)
return f"{header}\n{body}"
2 changes: 1 addition & 1 deletion test/unit/tool_template_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,5 @@ def test_retrieve_templates(subpackage, expected):
def test_install_templates(templates, pkg, expected, tmp_path):
template.install_template(templates, tmp_path, pkg)
actual = {file.name for file in tmp_path.iterdir()}
expected = {name for name in expected}
expected = {*expected}
assert actual == expected
30 changes: 30 additions & 0 deletions test/unit/util/dependencies/track_vulnerabilities_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,36 @@ def test_resolved_vulnerability(self, sample_vulnerability):
)
assert audit.resolved_vulnerabilities == [sample_vulnerability.vulnerability]

def test_report_deduplicates_repeated_vulnerability_rows(
self, sample_vulnerability
):
vulnerability = sample_vulnerability.vulnerability
earlier_alphabetically = Vulnerability(
package={"name": "black", "version": "26.5.1"},
id="CVE-2026-114134",
aliases=[],
fix_versions=["26.10.1"],
description="Dummy description",
)
audit = DependenciesAudit(
previous_vulnerabilities=[
vulnerability,
earlier_alphabetically,
vulnerability,
earlier_alphabetically,
],
current_vulnerabilities=[],
)

assert audit.report_resolved_vulnerabilities() == (
"This release fixes vulnerabilities by updating dependencies:\n\n"
"| Dependency | Vulnerability | Affected | Fixed in |\n"
"|------------|---------------|----------|----------|\n"
"| black | CVE-2026-114134 | 26.5.1 | 26.10.1 |\n"
f"| {sample_vulnerability.package_name} | {sample_vulnerability.cve_id} | "
f"{sample_vulnerability.version} | {sample_vulnerability.fix_version} |"
)

def test_vulnerability_without_fix_version_is_not_reported_as_resolved(
self, sample_vulnerability
):
Expand Down