Skip to main content

Sbomly: what changed between two SBOMs, and what to check.

CI PyPI Python Homebrew Docker License

Sbomly

See what changed between two SBOMs, and what deserves a closer look.

Sbomly compares two SBOMs, CycloneDX or SPDX JSON, and tells you which components were added, removed, upgraded or downgraded. It also flags the changes a reviewer should actually stop for:

  • Integrity: same version, different digest. The artifact was rebuilt or replaced.
  • Copyleft: a new dependency, or a new licence, that brings in GPL, LGPL, AGPL and similar.
  • Licence: a licence changed, or stopped being declared.
  • Supplier: a package's supplier changed. In a language ecosystem that's the account-takeover pattern.

Output goes wherever you need it: a terminal summary, a Markdown summary sized for a PR comment, JSON for other tools, and a self-contained HTML report that works offline. --fail-on turns any category into a CI gate.

Sbomly has no runtime dependencies and needs Python 3.10 or later.

Sbomly is a sibling of Vulnly and part of Full-Stack-Spectrum: small open-source tools that turn noisy supply chain data into decisions.

Sbomly HTML report comparing two releases of payments-api

Install

pipx install sbomly     # or: pip install sbomly
brew install fullstackspectrum/sbomly/sbomly

Or run the container image, mounting the directory that holds your SBOMs:

docker run --rm -t -v "$PWD:/data" fullstackspectrum/sbomly diff old.json new.json

Usage

sbomly diff old.cdx.json new.cdx.json

Findings come first, most serious at the top, then each kind of component change:

Terminal summary from sbomly diff

Write reports alongside the terminal summary:

sbomly diff old.json new.json --html report.html --markdown pr.md --json diff.json

The HTML report, shown at the top of this page, is a single file with its fonts embedded, so it opens offline and can be attached to a CI run or a ticket. Search and the change-type filters work without a network connection, and --theme light gives a light version for printing.

Diff view

Prefer to read changes the way you read code? -u prints a unified diff of the two component lists, like diff -u, with one line per component sorted like a lockfile:

sbomly diff old.json new.json -u        # 3 lines of context
sbomly diff old.json new.json -u -U 0   # changes only

Unified diff in the terminal from sbomly diff -u

In a colour terminal, the diff gets an old/new line-number gutter and highlights the words that changed in each -/+ pair. When piped, or with --no-color, it's a plain unified diff that patch and other diff tools accept.

Each line shows the name, version and licence. A digest or supplier is added only where it changed, so a same-version finding still shows up as a -/+ pair. Lines come from Sbomly's own comparison rather than the raw files, so anything it treats as equivalent, like licence term order or a new distro qualifier, stays as context instead of showing up as noise. The output is a valid patch.

The HTML report has the same diff behind a table / diff toggle, with line numbers and the changed words highlighted. Add #diff to the report's URL to open it on the diff view. With -u, the Markdown output also gets a ```diff block, which GitHub colours in PR comments.

The diff view in the HTML report

Screenshots show sample data from tests/fixtures. To regenerate them, run python docs/screenshots/src/render.py.

Read one SBOM from stdin, for example straight from a generator:

syft my-image:latest -o cyclonedx-json | sbomly diff baseline.cdx.json -

Options

Option
-f, --format text|markdown|json What to print to stdout (default text)
--html FILE Write the offline HTML report
--markdown FILE Write the Markdown summary
--json FILE Write the full diff as JSON
--fail-on LIST Exit 1 if any of these categories occur (see below)
-u, --unified Print a unified diff of the component lists instead of the summary, and add it to Markdown output
-U, --context N Unchanged components shown around each change in the diff (default 3)
--title TEXT Title for the HTML and Markdown reports
--theme dark|light HTML report theme (default dark)
--limit N Rows per section in text and Markdown (default 100)
--no-color Plain terminal output. NO_COLOR and FORCE_COLOR are respected
-q, --quiet Print nothing to stdout

Gating CI with --fail-on

Category Fails when
added / removed A component appears or disappears
upgraded / downgraded A component moves to a newer or older version
changed A version changes but can't be ordered (commit SHAs, digests)
hash Same version, different digest
copyleft A new dependency is copyleft, or a licence becomes more restrictive
license A licence changes, or is no longer declared
supplier A component's supplier changes
any Any of the above
sbomly diff main.cdx.json pr.cdx.json --fail-on hash,copyleft,downgraded

Exit codes: 0 passed, 1 a --fail-on category was hit, 2 bad usage or an unreadable SBOM.

Some findings are informational. They're shown, but they never fail a build:

  • A licence that was unknown and is now declared.
  • A same-version digest change where the purl's distro qualifier also changed. Distros rebuild unchanged packages for each release.
  • A supplier change for an OS package (apk, deb, rpm). There, the supplier is the distro maintainer, and maintainers rotate.

GitHub Actions

Sbomly ships as a composite action. It writes the Markdown summary to the job page, and exposes the report paths for a PR comment or artifact upload.

- uses: fullstackspectrum/sbomly@v0.1.0
  with:
    old: sbom-main.cdx.json
    new: sbom-pr.cdx.json
    fail-on: hash,copyleft

Or call the CLI yourself on any CI system:

pipx run sbomly diff baseline.json current.json --markdown sbomly.md --fail-on hash

How components are matched

Components are paired across the two SBOMs by package URL, ignoring the version. Qualifiers that only describe the build environment, like distro and repository_url, are also ignored, so moving to a new base image doesn't report every OS package as removed and re-added. arch, classifier and type are kept, because they identify a different artifact. PyPI names are normalised as PEP 503 describes. Components without a purl fall back to their group and name.

When a package has several versions in both SBOMs, which npm often does, the leftover versions are paired in version order.

Supported formats

Format Versions
CycloneDX JSON 1.4 to 1.6 tested, older versions usually work
SPDX JSON 2.2, 2.3

CycloneDX XML, SPDX tag-value and SPDX 3.0 aren't supported yet. Sbomly tells you so rather than guessing.

Development

python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
pytest

Licence

Apache-2.0. The bundled Space Grotesk and JetBrains Mono fonts are under the SIL Open Font License 1.1. See sbomly/assets/.

Copyleft classification is a triage signal, not legal advice.

Metadata

Release files for sbomly 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sbomly 0.1.0
File Size Uploaded Provenance Actions
sbomly-0.1.0.tar.gz 119.4 kB With provenance Details for sbomly-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for sbomly 0.1.0
File Interpreter ABI Platform Actions
sbomly-0.1.0-py3-none-any.whl Python 3 none any Details for sbomly-0.1.0-py3-none-any.whl

Total release size: 228.0 kB

Release files / sbomly-0.1.0.tar.gz

Download URL sbomly-0.1.0.tar.gz
Size 119.4 kB
Tags Source
SHA-256 checksum
How to use checksums
711a48de0721e4497c1c4ad29ab3ea2f6e273f821eacbc487e3361ec45ef4a43
BLAKE2b-256 checksum
How to use checksums
1f0836359dca8dbd2d088d03383ad0884118374eeacf1581d24fdb2243af358a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 9, 2026.

Transparency log

Release files / sbomly-0.1.0-py3-none-any.whl

Download URL sbomly-0.1.0-py3-none-any.whl
Size 108.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b76d4928d44ce4dd01d4b446458b8936649e57f58f585704d45f045197ab44c4
BLAKE2b-256 checksum
How to use checksums
a46b921f3e694820519dd610c07376f52f07365a00e9c37e7bd2482816b8e09e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 9, 2026.

Transparency log

Security for sbomly 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for sbomly-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 9, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page