Plugin package for the csspin task runner. Bundles miscellaneous utility plugins.
Wraps the sbomasm CLI. Exposed as a
task group with one task, hooked into the sbom:* lifecycle via when=:
sbomasm assemble(when="sbom:assemble") — resolves a primary SBOM from theprimary_sbomglob (the Python SBOM by default) and extends it with every other*.cdx.jsonSBOM found alongside it viasbomasm assemble --flatMerge --primary. With only the primary present, the merge is a pass-through copy. A glob matching nothing is a hard error. Input SBOMs are expected to already carry their own metadata (name, version, author, license) — this plugin does no enrichment of its own.
provision(cfg) always downloads the sbomasm release binary (Linux/Windows
x86_64) into {spin.data}/csspin_tooling/sbomasm/{version} if not cached.
The init hook prepends that versioned dir to PATH (same pattern as
sbomqs), so tasks invoke the binary as plain sbomasm. There is no use
override.
Wraps the sbomqs CLI. Quality gate for
the assembled SBOM. Exposed as a task group with two tasks, both hooked into the
sbom:quality lifecycle via when=:
sbomqs policy— runssbomqs policy -f <policy_file> <input_file>viash(check=True), so a policy violation makes the task exit non-zero. The policy applies uniformly to every component, including nested ones.sbomqs comp-valid-licenses(functioncomp_valid_licenses, click hyphenates the name) — runssbomqs list --feature comp_valid_licenses --missing --jsonand dies if any component is reported.comp_valid_licensesis a generic feature (no--profileneeded). It was added upstream in sbomqs #700 (released in 2.0.11) and validates each license against the SPDX license expression specification (SPDX-listed IDs,LicenseRef-references,AND/OR/WITHexpressions), flagging only strings that are not valid SPDX expressions.--missingalso reports components with no license at all, so the task gates on invalid-or-missing licenses. Components listed underfiles[].componentsin that JSON are the offending ones. The task is covered by the integration tests; there are no unit tests for the parsing.
provision(cfg) always downloads the sbomqs release binary (Linux/Windows
x86_64) into {spin.data}/csspin_tooling/sbomqs/{version}. The download itself
is cached. Same tar.gz layout as sbomasm.
The init hook prepends that versioned dir to PATH (same pattern as
csspin_java.java / csspin_ce.mkinstance), so the binary is discoverable on
every task. The policy task resolves it inline with shutil.which("sbomqs").
There is no use override.
The policy_file default is a callable (default_policy_file) resolving via
importlib.resources to the bundled policies/default.yaml; the configure
hook materializes it during defaults (same pattern as csspin_ce.mkinstance). A
configured path replaces it entirely. The default blacklists copyleft licenses
(^GPL-.*, ^AGPL-.*, EUPL-.*,
CC-BY-SA/NC/ND) and requires name/version/license on every component.
Downloads the VEX file for a project from a Dependency-Track instance.
fetch_vex— looks up the project UUID via the DepTrack API, fetches its CycloneDX VEX data, and writes it totarget_directory. The filename is derived from/metadata/componentname+version (slugified), falling back tovex.json(which then raises, since that signals invalid VEX data).
Runtime dep: requests. No provision step.
sbomasm_schema.yaml—version(sbomasm release),install_dir,output_file(default{spin.project_name}.cdx.json),primary_sbom(glob, default{spin.project_name}*.python_sbom.cdx.json),format.spec(cyclonedxorspdx),format.version.sbomqs_schema.yaml—version(sbomqs release),install_dir,input_file(default{spin.project_name}.cdx.json),policy_file(callable default → bundled policy, resolved inconfigure; else path override).fetch_vex_schema.yaml—project_name,project_version,deptrack_url,deptrack_api_key(secret),cyclonedx_version,target_directory. All four of url/api_key/project_name/project_version are required at runtime; the task dies if any is missing.
- Runtime (
pyproject.toml):csspin-python,requests. - Sibling plugins:
csspin(core),csspin-python(produces the*.python_sbom.cdx.jsonfilesbomasmuses as its default primary SBOM). - Build/dev: setuptools, setuptools_scm, pytest, pytest-cov, mypy, pylint, black, isort.
uv venv venv
source venv/bin/activate # required for spin/pytest to be on PATH
uv pip install -r requirements-dev.txt # installs spin + dev deps
spin provision # provision the project for running spin tasks
pytest tests/ # run tests
prek run --all-files # run linting and formattingrequirements-dev.txtis the single source of truth for the dev env: it pulls inspinitself plus everything needed to develop and test the plugin. No separatepip install -e .step.- Tests run via plain
pytest, notspin test.tests/unit/holds the unit tests (test_sbomasm.py,test_sbomqs.py,test_fetch_vex.py);tests/integration/shells out tospin(via the sharedexecute_spinhelper intests/integration/helpers.py) to exercise provisioning and the real tool binaries end-to-end. - Run provisioning tests only in case something for the provisioning has changed.
- Single test:
pytest tests/unit/test_sbomqs.py::test_name. Skip the slow integration tests during regular iteration withpytest -m "not integration". tests/integration/test_sbomqs.pyrunscomp-valid-licensesagainst the fixture SBOMs intests/integration/sboms/. Both are realspin sbomoutput from cs.template, with the component renamed tosome-dummy-package.valid-licenses.cdx.jsoncarriesLicenseRef-CONTACT-Software-General-1.0, which sbomqs 2.0.10 and 2.0.11 wrongly reject, so the test fails if the version pin drops below 2.0.12.invalid-licenses.cdx.jsonis the same SBOM with that license written as plain text (noLicenseRef-prefix), which is not a valid SPDX expression. The tests assert nothing about output: the task either exits zero or dies.spin <task>is for exploratory verification — e.g., runningspin sbomasm assemble/spin sbomqs policy/spin fetch_vexto confirm the plugins behave as expected during development. It is not the test runner.- Python ≥3.10.
- Pre-commit hooks (run via
prek): mypy (strict), pylint, black, isort.
- CycloneDX is the default SBOM format; SPDX is reachable via the
sbomasmschema config, not a separate task. sbomasmdoes no enrichment — the primary SBOM it extends must already carry complete metadata (name, version, author, license); that's produced upstream (e.g. bycsspin-python's SBOM generation), not by this plugin.- Docs:
doc/is built withcsspin_docs.sphinx. Schema reference pages are generated from the schemas viaschemadocbuild rules inspinfile.yaml.