Try it on the examples¶
The repository has more than a hundred real projects to try pixi-sbom on. There are fourteen
Python scenarios, from a Django app on an old LTS to an LLM stack, each locked by every tool pixi-sbom
reads, and three conda-only ones with R, Go and JavaScript packages in them. Every lockfile was written by the tool that owns its format. Some scenarios have known
vulnerabilities, one has a GPL package, one is an upgrade of another, and a separate set of
requirements.txt files is built to be refused.
Nothing needs installing beyond pixi-sbom itself (Installation). Get the examples with a clone:
Every command below runs from there. A test runs each one as written, so they work. The commands marked
# needs the network look things up online (OSV, CISA KEV, FIRST EPSS, the package indexes); the
rest work offline.
What's there¶
examples/projects/<reader>/<NN-scenario>/
examples/projects/requirements-unpinned/<NN-name>/
examples/projects/container/20-images/
| Reader | What each example has |
|---|---|
pixi |
pixi.toml, pixi.lock, one environment per dependency group and extra |
uv |
pyproject.toml, uv.lock |
poetry |
pyproject.toml, poetry.lock |
pdm |
pyproject.toml, pdm.lock |
pylock |
pyproject.toml, pylock.toml |
conda-lock |
environment.yml, conda-lock.yml |
conda-explicit |
environment.yml, explicit-linux-64.txt, explicit-osx-arm64.txt |
requirements |
requirements.in / .txt and requirements-dev.in / .txt, compiled and hashed |
npm, yarn, yarn-berry, pnpm |
package.json and the lockfile its tool wrote: package-lock.json, yarn.lock (v1, Berry), pnpm-lock.yaml |
container |
two container images, unpacked and trimmed to what pixi-sbom reads, with the Dockerfiles and build.sh that make them |
The scenarios worth knowing first:
| Scenario | Why try it |
|---|---|
01-django |
Django 3.2.12 with known advisories, an editable local package, a git dependency, an extra and two groups |
02-flask |
a 2021-era stack: urllib3 1.26.4, Werkzeug 2.0.2, several findings |
07-web-scraping |
html2text is GPL-3.0, for the license gate |
08-cli-tool |
nothing wrong with it, which is what a clean report looks like |
14-django-upgraded |
01-django after the upgrade: the other side of a diff |
15-r-analysis |
R packages with CRAN purls, and a CRAN advisory through --vulnerabilities osv |
16-go-tools |
the Go modules inside go-yq and gh, with --prefix --embedded-sboms |
17-node-tools |
the npm packages nodejs installs, with --prefix |
18-image-wheels |
Pillow 10.0.0, whose wheels bundle libwebp, libpng, zlib and more, with --prefix --embedded-sboms |
19-web-frontend |
a JavaScript frontend locked by npm, yarn and pnpm, and a pixi workspace with it beside, merged into one document |
20-images |
02-flask installed into two container images, a venv on the official Python image and pixi's production layout, unpacked for --scan |
15 to 18 describe what an installed environment holds, so install one first and point --prefix at it:
pixi install --manifest-path examples/projects/pixi/16-go-tools/pixi.toml
pixi sbom --prefix examples/projects/pixi/16-go-tools/.pixi/envs/default --embedded-sboms --report packages # after pixi install
examples/README.md in the repository lists all twenty, with what each one shows.
The conda and pixi examples are locked for linux-64 and osx-arm64, so the commands below pass
-p linux-64 to give the same answer on any machine.
One document from every kind of lockfile¶
The same scenario through each reader. The package count differs between conda and PyPI, because a conda environment carries the interpreter and system libraries too.
pixi sbom --lockfile examples/projects/pixi/01-django/pixi.lock -p linux-64 --report packages
pixi sbom --lockfile examples/projects/uv/01-django/uv.lock -p linux-64 --report packages
pixi sbom --lockfile examples/projects/poetry/01-django/poetry.lock -p linux-64 --report packages
pixi sbom --lockfile examples/projects/pdm/01-django/pdm.lock -p linux-64 --report packages
pixi sbom --lockfile examples/projects/pylock/01-django/pylock.toml -p linux-64 --report packages
pixi sbom --lockfile examples/projects/conda-lock/01-django/conda-lock.yml -p linux-64 --report packages
pixi sbom --lockfile examples/projects/conda-explicit/01-django/explicit-linux-64.txt --report packages
pixi sbom --lockfile examples/projects/requirements/01-django/requirements-dev.txt --report packages
Writing the document rather than a table, in either format:
pixi sbom --lockfile examples/projects/uv/01-django/uv.lock -p linux-64 --output -
pixi sbom --lockfile examples/projects/uv/01-django/uv.lock -p linux-64 --format spdx --spec-version 3.0 --output -
See Using pixi-sbom without pixi for what each reader takes from its lockfile.
A JavaScript frontend¶
The same frontend, locked by npm, yarn 1, yarn 4 (Berry) and pnpm: four lockfiles, the same 29 pkg:npm releases.
semver is a development dependency, so it and what it needs are scope: optional.
pixi sbom --lockfile examples/projects/npm/19-web-frontend/package-lock.json --report packages
pixi sbom --lockfile examples/projects/yarn/19-web-frontend/yarn.lock --report packages
pixi sbom --lockfile examples/projects/yarn-berry/19-web-frontend/yarn.lock --report packages
pixi sbom --lockfile examples/projects/pnpm/19-web-frontend/pnpm-lock.yaml --report packages
The pixi workspace in pixi/19-web-frontend has the same frontend beside its pixi.toml. Read from its directory or
named with --lockfile, the workspace and the frontend are one document, and --skip-input javascript leaves the frontend out:
pixi sbom --lockfile examples/projects/pixi/19-web-frontend/pixi.lock -p linux-64 --report packages
pixi sbom --lockfile examples/projects/pixi/19-web-frontend/pixi.lock -p linux-64 --skip-input javascript --report packages
See Reading JavaScript lockfiles.
Libraries inside wheels, and where everything was found¶
Pillow 10.0.0's wheels carry their own libwebp, libpng, zlib, libjpeg-turbo and more in pillow.libs/ (Linux) or
PIL/.dylibs/ (macOS). Installed, --embedded-sboms reads each one's version out of the binary and lists it under
Pillow, with the CPE a scanner matches: the libwebp is 1.3.1, the release CVE-2023-4863 was fixed after.
pixi install --manifest-path examples/projects/pixi/18-image-wheels/pixi.toml
pixi sbom --prefix examples/projects/pixi/18-image-wheels/.pixi/envs/default --embedded-sboms --vulnerabilities osv --report vulnerabilities # after pixi install
Any installed example also says where each component was found, as CycloneDX evidence.occurrences: the conda-meta
record, the dist-info, and for 16-go-tools and 18-image-wheels the binary each module or library was read from.
pixi sbom --prefix examples/projects/pixi/18-image-wheels/.pixi/envs/default --embedded-sboms --output - # after pixi install
See Bundled native libraries and Installed environments.
Every environment in a container image¶
20-images holds two images built from 02-flask, exported with docker export and trimmed to the metadata
pixi-sbom and syft read (build.sh beside them rebuilds both):
python-app/: the officialpython:3.11-slimimage with the application pip-installed into/app/.venv; the image's own Python installation in/usr/localis the second environment.pixi-app/: pixi's production layout, the environment installed in a build stage and copied to/app/.pixi/envs/defaulton a slim image, without the manifest or the lockfile.
--scan finds each installed environment and names it by its path in the image; --merge makes one document:
pixi sbom --scan examples/projects/container/20-images/python-app --merge --report packages
pixi sbom --scan examples/projects/container/20-images/pixi-app --merge --primary-purl pypi --output -
The image's operating system packages are not in the trimmed tree, and are syft's in any case. See An unpacked container image.
A requirements file that is not a lock¶
A requirements.txt is only a lock when every line is one version. Each project in
requirements-unpinned/ fails in a different way, and pixi-sbom refuses each one, naming the first
line that isn't one version:
pixi sbom --lockfile examples/projects/requirements-unpinned/01-loose-ranges/requirements.txt --output - # exit 1
pixi sbom --lockfile examples/projects/requirements-unpinned/03-one-loose-line/requirements.txt --output - # exit 1
pixi sbom --lockfile examples/projects/requirements-unpinned/05-wildcard-pins/requirements.txt --output - # exit 1
The third one is the subtle one: Django==4.2.* looks pinned and is any 4.2 release. See
Reading a pinned requirements.txt.
Every environment of a pixi workspace¶
pixi/01-django has a default environment and one each for its s3 extra and its dev and test
groups. --all-environments writes one document each into a directory:
pixi sbom --lockfile examples/projects/pixi/01-django/pixi.lock -p linux-64 --all-environments --output sboms/
See One document per environment and platform.
Where a fact came from¶
internal-utils is a local package installed in editable mode. --explain shows what pixi-sbom
knows about it and what it deliberately doesn't ask an index about:
Before and after an upgrade¶
14-django-upgraded is 01-django moved to Django 4.2 LTS:
pixi sbom --lockfile examples/projects/uv/14-django-upgraded/uv.lock -p linux-64 --report diff --against examples/projects/uv/01-django/uv.lock
See Looking instead of writing.
Vulnerabilities, and which to fix first¶
02-flask has several findings. CISA KEV marks the ones being exploited now, and FIRST EPSS scores
how likely the rest are to be exploited:
pixi sbom --lockfile examples/projects/uv/02-flask/uv.lock -p linux-64 --vulnerabilities osv --kev --epss --report vulnerabilities # needs the network
The same findings as a CI gate. The document is still written, and the run exits 4:
pixi sbom --lockfile examples/projects/uv/02-flask/uv.lock -p linux-64 --vulnerabilities osv --fail-on-severity high --output - # needs the network
08-cli-tool has none, which is the answer a clean project gets:
pixi sbom --lockfile examples/projects/uv/08-cli-tool/uv.lock -p linux-64 --vulnerabilities osv --report vulnerabilities # needs the network
See Looking up vulnerabilities.
A license gate¶
07-web-scraping depends on html2text, which is GPL-3.0. Its wheel doesn't say so in a form a policy
can match: it declares the free text GNU GPL 3. A deny list matches SPDX ids, so on its own it
passes this project:
pixi sbom --lockfile examples/projects/uv/07-web-scraping/uv.lock -p linux-64 --fetch-licenses --deny-license GPL-3.0-only --deny-license GPL-3.0-or-later --output - # needs the network
--require-license closes that gap: a license that isn't an SPDX expression becomes a violation. The
run names html2text and exits 3:
pixi sbom --lockfile examples/projects/uv/07-web-scraping/uv.lock -p linux-64 --fetch-licenses --deny-license GPL-3.0-only --deny-license GPL-3.0-or-later --require-license --output - # needs the network
See Enforcing a license policy.
How far behind¶
04-data-analysis pins a scientific stack well behind its newest releases:
pixi sbom --lockfile examples/projects/poetry/04-data-analysis/poetry.lock -p linux-64 --report outdated # needs the network
See How far behind the environment is.
Someone else's SBOM¶
Make two documents, then treat them as if a vendor had sent them: grade one, and merge both into one document for the product:
pixi sbom --lockfile examples/projects/uv/01-django/uv.lock -p linux-64 --output app.cdx.json
pixi sbom --lockfile examples/projects/requirements/12-aws-cloud/requirements.txt --format spdx --output vendor.spdx.json
pixi sbom --from-sbom vendor.spdx.json --report quality
pixi sbom --from-sbom app.cdx.json --from-sbom vendor.spdx.json --root-name product --report packages
See How complete the document is and Merging documents.
The whole tree at once¶
--scan finds every project with a lockfile of a fixed name under a directory: the pixi, uv,
Poetry, PDM, pylock and conda-lock examples, and the JavaScript ones (the frontend beside the pixi workspace joins
that workspace's document), and the three installed environments in the two container images, 100 in all. Explicit
specs and requirements files have no fixed name, so a scan doesn't pick them up.
See A monorepo: every workspace in one run.
What changes from day to day¶
The lockfiles don't change, so anything read from them doesn't either: the packages, the graph, the diff and the refusals. Anything looked up online does. New advisories are published every day, EPSS scores are recomputed daily, and the indexes keep releasing. The vulnerability counts and the outdated report you see will drift from what anyone saw before you, and that's the tool working.