Skip to content

Search

Search the docs, blog, and marketplace.

Getting started

Use cases

Recipes for PR gates, SBOMs, triage, and license and offline scans.

Last updated October 25, 2026View source (v0.30.0)

This page is a set of recipes, one per job people use Bomly for. Each recipe states the goal, the command, what you get back, and where to read more. New to Bomly? Start with Getting started.

GoalCommand
Gate a pull requestbomly diff --base main --head HEAD --enrich --audit --fail-on high
Generate SBOMsbomly scan -o spdx=sbom.spdx.json -o cyclonedx=sbom.cdx.json
Triage by reachabilitybomly scan --enrich --audit --analyze --fail-on high --fail-on reachable
Enforce a license policybomly scan --enrich --audit --allow-license MIT --fail-on any
Catch typosquats and banned packagesbomly scan --enrich --audit --protected-package react --deny-package event-stream --fail-on any
Scan offlinebomly scan
Scan a container imagebomly scan --image ghcr.io/example/app:latest --enrich --audit --fail-on high
Diff two releasesbomly diff --base v1.2.0 --head v1.3.0 --enrich --audit
Explain a dependencybomly explain send
Explore interactivelybomly scan --enrich --interactive

Gate a pull request on dependency vulnerabilities

Goal: fail a PR when its dependency changes carry a high-severity vulnerability, without complaining about packages the PR did not touch.

bomly diff --base main --head HEAD --enrich --audit --fail-on high

You get: added, removed, and changed packages, and their findings classified as introduced, resolved, or persisted. Only the packages the change touched are audited, and both introduced and persisted findings gate. The diff command page explains the classification. Exit code 2 means the change carries a gating finding.

Sample output — an express upgrade that drags in one new advisory
Added (1)
  + encodeurl@2.0.0  MIT      runtime
Version changed (9)
  ~ body-parser        1.20.2 → 1.20.3
  ~ cookie             0.6.0 → 0.7.1
  ~ express            4.19.2 → 4.21.2
  ~ finalhandler       1.2.0 → 1.3.1
  ~ merge-descriptors  1.0.1 → 1.0.3
  ~ path-to-regexp     0.1.7 → 0.1.12
  ~ qs                 6.11.0 → 6.13.0
  ~ send               0.18.0 → 0.19.0
  ~ serve-static       1.15.0 → 1.16.2

1 new finding(s) introduced; 3 finding(s) persisted.
  introduced  [MEDIUM]    GHSA-q8mj-m7cp-5q26  qs@6.13.0
  persisted   [HIGH]      GHSA-37ch-88jc-xwx2  path-to-regexp@0.1.12
  persisted   [MEDIUM]    GHSA-6rw7-vpxm-498p  qs@6.13.0
  persisted   [LOW]       GHSA-w7fw-mjwx-w883  qs@6.13.0

✓ 2 fix suggestions for 2 of 2 vulnerable packages.
  Run again with --format json to see remediation details.

With --fail-on high this run exits 2. The introduced finding is only medium, but path-to-regexp still has a high-severity issue after the upgrade. The gate holds until a version with the fix, or until the finding is accepted into a committed baseline.

For GitHub pull requests, the Bomly Guard action runs this command for you and posts the result as a PR comment.

Generate and publish an SBOM

Goal: produce SPDX and CycloneDX SBOMs as build artifacts.

bomly scan -o spdx=sbom.spdx.json -o cyclonedx=sbom.cdx.json

You get: both files from one scan. Add --enrich when the SBOM is for someone else, because most lockfiles carry no license data. Details and the -o rules: SBOM formats.

Triage vulnerabilities by reachability

Goal: cut a long advisory list down to the ones your code can reach.

bomly scan --enrich --audit --analyze --fail-on high --fail-on reachable

You get: a reachability status on each advisory, and a gate that fails only on advisories that are both high severity and reachable. Reachability is experimental, and "unreachable" is not "safe". Read Reachability before you rely on this gate.

Enforce a license policy

Goal: block dependencies under licenses you cannot ship.

# Allowlist: permit only these, fail on anything else
bomly scan --enrich --audit \
  --allow-license MIT --allow-license Apache-2.0 --allow-license BSD-3-Clause \
  --fail-on any

You get: a finding for every package whose license is outside the list. Licenses are matched as SPDX expressions. Use --deny-license to block specific licenses instead, and --license-exempt-package to skip the check for one package. See the license auditor.

Catch typosquats and banned packages

Goal: flag dependency names that look like packages you trust, or that you have banned.

bomly scan --enrich --audit \
  --protected-package react --protected-package lodash \
  --typosquat-threshold 0.85 \
  --deny-package event-stream \
  --fail-on any

You get: a finding for each name close to a protected one, and for each denied package. The check itself only compares names, but --audit requires --enrich, so this run does contact the enrichment services. See the package auditor.

Scan offline

Goal: analyze dependencies without contacting any service.

bomly scan                         # no enrichment calls
bomly scan --sbom --path sbom.json # read an SBOM you already have

You get: the dependency graph with no license or vulnerability data. Without --enrich Bomly makes no enrichment calls, but a detector that runs your build tool (Go, Maven, Gradle) may download packages. Commit a lockfile or fill the build tool's cache first to stay fully offline. See Network and privacy.

Scan and audit a container image

Goal: find out what is inside an image and gate on it.

# Inventory an image (native lockfile detectors in layers + Syft for OS packages)
bomly scan --image ghcr.io/example/app:latest

# Audit an image and fail on high-severity vulnerabilities
bomly scan --image ghcr.io/example/app:latest --enrich --audit --fail-on high

# Generate an SBOM from an image
bomly scan --image ghcr.io/example/app:latest -o spdx=image.spdx.json

# Pin by digest for a reproducible scan
bomly scan --image ghcr.io/example/app@sha256:<digest> --enrich --audit

You get: every package in the image. Native detectors read the lockfiles they find in the layers, and Syft covers the rest, including operating-system packages. Bomly uses your host's registry credentials (the same ones docker and podman use), so private images work once you have run docker login. See Scan targets.

Gate a base-image upgrade in CI

In a GitHub Actions job, install Bomly and audit the image you just built:

steps:
  - name: Install Bomly
    run: curl -fsSL https://bomly.dev/install.sh | sh
  - name: Audit the built image
    run: bomly scan --image ${{ env.IMAGE }}:${{ github.sha }} --enrich --audit --fail-on high --format sarif > image.sarif

Exit code 2 fails the job on a policy violation. Upload image.sarif to the Security tab as shown in CI integration.

Diff two releases

Goal: see what changed in your dependency tree between two versions.

# Between Git refs
bomly diff --base v1.2.0 --head v1.3.0 --enrich --audit

# Between two SBOM files (no checkout needed)
bomly diff --sbom --base old.spdx.json --head new.spdx.json

# Between two tags (or digests) of the same container image
bomly diff --image ghcr.io/example/app --base 1.4.0 --head 1.5.0 --enrich --audit --fail-on high

You get: added, removed, and changed dependencies, plus introduced, resolved, and persisted findings when --audit is set. Use it for release notes, upgrade reviews, and base-image bumps.

Understand why a dependency is there

Goal: find the path that pulled a transitive package into your build.

bomly explain send

You get: every dependency path that introduces the package:

package    send@0.18.0
direct     no
introduced by:
  demo@1.0.0
  └─ express@4.19.2
     ├─ send@0.18.0 [analyzed] (transitive)
     └─ serve-static@1.15.0
        └─ send@0.18.0 [analyzed] (transitive)

Add --enrich --audit to see the package's findings alongside the paths. Full reference: explain.

Explore results interactively

Goal: browse a scan without parsing JSON.

bomly scan --enrich --interactive

You get: a terminal UI with tabs for packages, vulnerabilities, licenses, findings, and dependency paths. Keybindings: TUI.

See also