# SBOM Generation

> Audience: vendor implementation team and operator pre-handover reviewers.
> Goal: document how the CycloneDX SBOM at [`sbom-current.json`](sbom-current.json) was produced and how to refresh it.
> Priority: **High** — required as governance evidence (ADR 017).

---

## 1. What is checked in

`sbom-current.json` is a CycloneDX Bill of Materials in JSON format (spec 1.6) covering production dependencies of this Node.js project at the time the foundation-readiness branch was authored. Dev dependencies are omitted.

It is intentionally pinned to the moment of generation. Re-generating produces a different file because the dependency graph evolves.

## 2. How it was generated

The exact command run in the foundation-readiness branch:

```bash
npx --yes @cyclonedx/cyclonedx-npm \
  --ignore-npm-errors \
  --omit dev \
  --output-format JSON \
  --output-file docs/foundation/sbom-current.json
```

Notes:
- `--yes` makes `npx` install the package transparently the first time.
- `--ignore-npm-errors` is required because the local `node_modules/` resolution sometimes reports `ELSPROBLEMS` from `npm ls` (transient peer-dep mismatches) — those are noise, not real graph problems. Without this flag the tool exits non-zero and writes nothing.
- `--omit dev` keeps dev tooling out of the manifest (Vitest, ESLint, Prettier, etc.). Production-time supply chain is the regulator-relevant view.
- The default output is CycloneDX 1.6 + JSON. Switch to XML by setting `--output-format XML` if a downstream tool requires it.

The repo's `package.json` is unchanged — the SBOM tool is invoked transitively through `npx`. No new dependency is added.

## 3. Validation

The JSON should be a single self-contained CycloneDX document. To check:

```bash
test -f docs/foundation/sbom-current.json
jq empty docs/foundation/sbom-current.json     # parses successfully
jq '{ schema: .["$schema"], specVersion, components_count: (.components|length) }' \
  docs/foundation/sbom-current.json
```

The expected output has `specVersion: "1.6"` and a non-zero `components_count` (≈ 550 for the production graph at the time of writing).

If `jq empty` fails, **delete the file and regenerate**. A truncated SBOM is worse than no SBOM — downstream scanners may silently accept a partial document.

## 4. When to refresh

- **Before any production-bound build** the vendor produces.
- **After every dependency change** (`npm install`, `npm update`, lockfile bumps).
- **As part of CI** — the suggested place is the same job that runs `npm run check:portability`, with the artefact uploaded for retention.

A cron-style refresh is acceptable but does not replace the per-build refresh.

## 5. Vendor notes

- The Azure pipeline should treat the SBOM as a release artefact: produce it, sign it, upload it, retain it per the operator's compliance window.
- The current SBOM omits dev deps. If the vendor needs the full graph (for, e.g., a SAST scanner that wants a complete view), re-run without `--omit dev` into a separate artefact (`sbom-fullgraph.json`).
- License data is part of the CycloneDX record. The vendor should run a separate license-policy check against the SBOM (e.g. CycloneDX's own policy tooling, or a license-clearing service in BMW infrastructure).
- ADR 017 expects Trivy + ZAP scans in addition to SBOM evidence. Those are vendor-side decisions.

## 6. If generation fails

If a future regeneration attempt does not produce a valid SBOM:

1. Confirm the `--ignore-npm-errors` flag is present.
2. Run `npm ls --json --long --all > /dev/null` and inspect the exit code. Anything other than `0` or known `ELSPROBLEMS` should be triaged.
3. As a fallback, run `npx @cyclonedx/cyclonedx-npm --package-lock-only --output-format JSON --output-file docs/foundation/sbom-current.json` — this reads only the lockfile and skips `node_modules/`. The output is less detailed but still valid.
4. If the file is broken, delete it. Do not commit a partial or invalid SBOM. Replace it with a note in this document describing the failure.

## 7. References

- CycloneDX spec: <https://cyclonedx.org/specification/overview/>
- ADR 017 — `docs/adr/017-security-baseline-and-scan-policy.md`
- `package.json` — scripts under `check:portability` are the gate this SBOM evidence supplements.
