A software bill of materials (SBOM) is a machine-readable inventory of every component your application ships — direct dependencies, transitive dependencies, versions, and license metadata. Customers ask for one during procurement, regulators increasingly require one, and your own security team needs one to answer "are we affected?" the next time a critical CVE lands. The problem is that a hand-maintained dependency list is stale the moment you merge a pull request. This guide shows you how to generate an accurate SBOM automatically — whether you're working from a source repository or want to generate an SBOM from a container image after it's built — in both CycloneDX and SPDX formats, and how to keep it current.
Prerequisites
- A repository with a resolved lockfile (
package-lock.json,poetry.lock,go.sum,pom.xml, and so on). - The Safeguard CLI installed. On macOS or Linux:
curl -sSfL https://get.safeguard.sh/install.sh | sh. On Windows, install via Scoop. - A Safeguard project token exported as
SAFEGUARD_TOKENif you want to upload the result. Local generation works without one.
Step 1: Initialize the project
From the root of your repo, create a config so every tool behaves identically:
sg init
This writes .safeguard/config.yaml. Set your default SBOM format and output path so generate needs no flags later:
project: checkout-service
ecosystems:
- npm
- pypi
sbom:
format: cyclonedx-json
output: .safeguard/sbom.cdx.json
Commit this file. A committed config is what makes SBOM output reproducible across laptops and CI runners.
Step 2: Generate the SBOM
Run the generator. It resolves your lockfiles, walks the full dependency graph, and emits a spec-compliant document:
sg sbom generate --format cyclonedx-json --output sbom.cdx.json
Prefer SPDX for a customer who standardized on it? Generate both — they describe the same graph:
sg sbom generate --format spdx-json --output sbom.spdx.json
The CLI prints a summary so you know the run succeeded:
Resolved 1,284 components across 2 ecosystems
npm: 1,046 components
pypi: 238 components
Wrote sbom.cdx.json (CycloneDX 1.6, 1,284 components)
Step 3: Validate the document
An SBOM nobody can parse is worse than none. Validate it against the schema before you hand it out:
sg sbom validate sbom.cdx.json
A passing run confirms the document is well-formed CycloneDX 1.6 (or SPDX 2.3), that every component has a purl, and that no required fields are missing. If you generated the SBOM with a third-party tool, run this same command to check it before relying on it downstream.
Step 4: Enrich with vulnerability and license data
A raw component list answers "what do we ship." Enrich it to also answer "what is risky":
sg scan --input sbom.cdx.json --format table
This cross-references each component against Safeguard's advisory data and your license policy, adding severity, fixed-version, and reachability annotations. The enriched view is what turns a compliance artifact into an operational one.
Step 5: Attach the SBOM to a release
Upload it so it is linked to the exact commit and available for dashboards and audits:
sg sbom generate --format cyclonedx-json --sbom-upload
For releases, also attach the file to your Git tag or GitHub Release so consumers can retrieve it without portal access. Many teams publish sbom.cdx.json and sbom.spdx.json as release assets on every tagged build.
Verify the result
Confirm the SBOM is real and complete with three quick checks:
# 1. Component count matches your expectation
sg sbom stats sbom.cdx.json
# 2. Schema is valid
sg sbom validate sbom.cdx.json
# 3. A known dependency is present
grep -c '"purl"' sbom.cdx.json
If the component count is far lower than your lockfile's dependency count, you probably have an ecosystem that was not resolved — check the ecosystems list in your config.
How Safeguard streamlines this
Generating the file is the easy part; keeping it accurate and useful is the hard part. Safeguard's CLI produces the SBOM from the same resolution engine your scans use, so the inventory always matches what you actually ship. SBOM Studio then stores every SBOM against its commit, diffs versions so you can see exactly which components a pull request introduced, and re-evaluates historical SBOMs when a new CVE drops — so you can answer "are we affected?" in seconds instead of re-scanning. Pair that with SCA and each component in the document carries live severity and reachability context. Because generation, storage, and analysis share one pipeline, your SBOM stops being a stale PDF and becomes a queryable, always-current asset. See how tiers scale on the pricing page.
Ready to try it? Generate your first SBOM and connect a repository at app.safeguard.sh/register.
Frequently Asked Questions
What is the difference between CycloneDX and SPDX? Both are open SBOM standards that describe the same underlying dependency graph. CycloneDX originated in the security community and is strong on vulnerability and dependency relationships; SPDX originated in the license-compliance world and is a Linux Foundation and ISO standard. Safeguard generates both from one command, so you can hand each stakeholder the format they prefer.
How often should I regenerate my SBOM? On every build, or at minimum on every release. An SBOM is only trustworthy if it reflects the exact dependency set of a specific commit, and dependencies change every time you merge. Automating generation in CI means you never ship a build without a matching bill of materials.
Can I generate an SBOM without uploading anything?
Yes. sg sbom generate runs entirely locally and writes the file to disk without a token or network upload. Uploading is optional and only needed if you want the SBOM stored in the portal for diffing, dashboards, and historical re-evaluation.
Does an SBOM include transitive dependencies? Yes — a complete SBOM includes the entire resolved graph, not just the packages you named directly. Transitive dependencies are where most supply chain risk actually lives, so an inventory that stops at direct dependencies is incomplete and misleading.
Is a generated SBOM enough for compliance? It is the foundation, but most frameworks also expect the SBOM to be current, tied to a build, and paired with a process for acting on the vulnerabilities it reveals. Generating the document satisfies the artifact requirement; enriching and monitoring it is what satisfies the intent behind the requirement.
Can I generate an SBOM from a container image instead of source? Yes. The steps above work from a repository's lockfiles, but you can generate an SBOM from a container image the same way once it's built — pointing the scan at the image instead of the source tree — which is useful when you need to attest to exactly what shipped, including OS packages layered in during the build, not just what your application manifest declares.
Explore SBOM Studio, the Safeguard CLI, and SCA, or compare plans on the pricing page. Full setup steps live in the Safeguard docs.