diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b42d730d..1981cb14 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -80,6 +80,7 @@ jobs: NUITKA_CCACHE_BINARY: /usr/bin/ccache run: | pip install .[build] + python script/create_sbom.py python script/build.py python script/package.py @@ -92,6 +93,7 @@ jobs: build/dfetch-package/*.rpm build/dfetch-package/*.pkg build/dfetch-package/*.msi + build/dfetch-package/*.cdx.json test-binary: name: test binary diff --git a/.gitignore b/.gitignore index 9f68b6a0..f420ad5d 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ doc/_build doc/landing-page/_build example/Tests/ venv* +*.cdx.json diff --git a/pyproject.toml b/pyproject.toml index 56aa9f4e..b2a782a5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,6 +105,7 @@ build = [ 'nuitka==2.8.9', "tomli; python_version < '3.11'", # Tomllib is default in 3.11, required for letting codespell read the pyproject.toml] ] +sbom = ["cyclonedx-bom==7.2.1"] [project.scripts] dfetch = "dfetch.__main__:main" diff --git a/script/create_sbom.py b/script/create_sbom.py new file mode 100644 index 00000000..ddf3b5cf --- /dev/null +++ b/script/create_sbom.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +"""Generate an sbom of the tool.""" +import contextlib +import logging +import subprocess # nosec +import sys +import tempfile +import venv +from pathlib import Path + +from dfetch import __version__ + +logging.basicConfig(level=logging.INFO) + +PROJECT_DIR = Path(__file__).parent.parent.resolve() +OUTPUT_FILE = ( + PROJECT_DIR + / "build" + / "dfetch-package" + / f"dfetch-{__version__}.{sys.platform}.cdx.json" +) + +DEPS = f"{PROJECT_DIR}[sbom]" + + +@contextlib.contextmanager +def temporary_venv(): + """Create a temporary virtual environment and clean it up on exit.""" + with tempfile.TemporaryDirectory(prefix="venv_sbom_") as tmpdir: + venv_dir = Path(tmpdir) + logging.info(f"Creating temporary virtual environment at {venv_dir}") + venv.create(venv_dir, with_pip=True, upgrade_deps=True) + + if sys.platform.startswith("win"): + python_bin = venv_dir / "Scripts" / "python.exe" + else: + python_bin = venv_dir / "bin" / "python" + + yield str(python_bin) + + +with temporary_venv() as python: + OUTPUT_FILE.parent.mkdir(parents=True, exist_ok=True) + subprocess.check_call([python, "-m", "pip", "install", DEPS]) # nosec + subprocess.check_call( # nosec + [python, "-m", "cyclonedx_py", "environment", "-o", str(OUTPUT_FILE)] + ) + +logging.info(f"SBOM generated at {OUTPUT_FILE}")