diff --git a/Makefile b/Makefile index 94e6c348c..ecfd3c2eb 100644 --- a/Makefile +++ b/Makefile @@ -301,13 +301,6 @@ requirements.txt: pyproject.toml # a PyPI entry; also print out CVE description and potential fixes if audit # found an issue. If an advisory needs to be ignored, use the --ignore-vuln option. # -# Remove GHSA-vfmq-68hx-4jfw when the following issue is resolved to be able to -# install the latest version of lxml. -# https://github.com/semgrep/semgrep/issues/11630 -# -# Remove PYSEC-2026-2132 when Semgrep allows Click >=8.3.3. Click is a -# transitive dependency of Semgrep -# # GHSA-hvrp-rf83-w775 ignore-vuln GHSA-jpw9-pfvf-9f58, and ignore-vuln GHSA-vj7q-gjh5-988w are advisories # for the mcp package, which is a dependency of semgrep and we cannot update it outselves. Macaron does # not use this transitive dependency and we can ignore them for now. Remove them when semgrep is updated and uses @@ -319,8 +312,7 @@ audit: echo "No package pip_audit installed, upgrade your environment!" && exit 1; \ fi; python -m pip_audit --skip-editable --desc on --fix --dry-run \ - --ignore-vuln GHSA-vfmq-68hx-4jfw --ignore-vuln PYSEC-2026-2132 --ignore-vuln GHSA-hvrp-rf83-w775 \ - --ignore-vuln GHSA-jpw9-pfvf-9f58 --ignore-vuln GHSA-vj7q-gjh5-988w + --ignore-vuln GHSA-hvrp-rf83-w775 --ignore-vuln GHSA-jpw9-pfvf-9f58 --ignore-vuln GHSA-vj7q-gjh5-988w # Run some or all checks over the package code base. .PHONY: check check-code check-ruff check-lint check-mypy check-go check-actionlint diff --git a/pyproject.toml b/pyproject.toml index 1e65ca7a6..5b714de2b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ dependencies = [ "beautifulsoup4 >=4.12.0,<5.0.0", "problog >=2.2.6,<3.0.0", "cryptography >=48.0.1,<49.0.0", - "semgrep == 1.151.0", + "semgrep == 1.171.0", "email-validator >=2.2.0,<3.0.0", "rich >=13.5.3,<15.0.0", "lark >=1.3.0,<2.0.0", diff --git a/src/macaron/policy_engine/policy_engine.py b/src/macaron/policy_engine/policy_engine.py index 73b7da0cb..fc9aaa0d4 100644 --- a/src/macaron/policy_engine/policy_engine.py +++ b/src/macaron/policy_engine/policy_engine.py @@ -46,17 +46,20 @@ def get_generated(database_path: os.PathLike | str) -> SouffleProgram: metadata = MetaData() engine = create_engine(f"sqlite:///{database_path}", echo=False) - metadata.reflect(engine) + try: + metadata.reflect(engine) - prelude = get_souffle_import_prelude(os.path.abspath(database_path), metadata) + prelude = get_souffle_import_prelude(os.path.abspath(database_path), metadata) - 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)) - prelude.update(project_with_fk_join(table)) + 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)) + prelude.update(project_with_fk_join(table)) - return prelude + return prelude + finally: + engine.dispose() def copy_prelude( @@ -130,18 +133,16 @@ def _check_version(database_path: str) -> None: The path to the macaron database """ engine = create_engine(f"sqlite:///{database_path}", echo=False) - - with engine.connect() as conn: - versions = conn.execute( - select(Analysis.macaron_version).where(Analysis.macaron_version != mcn_version) - ).scalar() - if versions is not None: - logger.error("Database generated with unsupported versions (%s).", versions) - logger.error( - "Only databases generated by Macaron version %s are supported.", - mcn_version, - ) - sys.exit(os.EX_DATAERR) + try: + with engine.connect() as conn: + versions = conn.execute( + select(Analysis.macaron_version).where(Analysis.macaron_version != mcn_version) + ).scalar() + if versions is not None: + logger.error("Database generated with unsupported versions (%s).", versions) + sys.exit(os.EX_DATAERR) + finally: + engine.dispose() def show_prelude(database_path: str) -> None: diff --git a/tests/build_spec_generator/test_macaron_db_extractor.py b/tests/build_spec_generator/test_macaron_db_extractor.py index 03de0d8c4..6539de8a5 100644 --- a/tests/build_spec_generator/test_macaron_db_extractor.py +++ b/tests/build_spec_generator/test_macaron_db_extractor.py @@ -48,6 +48,7 @@ def macaron_db_session() -> Generator[Session, Any, None]: yield session session.close() + engine.dispose() @pytest.fixture() @@ -64,6 +65,7 @@ def invalid_db_session() -> Generator[Session, Any, None]: yield session session.close() + engine.dispose() @pytest.mark.parametrize( diff --git a/tests/database/test_database_manager.py b/tests/database/test_database_manager.py index 138777cb2..aa64a2504 100644 --- a/tests/database/test_database_manager.py +++ b/tests/database/test_database_manager.py @@ -6,6 +6,7 @@ import os import sqlite3 from collections.abc import Iterable +from contextlib import closing from pathlib import Path import pytest @@ -37,11 +38,13 @@ def db_man() -> Iterable: """Set up the database and ensure it is empty.""" db_manager = DatabaseManager(DB_PATH, base=Base) con = sqlite3.connect(DB_PATH) - with con: + with closing(con), con: con.execute("drop table if exists _test_orm_table;") con.execute("drop view if exists test_orm_table;") con.commit() + yield db_manager + db_manager.engine.dispose() os.remove(DB_PATH) @@ -66,7 +69,7 @@ def test_orm_mapping( query = "select * from _test_orm_table;" con = sqlite3.connect(DB_PATH) - with con: + with closing(con), con: cursor = con.execute(query) rows = cursor.fetchall() assert (str(rows) == str([(identifier, test_value)])) == expect diff --git a/tests/slsa_analyzer/checks/test_github_actions_vulnerability_check.py b/tests/slsa_analyzer/checks/test_github_actions_vulnerability_check.py index a58ceaf2b..151ffb1e9 100644 --- a/tests/slsa_analyzer/checks/test_github_actions_vulnerability_check.py +++ b/tests/slsa_analyzer/checks/test_github_actions_vulnerability_check.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 GitHub Actions vulnerabilities check.""" @@ -58,6 +58,7 @@ def test_github_actions_vulns( httpserver: HTTPServer, tmp_path: Path, macaron_path: Path, + monkeypatch: pytest.MonkeyPatch, ci_name: str, ci_services: dict[str, BaseCIService], expected: str, @@ -96,6 +97,10 @@ def test_github_actions_vulns( httpserver.expect_request("/v1/query").respond_with_json(query_json) httpserver.expect_request("/v1/querybatch").respond_with_json(query_batch_json) + # Keep the test offline: resolving a mutable GitHub Action ref otherwise + # issues a live GitHub API request and can block on rate-limit backoff. + monkeypatch.setattr(ci_services["github_actions"].api_client, "get_commit_sha_from_ref", lambda *_: None) + ctx.dynamic_data["ci_services"] = [get_ci_info(ci_services, ci_name, gha_source_path)] assert check.run_check(ctx).result_type == expected