Skip to content
Open
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
2 changes: 1 addition & 1 deletion .github/actions/security-issues/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ runs:
- name: Install Python Toolbox / Security tool
shell: bash
run: |
pip install exasol-toolbox==6.1.0
pip install exasol-toolbox==6.1.1

- name: Create Security Issue Report
shell: bash
Expand Down
2 changes: 2 additions & 0 deletions doc/changes/changelog.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions doc/changes/changes_6.1.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# 6.1.1 - 2026-03-18

## Summary

## Security Issues

* #748: Updated dependency to `black`

## Refactorings

* #752: Updated upload-artifact from v6 to v7 and download-artifact from v7 to v8
* #750: Updated dependency `pip-audit`

## Dependency Updates

### `main`

* Updated dependency `bandit:1.9.3` to `1.9.4`
* Updated dependency `black:25.12.0` to `26.3.1`
* Updated dependency `coverage:7.13.1` to `7.13.4`
* Updated dependency `import-linter:2.9` to `2.11`
* Updated dependency `nox:2025.11.12` to `2026.2.9`
* Updated dependency `pip-audit:2.9.0` to `2.10.0`
* Updated dependency `pip-licenses:5.5.0` to `5.5.1`
* Updated dependency `pylint:4.0.4` to `4.0.5`
* Updated dependency `ruff:0.14.13` to `0.14.14`
* Updated dependency `sphinxcontrib-mermaid:2.0.0` to `2.0.1`
* Updated dependency `typer:0.21.1` to `0.24.1`

### `dev`

* Updated dependency `cookiecutter:2.6.0` to `2.7.1`
8 changes: 0 additions & 8 deletions doc/changes/unreleased.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
# Unreleased

## Summary

## Security Issues

* #748: Updated dependency to `black`

## Refactoring

* #752: Updated upload-artifact from v6 to v7 and download-artifact from v7 to v8
2 changes: 1 addition & 1 deletion exasol/toolbox/nox/_dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def audit(session: Session) -> None:
try:
vulnerabilities = Vulnerabilities.load_from_pip_audit(working_directory=Path())
except PipAuditException as e:
session.error(e.return_code, e.stdout, e.stderr)
session.error(e.returncode, e.stdout, e.stderr)

security_issue_dict = vulnerabilities.security_issue_dict
print(json.dumps(security_issue_dict, indent=2))
38 changes: 25 additions & 13 deletions exasol/toolbox/util/dependencies/audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,18 @@
)


PipAuditEntry = dict[str, str | list[str] | tuple[str, ...]]
Copy link
Contributor Author

@ckunki ckunki Mar 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Improve readability and reduce typing effort in type hints.



@dataclass
class PipAuditException(Exception):
return_code: int
returncode: int
stdout: str
stderr: str

def __init__(self, subprocess_output: subprocess.CompletedProcess) -> None:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, adding method __init__ to a dataclass could be problematic.

self.return_code = subprocess_output.returncode
self.stdout = subprocess_output.stdout
self.stderr = subprocess_output.stderr
@classmethod
def from_subprocess(cls, proc: subprocess.CompletedProcess) -> PipAuditException:
return cls(proc.returncode, proc.stdout, proc.stderr)


class VulnerabilitySource(str, Enum):
Expand Down Expand Up @@ -102,7 +104,7 @@ def reference_links(self) -> tuple[str, ...]:
)

@property
def security_issue_entry(self) -> dict[str, str | list[str] | tuple[str, ...]]:
def security_issue_entry(self) -> PipAuditEntry:
return {
"name": self.package.name,
"version": str(self.package.version),
Expand Down Expand Up @@ -132,10 +134,20 @@ def subsection_for_changelog_summary(self) -> str:
"""
Create a subsection to be included in the Summary section of a versioned changelog.
"""
links_join = "\n* ".join(sorted(self.reference_links))
references_subsection = f"\n#### References:\n\n* {links_join}\n\n "
subsection = f"### {self.vulnerability_id} in {self.package.coordinates}\n\n{self.description}\n{references_subsection}"
return cleandoc(subsection.strip())
indent = " " * 12
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a cleandoc and some indent magic improves readability.

references = f"\n{indent}".join(
f"* {link}" for link in sorted(self.reference_links)
)
description = self.description.replace("\n", f"\n{indent}")
return cleandoc(f"""
### {self.vulnerability_id} in {self.package.coordinates}

{description}

#### References

{references}
""")


def audit_poetry_files(working_directory: Path) -> str:
Expand All @@ -159,7 +171,7 @@ def audit_poetry_files(working_directory: Path) -> str:
cwd=working_directory,
) # nosec
if output.returncode != 0:
raise PipAuditException(subprocess_output=output)
raise PipAuditException.from_subprocess(output)

with tempfile.TemporaryDirectory() as path:
tmpdir = Path(path)
Expand All @@ -179,7 +191,7 @@ def audit_poetry_files(working_directory: Path) -> str:
# they both map to returncode = 1, so we have our own logic to raise errors
# for the case of 2) and not 1).
if not search(PIP_AUDIT_VULNERABILITY_PATTERN, output.stderr.strip()):
raise PipAuditException(subprocess_output=output)
raise PipAuditException.from_subprocess(output)
return output.stdout


Expand Down Expand Up @@ -215,7 +227,7 @@ def load_from_pip_audit(cls, working_directory: Path) -> Vulnerabilities:
return Vulnerabilities(vulnerabilities=vulnerabilities)

@property
def security_issue_dict(self) -> list[dict[str, str | list[str] | tuple[str, ...]]]:
def security_issue_dict(self) -> list[PipAuditEntry]:
return [
vulnerability.security_issue_entry for vulnerability in self.vulnerabilities
]
Expand Down
2 changes: 1 addition & 1 deletion exasol/toolbox/version.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 24 additions & 10 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion project-template/cookiecutter.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"author_email": "opensource@exasol.com",
"project_short_tag": "",
"python_version_min": "3.10",
"exasol_toolbox_version_range": ">=6.1.0,<7",
"exasol_toolbox_version_range": ">=6.1.1,<7",
"license_year": "{% now 'utc', '%Y' %}",
"__repo_name_slug": "{{cookiecutter.package_name}}",
"__package_name_slug": "{{cookiecutter.package_name}}",
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "exasol-toolbox"
version = "6.1.0"
version = "6.1.1"
description = "Your one-stop solution for managing all standard tasks and core workflows of your Python project."
authors = [
{ name = "Nicola Coretti", email = "nicola.coretti@exasol.com" },
Expand Down Expand Up @@ -38,7 +38,7 @@ dependencies = [
"mypy>=0.971",
"myst-parser>=2.0.0,<4",
"nox>=2022.8.7",
"pip-audit>=2.7.3,<2.10.0", # see issue https://github.com/exasol/python-toolbox/issues/750
"pip-audit>=2.10,<3",
"pip-licenses>=5.0.0,<6",
"pluggy>=1.5.0,<2",
"pre-commit>=4,<5",
Expand Down
13 changes: 8 additions & 5 deletions test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
Issue,
_issues_as_json_str,
)
from exasol.toolbox.util.dependencies.audit import Vulnerability
from exasol.toolbox.util.dependencies.audit import (
PipAuditEntry,
Vulnerability,
)


class SampleVulnerability:
Expand All @@ -24,11 +27,11 @@ class SampleVulnerability:
)

@property
def pip_audit_vuln_entry(self) -> dict[str, str | list[str]]:
def pip_audit_vuln_entry(self) -> PipAuditEntry:
return {
"id": self.vulnerability_id,
"id": self.cve_id,
"fix_versions": [self.fix_version],
"aliases": [self.cve_id],
"aliases": [self.vulnerability_id],
"description": self.description,
}

Expand Down Expand Up @@ -59,7 +62,7 @@ def nox_dependencies_audit(self) -> str:
return json.dumps([self.security_issue_entry], indent=2) + "\n"

@property
def security_issue_entry(self) -> dict[str, str | list[str] | tuple[str, ...]]:
def security_issue_entry(self) -> PipAuditEntry:
return {
"name": self.package_name,
"version": self.version,
Expand Down
16 changes: 16 additions & 0 deletions test/integration/conftest.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
import subprocess
from pathlib import Path

import pytest

from exasol.toolbox.config import BaseConfig


@pytest.fixture(scope="session")
def poetry_path() -> str:
result = subprocess.run(["which", "poetry"], capture_output=True, text=True)
poetry_path = result.stdout.strip()
return poetry_path


@pytest.fixture(scope="session")
def ptb_minimum_python_version() -> str:
"""
Some integration tests create a sample poetry project and need to
specify its minimum python version in property "requires-python" in file
pyproject.toml.

This fixture returns a value including all python versions supported by
the PTB.
"""
return BaseConfig(root_path=Path(), project_name="toolbox").minimum_python_version
2 changes: 0 additions & 2 deletions test/integration/smoke_test.py

This file was deleted.

Loading