This page defines what an SBOM is, why it matters, what the Custodian SBOM
standard requires of registered repos, and how to bring a repo into compliance.
---
## What is an SBOM?
An SBOM (Software Bill of Materials) is an inventory of every component a
piece of software depends on — direct and transitive, runtime and build-time.
For software projects this means: every library installed via pip, npm, cargo,
or any other package manager. For infrastructure repos it means: Ansible itself,
Terraform providers, system tools the playbooks invoke. For container images: OS
packages, base image layers, language runtimes.
The key question an SBOM answers is: **"what exactly is running, and at which
version?"**
---
## What a lockfile is — and why it matters
A **lockfile** is the machine-generated, committed answer to that question for
one package manager. When you run `uv lock`, `npm install`, or `terraform init`,
the tool resolves all transitive dependencies, pins them to exact versions, and
writes those pins to a lockfile (`uv.lock`, `package-lock.json`,
`.terraform.lock.hcl`).
Without a lockfile:
| Problem | Consequence |
|---------|-------------|
| Versions are not pinned | Different machines or CI runs get different versions — one may work, another may not |
| No transitive inventory | You know you depend on `ansible`, but not which version of `paramiko` or `cryptography` it pulls in |
| Vulnerability scanning is imprecise | CVE databases require exact versions; a range like `ansible>=8` can't be scanned |
| Licence auditing is impossible | You can't know the licence of every transitive dependency |
| Reproducibility breaks | Debugging a production incident requires knowing the exact versions in use |
The lockfile is the **unit of SBOM evidence** for package-managed dependencies.
The State Hub ingests lockfiles to populate the SBOM store.
---
## The Custodian SBOM Standard
Every registered repo is assessed against five maturity levels. A repo must
reach **Level 3** to be considered SBOM-compliant.
| Level | Name | Criterion |
|-------|------|-----------|
| **0** | Registered | Repo appears in the State Hub `/repos/` |
| **1** | Manifested | For every ecosystem in use, a **manifest file** exists and is committed (`pyproject.toml`, `package.json`, `Cargo.toml`, `go.mod`, `ansible/requirements.yml`, etc.) |
| **2** | Locked | Every manifest file has a corresponding **lockfile** committed to the repo |
| **3** | Ingested | `last_sbom_at` is not null; the ingested packages cover all detected ecosystems |
| **4** | Current | `last_sbom_at` is within 30 days, or since the last lockfile change |
| **5** | Clean | No unreviewed copyleft flags in direct prod dependencies; no unknown licences in direct deps |
### SBOM gap types
**Type A — Missing manifest**: dependencies exist but nothing declares them.
Example: Ansible is installed on the control node but there is no `pyproject.toml`
declaring `ansible` as a dependency. Fix: create the manifest.
**Type B — Manifest without lockfile**: a `pyproject.toml` or `package.json`
exists but no lockfile has been generated. Fix: run `uv lock` / `npm install`.