Running the sbomify Action Locally

Generate SBOMs on your own machine with uvx, pipx or Docker - for trying things out, debugging a pipeline, or running the setup wizard.

Running locally is useful for trying the tool out, debugging a pipeline that behaves unexpectedly, generating a one-off SBOM, and running the setup wizard - which is interactive and deliberately refuses to run in CI.

For actual SBOM generation in a pipeline, use your CI platform.

Docker

Closest to what CI does, which makes it the best choice for reproducing a pipeline problem:

docker run --rm \
  -v "$(pwd):/github/workspace" \
  -w /github/workspace \
  -e LOCK_FILE=requirements.txt \
  -e OUTPUT_FILE=sbom.cdx.json \
  -e ENRICH=true \
  -e UPLOAD=false \
  ghcr.io/sbomify/sbomify-action

Note that the container runs as root, so generated files will be root-owned on the host. Add --user "$(id -u):$(id -g)" if that is inconvenient.

uvx

If you have uv, you can run the CLI without installing anything permanently:

uvx sbomify-action --lock-file requirements.txt --enrich --no-upload -o sbom.cdx.json

uvx downloads the package into a temporary environment, runs it, and leaves nothing behind. Ideal for a one-off.

The setup wizard works the same way:

uvx sbomify-action wizard

The license database generator is a separate entry point in the same package:

uvx --from sbomify-action sbomify-license-db --distro alpine --version 3.20 -o alpine-3.20.json.gz

pipx

pipx run is the equivalent if you use pipx rather than uv:

pipx run sbomify-action --lock-file requirements.txt --enrich --no-upload -o sbom.cdx.json
pipx run sbomify-action wizard

Both uvx and pipx run keep the tool out of your global Python environment, which is what you want for something you invoke occasionally.

The generators come down on first use

You do not need to install Syft or cdxgen yourself. The tool downloads the generators it needs on first use, verified against a pinned digest and cached under ~/.cache/sbomify/runtimes (or wherever SBOMIFY_TOOL_CACHE points).

That means uvx sbomify-action --lock-file Cargo.lock ... gets you cargo-cyclonedx, not a Syft fallback, without any setup. The first run for a given ecosystem pays a download; later runs reuse the cache.

If you would rather use only what is already on your machine, opt out:

SBOMIFY_FETCH_RUNTIMES=0 uvx sbomify-action --lock-file requirements.txt --enrich --no-upload -o sbom.cdx.json

Be aware of what that trades away. Opting out does not make the tool fail when a native generator is missing - it falls back to whatever is installed, which is usually a worse answer, and the SBOM does not say so. If you set this flag, install the generators you care about:

ToolInstallCovers
cyclonedx-pyBundled as a dependencyPython
Syftbrew install syft or the install guideMost ecosystems, container images, SPDX output
cdxgennpm install -g @cyclonedx/cdxgenJavaScript, Ruby, PHP, .NET and more
cargo-cyclonedxcargo install cargo-cyclonedxRust
crane and cosignbrew install crane cosignChainguard image detection

If a required tool is missing and fetching is disabled, the CLI tells you which one and how to install it.

Environment variables work too

Every CLI flag has an environment variable equivalent, which is convenient in scripts:

export LOCK_FILE=requirements.txt
export OUTPUT_FILE=sbom.cdx.json
export ENRICH=true
export UPLOAD=false

uvx sbomify-action

Flags take precedence over environment variables. See the configuration reference.

Uploading from your machine

export SBOMIFY_TOKEN="your-token"

uvx sbomify-action \
  --component-id your-component-id \
  --lock-file requirements.txt \
  --augment --enrich

OIDC trusted publishing is not available locally - it depends on a CI-issued identity token - so use an API token.

Be deliberate about uploading from a laptop. An SBOM generated locally reflects your machine rather than a clean build, and it cannot be attested. It is fine for experimenting; for anything you intend to distribute, generate it in CI where it can be signed at origin.

VCS information

Nothing is auto-detected locally. Set the values in sbomify.json if you need them:

{
  "vcs_url": "https://github.com/my-org/my-repo",
  "vcs_commit_sha": "abc123def456",
  "vcs_ref": "main"
}

See augmentation.

Debugging a pipeline

When CI produces something you did not expect, reproduce it locally with the same image and the same variables:

docker run --rm \
  -v "$(pwd):/github/workspace" \
  -w /github/workspace \
  -e LOCK_FILE=requirements.txt \
  -e OUTPUT_FILE=sbom.cdx.json \
  -e ENRICH=true \
  -e UPLOAD=false \
  -e VERBOSE=true \
  ghcr.io/sbomify/sbomify-action

VERBOSE=true shows which generator ran, which enrichment sources answered, and where time went. Check audit_trail.txt afterwards for the full list of changes.

Two differences from CI worth keeping in mind: VCS auto-detection will not fire locally, and enrichment coverage may differ if CI is hitting GitHub API rate limits that your machine is not.

Next steps