Installation & access
SBOMFlow is a standard-library Python CLI with zero required runtime dependencies. It requires Python 3.11 or newer and runs fully offline on a laptop or in locked-down CI.
Important
SBOMFlow is in an early, invite-only phase while we work directly with a
small number of design partners, and the source is not publicly distributed
yet. To evaluate it on your own build, request access below — we'll set up a
short call and get you a copy to test. Public pipx, PyPI, and Homebrew
channels will follow the first release.
Request access to evaluate#
Want to run SBOMFlow against a real build of your own? Email hello@sbomflow.com with a line about your product and build system (Yocto, Zephyr, Buildroot, or other). We'll arrange a short call to understand your release workflow and set you up with an evaluation copy.
The engine runs fully offline on your own machines, so nothing about your source, firmware, or findings ever leaves your environment — evaluating it does not send us your code.
Install your evaluation copy#
Once you have your evaluation copy, install it into a clean virtual environment from the source tree provided to you:
cd sbomflow # the source tree provided with your evaluation access
python -m pip install .
sbomflow --versionThis installs the sbomflow entry point. Verify it resolves:
sbomflow doctor .Optional extras#
Some optional capabilities use the cryptography package. Build-provenance verification uses the attest extra and bundle signing uses the sign extra; the baseline engine never requires either:
python -m pip install ".[attest,sign]"Offline
Installing the core touches nothing over the network — it has zero
dependencies; only the optional extras above fetch third-party packages.
Running SBOMFlow afterwards is offline by default.
Air-gapped install (no package index)#
For machines with no PyPI egress, build a self-contained bundle on a networked machine and carry it across:
make offline-installer # -> dist/offline/ and a reproducible dist/sbomflow-offline-<version>.zipThe bundle holds the wheel, the sdist, a SHA256SUMS file, and an INSTALL.txt with the exact digests and verify-then-install steps. On the air-gapped machine:
sha256sum -c SHA256SUMS
python3 -m venv /opt/sbomflow-venv
/opt/sbomflow-venv/bin/python -m pip install --no-index --no-deps ./sbomflow-<version>-py3-none-any.whl
/opt/sbomflow-venv/bin/sbomflow --version--no-index forbids any index lookup, and --no-deps is safe because the core has zero required runtime dependencies. A CI lane performs exactly this install on pull requests and on the nightly schedule — not on pushes to main — so a core that grew a dependency would fail that build; the same check runs locally in make install-check.
The bundle builder never reaches the network. Optional extras have third-party dependencies, so they are included only when you supply your own wheelhouse — and when you do not, INSTALL.txt says so plainly instead of shipping a core-only bundle that looks complete:
pip download 'sbomflow[yaml,validate,attest,sign]' -d ./wheelhouse # networked machine
make offline-installer EXTRAS_DIR=./wheelhouseThe checksums prove the bytes you received match the bytes the build produced. They are not a signature and do not establish who built them.
Deployment contexts#
| Context | Installation and durable state |
|---|---|
| Non-admin workstation | Use a virtual environment (preferred), or python -m pip install --user . when local policy permits it. Keep the evidence store and vulnerability snapshots in operator-owned directories with access limited to the reviewers who need them. |
| CI container | Mount persistent volumes for the evidence store and vulnerability database; do not leave either only in the container filesystem. Pin the evaluation-copy revision or wheel digest, run offline by default, and make network enrichment an explicit job choice. |
| Ephemeral CI runner | Restore the evidence store and .sbomflow-vulndb from an access-controlled cache or artifact before the run, then persist the updated state after a successful run. If neither is restored, the job starts without release history or cached snapshot state; it must not describe that absence as a clean result. |
| Locked-down enterprise | Use the air-gapped bundle or an internally mirrored, digest-verified wheel. Run under a dedicated unprivileged account, keep source and evidence on approved local storage, permit no egress by default, and inject credentials only for an explicitly enabled integration. |
A minimal container job should bind durable host or managed-runner storage rather than the image layer. Adapt the paths to your runner and access policy:
docker run --rm --network none \
--mount type=bind,src="$PWD/product",dst=/work/product,readonly \
--mount type=volume,src=sbomflow-store,dst=/var/lib/sbomflow/store \
--mount type=volume,src=sbomflow-vulndb,dst=/var/lib/sbomflow/vulndb \
sbomflow-evaluation:local \
sbomflow analyze /work/product --output /var/lib/sbomflow/store/currentThe store and vulnerability database can contain release metadata and security findings. Back them up, restrict their readers, and apply the same retention and incident-response controls as other product-security evidence.
Measured capacity reference#
The current synthetic 50,000-component reference pack measured approximately 187 MB of output and 0.85 GB peak resident memory. This is a CI alarm reference, not a supported ceiling, performance guarantee, SLA, or prediction for a particular firmware estate. Input shapes, dependency density, findings, filesystem behavior, and optional artifacts can materially change both figures. Validate the complete workflow with your own representative build artifacts and leave headroom for the Python process, temporary files, and retained releases.
Compatibility matrix#
"Python 3.11 or newer" is a floor, not a promise. The honest answer to "is my Python and OS supported?" has three parts: which CI lane covers the combination, which events actually trigger that lane, and whether the lane has ever completed green. A lane that exists but is skipped on your change proves nothing, and a lane that runs and fails is not the same as one that was never tried. The table below is kept in lockstep with .github/workflows/ci.yml by two drift tests — one pins the combinations, one pins the trigger of each row — so neither can quietly fall out of date.
Verification states below were read from the complete GitHub Actions history for ci.yml: 1,468 workflow runs and every job inside the 174 of them that were not push events, measured on 2026-08-10.
| Python | Operating system | Status |
|---|---|---|
| 3.11 | Ubuntu (ubuntu-latest) | Runs make test + make demo on every push; has completed green |
| 3.12 | Ubuntu (ubuntu-latest) | Runs make test + make demo on pull requests, the nightly schedule and manual dispatch — not on pushes to main; has completed green |
| 3.13 | Ubuntu (ubuntu-latest) | Runs make test + make demo on pull requests, the nightly schedule and manual dispatch — not on pushes to main; has completed green |
| 3.14 | Ubuntu (ubuntu-latest) | Runs make test on every push (optional-extras lane), plus make test + make demo on pull requests and nightly; has completed green |
| 3.14 | macOS on Apple Silicon (macos-latest) | Runs make test + make demo on pull requests, the nightly schedule and manual dispatch — not on pushes to main; has completed green |
| 3.14 | Windows (windows-latest) | Runs make test (invoked directly — Windows has no make) on pull requests, the nightly schedule and manual dispatch — not on pushes to main. Has never completed green: 159 lane runs, 152 of them completed and failed, zero passes. Native Windows is not a supported platform — see below |
Read the trigger column carefully before drawing conclusions from a green build badge on main. A push to main runs the Ubuntu 3.11 lane, the 3.14 optional-extras lane, the linting/typing lane and the memory-budget lane, and skips the 3.12/3.13/3.14 interpreter fan-out, macOS, Windows, the reproducible-build check and the air-gapped installer check. A green push run is therefore evidence about Ubuntu on two interpreters, and about nothing else.
macOS and Windows each run one interpreter lane deliberately: a second and third operating system catch OS differences (paths, file locking, archive behaviour) — Windows most of all, since it is the one platform whose file-locking primitive differs (msvcrt rather than POSIX flock) — while the four-minor interpreter spread is covered by the Ubuntu rows above.
Two combinations carry no verification, for two different reasons. They are named rather than left to inference, and the two reasons are not merged into one word:
- macOS on Intel — Unverified. No CI lane exists and no run has been performed, so nothing is known either way.
- Native Windows — tested and red, which is a different and stronger statement than unverified. A lane exists, runs on every pull request and every nightly, and has never passed. The next section says exactly what it reports.
Everything else this project has merged was verified on macOS on Apple Silicon (Darwin arm64) with CPython 3.14, by running the offline suite and the aggregate make gates battery locally before the push. That battery covers no other operating system and no packaging step — wheel and sdist reproducibility and the air-gapped install are proven only by the CI lanes above, which do not run on pushes to main.
It reaches a second interpreter in exactly one place, and the scope is worth stating precisely rather than rounding up. The timestamp-parsing tests re-run their corpus under every other CPython installed on the machine, because datetime.fromisoformat accepts different spellings on different minors and a suite that measures one interpreter cannot see that split at all. Those tests find interpreters by searching known install locations and confirming each one by executing it, not by trusting PATH — an earlier PATH-only search meant they skipped silently in every gate run while the run still reported OK. When the machine genuinely has only one interpreter they skip, and say which of those two facts applies; a search that finds nothing at all fails instead of skipping.
This is agreement about timestamp parsing, on whatever interpreters happen to be installed. It is not a cross-interpreter determinism check, it does not prove byte-identical evidence across versions, and it claims nothing about a minor that is not installed locally. The published support matrix is still carried by the CI lanes above.
Windows: use WSL#
Run SBOMFlow on Windows through WSL. Native Windows is not a supported platform today, and this section says plainly why rather than leaving you to discover it.
The native-Windows CI lane runs and has never passed. Of 159 lane runs since it was added, 152 completed and every one of them failed; the other 7 were cancelled by a newer commit, so they produced no result either way. Zero passes.
What the lane reports is specific, so it is quoted rather than summarised: the most recent completed runs execute the whole offline suite and end with
Ran 10140 tests in 2138.792s
FAILED (failures=86, errors=13, skipped=149)Roughly 99 checks out of about 10,100 fail on native Windows, consistently across runs. That is a bounded, real defect surface — not a lane that never got started, and not a platform that quietly works. Until those failures are fixed and the lane runs green, any claim that native Windows works would be a guess, and this page will state the result when there is one.
The reviewer decision-write lock is OS-backed on Windows — an exclusive msvcrt byte-range lock, not a no-op that would let two concurrent sbomflow review processes clobber a decision. That is a real piece of Windows support, and it is still not sufficient on its own to call the platform verified.
Under WSL you are on a Linux environment, which matches the Ubuntu rows above — those rows have completed green, so WSL rests on verified ground rather than on hope. Two further things about Windows-shaped input are worth stating:
- Path-traversal safety is hardened for Windows-shaped input. SBOMFlow only ever writes POSIX member names, and a dedicated robustness suite proves the single shared safety gate refuses the full Windows attack surface — backslash separators (
..\..\etc), UNC and\\?\device paths, drive-absolute and drive-relative specs (C:\…,C:file), and NTFS alternate data streams (file:$DATA) — while ordinary relative members are still accepted. - Reserved device names are a known native-Windows edge. A member literally named
CON,NUL, orCOM1is a device on native Windows; SBOMFlow treats it as an ordinary relative name (refusing every such name would reject legitimate files likeaux.jsonelsewhere). This is one concrete reason WSL is the recommended Windows path.
Minimum Python & support window#
SBOMFlow requires Python 3.11 or newer. requires-python guards pip install, but a direct source or PYTHONPATH run on an older interpreter is also handled gracefully: SBOMFlow checks the interpreter before loading the CLI and, on anything below 3.11, prints one clear line and exits with code 2 —
SBOMFlow requires Python 3.11 or newer (found 3.10.x).— instead of a cryptic SyntaxError from deep in the import chain. The supported window tracks the compatibility matrix above: the floor rises only when the oldest listed version does, and never silently.
Support policy. Every CPython minor version from 3.11 through the newest stable release has a CI lane, and every one of them has completed green. Only the floor (3.11) runs on every push; the full interpreter fan-out runs on pull requests, the nightly schedule and manual dispatch, as the table above records per row. A new stable minor joins the matrix within one SBOMFlow release of its GA. Pre-release interpreters are never listed. The requires-python floor, the Programming Language :: Python :: classifiers, the CI matrix, and the table above are held in agreement by a drift test, so this is a checked fact rather than a promise.
Man page and shell completions#
A troff man page and static bash/zsh completions ship in the repository, generated from the real CLI parser (so they never drift from the commands --help prints) and drift-guarded by tests. Install them optionally:
# man page
sudo install -m 0644 docs/sbomflow.1 /usr/local/share/man/man1/sbomflow.1
man sbomflow
# bash completion (adjust the path for your distro)
sudo install -m 0644 completions/sbomflow.bash /etc/bash_completion.d/sbomflow
# zsh completion (place on your $fpath, then rebuild the completion cache)
sudo install -m 0644 completions/_sbomflow /usr/local/share/zsh/site-functions/_sbomflowThe shipped man page and completions are generated directly from the CLI parser, so they always match the current commands. SBOMFlow never auto-installs into your shell.
Uninstall, cleanup, and offboarding#
SBOMFlow is easy to remove completely, which matters for a controlled pilot: a partner should be able to prove nothing lingers on their machines afterwards.
What SBOMFlow writes. The engine writes only to the output directory you name (--output), plus a cache directory only if you explicitly pass one (--scan-cache-dir / --osv-cache-dir). sbomflow init writes a single sbomflow.yaml into the project directory you point it at. Nothing is written to your home directory: the optional entitlement file (~/.config/sbomflow/entitlement.json) is read if present and never created by the tool. There is no hidden state, no daemon, no telemetry, and no default network call.
To remove the tool:
pip uninstall sbomflow # or: pipx uninstall sbomflow, once publishedIf you installed into a dedicated virtual environment (recommended), simply delete the environment directory.
To remove all generated evidence, delete the output directories you created:
rm -rf ./sbomflow-output ./evidence # whatever paths you passed to --outputBecause outputs are self-contained and deterministic, deleting those directories removes every SBOM, report, bundle, audit log, and review/approval file SBOMFlow produced. Keep a copy first if you need the evidence for your own records — the evidence bundle is a portable, hash-verifiable archive designed exactly for that.
Planned install channels (after first release)#
The following are not yet available and will be documented when the first release ships:
pipx install sbomflowpython -m pip install sbomflow(from PyPI)- a Homebrew formula (a Python CLI ships as a formula, not a cask)
When a Homebrew tap is published, follow the tap's own trust guidance. Prefer installing the specific formula over trusting an entire third-party tap; do not disable Homebrew's trust checks globally.
Next#
Continue to your first offline audit.