From 05c626a95a25aa8adc84608fd2ba50bcdb1ff65a Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Mon, 20 Apr 2026 11:34:30 +0200 Subject: [PATCH 01/10] Switch to min as still deterministic and more performant --- exasol/toolbox/tools/security.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exasol/toolbox/tools/security.py b/exasol/toolbox/tools/security.py index 9fc30161b4..6d479390d3 100644 --- a/exasol/toolbox/tools/security.py +++ b/exasol/toolbox/tools/security.py @@ -159,7 +159,7 @@ def from_pip_audit(report: str) -> Iterable[Issue]: ) if cves: yield Issue( - cve=sorted(cves)[0], + cve=min(cves), cwe="None" if not cwes else ", ".join(cwes), description=vulnerability["description"], coordinates=vulnerability["coordinates"], From b94fc3c260fd6160395f6df0f2f3ad3f2e8e6627 Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Mon, 20 Apr 2026 11:36:50 +0200 Subject: [PATCH 02/10] Use variable instead of repeating hard-coded string --- exasol/toolbox/tools/issue.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/exasol/toolbox/tools/issue.py b/exasol/toolbox/tools/issue.py index a41658841e..2eb35efdef 100644 --- a/exasol/toolbox/tools/issue.py +++ b/exasol/toolbox/tools/issue.py @@ -7,6 +7,7 @@ CLI = typer.Typer() PKG = "exasol.toolbox.templates.github.ISSUE_TEMPLATE" LEXER = "markdown" +ISSUE_TEMPLATE_PATH = Path("./.github/ISSUE_TEMPLATE") @CLI.command(name="list") @@ -31,7 +32,7 @@ def show_issue( def diff_issue( issue: str = typer.Argument(..., help="issue which shall be diffed."), dest: Path = typer.Argument( - Path("./.github/ISSUE_TEMPLATE"), + ISSUE_TEMPLATE_PATH, help="target directory to diff the issue against.", ), ) -> None: @@ -47,7 +48,7 @@ def diff_issue( def install_issue( issue: str = typer.Argument("all", help="name of the issue to install."), dest: Path = typer.Argument( - Path("./.github/ISSUE_TEMPLATE"), + ISSUE_TEMPLATE_PATH, help="target directory to install the issue to.", ), ) -> None: @@ -63,7 +64,7 @@ def install_issue( def update_issue( issue: str = typer.Argument("all", help="name of the issue to install."), dest: Path = typer.Argument( - Path("./.github/ISSUE_TEMPLATE"), + ISSUE_TEMPLATE_PATH, help="target directory to install the issue to.", ), confirm: bool = typer.Option( From 15ef90e212f0c8859018daed75f4649d033bd5b4 Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Mon, 20 Apr 2026 11:39:51 +0200 Subject: [PATCH 03/10] Fix concatenated string issue --- exasol/toolbox/sphinx/multiversion/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exasol/toolbox/sphinx/multiversion/main.py b/exasol/toolbox/sphinx/multiversion/main.py index f183d97cc8..588eef4248 100644 --- a/exasol/toolbox/sphinx/multiversion/main.py +++ b/exasol/toolbox/sphinx/multiversion/main.py @@ -524,7 +524,7 @@ def _main(args, argv): build_artefacts = candidate_files if len(build_artefacts) == 0: logger.warning( - ("Build artefact {project}" "not found.").format( + "Build artefact {project} not found.".format( project=build_file_pattern.lower(), ) ) From 31651e15e5c162fb91a47defdd26072b2cf468ff Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Mon, 20 Apr 2026 11:41:13 +0200 Subject: [PATCH 04/10] Remove unused parameter 'src' --- exasol/toolbox/sphinx/multiversion/git.py | 2 +- exasol/toolbox/sphinx/multiversion/main.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/exasol/toolbox/sphinx/multiversion/git.py b/exasol/toolbox/sphinx/multiversion/git.py index 4737ee038a..f97f17138f 100644 --- a/exasol/toolbox/sphinx/multiversion/git.py +++ b/exasol/toolbox/sphinx/multiversion/git.py @@ -143,7 +143,7 @@ def file_exists(gitroot, refname, filename): return proc.returncode == 0 -def copy_tree(gitroot, src, dst, reference, sourcepath="."): +def copy_tree(gitroot, dst, reference, sourcepath="."): with tempfile.SpooledTemporaryFile() as fp: cmd = ( "git", diff --git a/exasol/toolbox/sphinx/multiversion/main.py b/exasol/toolbox/sphinx/multiversion/main.py index 588eef4248..c8a3ab5762 100644 --- a/exasol/toolbox/sphinx/multiversion/main.py +++ b/exasol/toolbox/sphinx/multiversion/main.py @@ -310,7 +310,7 @@ def _main(args, argv): # Clone Git repo repopath = os.path.join(tmp, gitref.commit) try: - git.copy_tree(str(gitroot), gitroot.as_uri(), repopath, gitref) + git.copy_tree(str(gitroot), repopath, gitref) except (OSError, subprocess.CalledProcessError): logger.error( "Failed to copy git tree for %s to %s", From 20adc218747ffe77625ff9fde24b546616ccb936 Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Mon, 20 Apr 2026 12:48:40 +0200 Subject: [PATCH 05/10] Accept subprocess usage security warnings --- exasol/toolbox/nox/_artifacts.py | 2 +- exasol/toolbox/nox/_documentation.py | 2 +- exasol/toolbox/nox/_release.py | 2 +- exasol/toolbox/util/dependencies/audit.py | 2 +- exasol/toolbox/util/dependencies/licenses.py | 2 +- exasol/toolbox/util/dependencies/poetry_dependencies.py | 2 +- exasol/toolbox/util/git.py | 2 +- exasol/toolbox/util/version.py | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/exasol/toolbox/nox/_artifacts.py b/exasol/toolbox/nox/_artifacts.py index 19eab7d9da..a5d3a14793 100644 --- a/exasol/toolbox/nox/_artifacts.py +++ b/exasol/toolbox/nox/_artifacts.py @@ -2,7 +2,7 @@ import os import shutil import sqlite3 -import subprocess # nosec +import subprocess # nosec: B404 - risk of subprocess is accepted import sys from collections.abc import Iterable from pathlib import Path diff --git a/exasol/toolbox/nox/_documentation.py b/exasol/toolbox/nox/_documentation.py index 4d4b106d75..5c2988e0d3 100644 --- a/exasol/toolbox/nox/_documentation.py +++ b/exasol/toolbox/nox/_documentation.py @@ -3,7 +3,7 @@ import argparse import json import shutil -import subprocess +import subprocess # nosec: B404 - risk of subprocess is accepted import sys import tempfile import webbrowser diff --git a/exasol/toolbox/nox/_release.py b/exasol/toolbox/nox/_release.py index 1607292205..ad50104ce5 100644 --- a/exasol/toolbox/nox/_release.py +++ b/exasol/toolbox/nox/_release.py @@ -2,7 +2,7 @@ import argparse import re -import subprocess +import subprocess # nosec: B404 - risk of subprocess is accepted from pathlib import Path import nox diff --git a/exasol/toolbox/util/dependencies/audit.py b/exasol/toolbox/util/dependencies/audit.py index 26bc4fbd38..553c835f73 100644 --- a/exasol/toolbox/util/dependencies/audit.py +++ b/exasol/toolbox/util/dependencies/audit.py @@ -1,7 +1,7 @@ from __future__ import annotations import json -import subprocess # nosec +import subprocess # nosec: B404 - risk of subprocess is accepted import tempfile from dataclasses import dataclass from enum import Enum diff --git a/exasol/toolbox/util/dependencies/licenses.py b/exasol/toolbox/util/dependencies/licenses.py index db329e9076..d40d9d91ad 100644 --- a/exasol/toolbox/util/dependencies/licenses.py +++ b/exasol/toolbox/util/dependencies/licenses.py @@ -1,6 +1,6 @@ from __future__ import annotations -import subprocess +import subprocess # nosec: B404 - risk of subprocess is accepted import tempfile from collections import OrderedDict from dataclasses import dataclass diff --git a/exasol/toolbox/util/dependencies/poetry_dependencies.py b/exasol/toolbox/util/dependencies/poetry_dependencies.py index e56ecefe0f..26a0265565 100644 --- a/exasol/toolbox/util/dependencies/poetry_dependencies.py +++ b/exasol/toolbox/util/dependencies/poetry_dependencies.py @@ -1,6 +1,6 @@ from __future__ import annotations -import subprocess +import subprocess # nosec: B404 - risk of subprocess is accepted from collections import OrderedDict from pathlib import Path diff --git a/exasol/toolbox/util/git.py b/exasol/toolbox/util/git.py index e74ab640c9..0322bc4bbc 100644 --- a/exasol/toolbox/util/git.py +++ b/exasol/toolbox/util/git.py @@ -1,4 +1,4 @@ -import subprocess # nosec +import subprocess # nosec: B404 - risk of subprocess is accepted from functools import wraps from pathlib import Path diff --git a/exasol/toolbox/util/version.py b/exasol/toolbox/util/version.py index d65968384d..86dc177e2d 100644 --- a/exasol/toolbox/util/version.py +++ b/exasol/toolbox/util/version.py @@ -1,6 +1,6 @@ from __future__ import annotations -import subprocess +import subprocess # nosec: B404 - risk of subprocess is accepted from dataclasses import dataclass from enum import Enum from functools import ( From 26a105a4aff2ae03f2c8b8bf7103c88d4a55ef6c Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Mon, 20 Apr 2026 12:52:14 +0200 Subject: [PATCH 06/10] Add changelog entry --- doc/changes/unreleased.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changes/unreleased.md b/doc/changes/unreleased.md index 5cd75f42be..b1179794c6 100644 --- a/doc/changes/unreleased.md +++ b/doc/changes/unreleased.md @@ -5,3 +5,4 @@ ## Refactoring * #800: Removed tbx security pretty-print, tbx lint pretty-print, and creation of .lint.txt, as superseded by Sonar and .lint.json usage +* #791: Resolved Sonar concerns: accepted specific `subprocess` import usage & improved minor maintainability items From 9fed8aad33009a52bffc41b4e2019d2329d185bc Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Mon, 20 Apr 2026 12:53:44 +0200 Subject: [PATCH 07/10] Accept subprocess usage security warnings --- exasol/toolbox/sphinx/multiversion/git.py | 2 +- exasol/toolbox/sphinx/multiversion/main.py | 2 +- exasol/toolbox/tools/security.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/exasol/toolbox/sphinx/multiversion/git.py b/exasol/toolbox/sphinx/multiversion/git.py index f97f17138f..22fca61259 100644 --- a/exasol/toolbox/sphinx/multiversion/git.py +++ b/exasol/toolbox/sphinx/multiversion/git.py @@ -3,7 +3,7 @@ import logging import os import re -import subprocess +import subprocess # nosec: B404 - risk of subprocess is accepted import tarfile import tempfile diff --git a/exasol/toolbox/sphinx/multiversion/main.py b/exasol/toolbox/sphinx/multiversion/main.py index c8a3ab5762..c17410195f 100644 --- a/exasol/toolbox/sphinx/multiversion/main.py +++ b/exasol/toolbox/sphinx/multiversion/main.py @@ -10,7 +10,7 @@ import re import shutil import string -import subprocess +import subprocess # nosec: B404 - risk of subprocess is accepted import sys import tempfile from importlib import resources diff --git a/exasol/toolbox/tools/security.py b/exasol/toolbox/tools/security.py index 6d479390d3..bcc5e0017d 100644 --- a/exasol/toolbox/tools/security.py +++ b/exasol/toolbox/tools/security.py @@ -4,7 +4,7 @@ import json import re -import subprocess +import subprocess # nosec: B404 - risk of subprocess is accepted import sys from collections.abc import ( Generator, From 52768b12f658712c1de326946e27b16011a7a8f6 Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Thu, 23 Apr 2026 10:13:47 +0200 Subject: [PATCH 08/10] Fix typo per comment --- exasol/toolbox/sphinx/multiversion/main.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/exasol/toolbox/sphinx/multiversion/main.py b/exasol/toolbox/sphinx/multiversion/main.py index c17410195f..b3fea3760c 100644 --- a/exasol/toolbox/sphinx/multiversion/main.py +++ b/exasol/toolbox/sphinx/multiversion/main.py @@ -524,9 +524,8 @@ def _main(args, argv): build_artefacts = candidate_files if len(build_artefacts) == 0: logger.warning( - "Build artefact {project} not found.".format( - project=build_file_pattern.lower(), - ) + "Build artifact %s not found.", + build_file_pattern.lower(), ) elif len(build_artefacts) > 1: logger.warning( From cace0cae08cb3795b4f128a42da19c336ae2fc4a Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Thu, 23 Apr 2026 10:32:55 +0200 Subject: [PATCH 09/10] Add sorted as does not seem stable otherwise --- exasol/toolbox/nox/_artifacts.py | 2 +- test/unit/nox/_artifacts_test.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/exasol/toolbox/nox/_artifacts.py b/exasol/toolbox/nox/_artifacts.py index a5d3a14793..f487a8ba62 100644 --- a/exasol/toolbox/nox/_artifacts.py +++ b/exasol/toolbox/nox/_artifacts.py @@ -42,7 +42,7 @@ def check_artifacts(session: Session) -> None: """Validate that all project artifacts are available and consistent""" all_files = {f.name for f in PROJECT_CONFIG.root_path.iterdir() if f.is_file()} if missing_files := (ALL_LINT_FILES - all_files): - print(f"files not available: {missing_files}", file=sys.stderr) + print(f"files not available: {sorted(missing_files)}", file=sys.stderr) sys.exit(1) all_is_valid_checks = [ diff --git a/test/unit/nox/_artifacts_test.py b/test/unit/nox/_artifacts_test.py index e086ded340..b850e3b6a5 100644 --- a/test/unit/nox/_artifacts_test.py +++ b/test/unit/nox/_artifacts_test.py @@ -118,7 +118,9 @@ def test_fails_when_file_missing( ) as session: with pytest.raises(SystemExit): check_artifacts(session) - assert f"files not available: {missing_files}" in capsys.readouterr().err + assert ( + f"files not available: {sorted(missing_files)}" in capsys.readouterr().err + ) def test_fails_when_check_fails( self, test_project_config_factory, tmp_path, capsys From 71eb1623bc85687453012d4542219799b315fdad Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Thu, 23 Apr 2026 10:40:09 +0200 Subject: [PATCH 10/10] Make checks alphabetical --- exasol/toolbox/nox/_artifacts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exasol/toolbox/nox/_artifacts.py b/exasol/toolbox/nox/_artifacts.py index f487a8ba62..fe28599c61 100644 --- a/exasol/toolbox/nox/_artifacts.py +++ b/exasol/toolbox/nox/_artifacts.py @@ -46,9 +46,9 @@ def check_artifacts(session: Session) -> None: sys.exit(1) all_is_valid_checks = [ + _is_valid_coverage(Path(PROJECT_CONFIG.root_path, COVERAGE_DB)), _is_valid_lint_json(Path(PROJECT_CONFIG.root_path, LINT_JSON)), _is_valid_security_json(Path(PROJECT_CONFIG.root_path, SECURITY_JSON)), - _is_valid_coverage(Path(PROJECT_CONFIG.root_path, COVERAGE_DB)), ] if not all(all_is_valid_checks): sys.exit(1)