# Sbom

> Generate and manage Software Bill of Materials (SBOMs) for the OpenShell project. Covers SBOM generation with Syft, license resolution via public registries, and CSV export for compliance review. Trigger keywords - SBOM, sbom, bill of materials, license audit, license resolution, generate sbom, sbom csv, dependency license, supply chain, license scan.

- Skill: `nvidia/sbom` (Agent Skill)
- Install (CLI): `npx skillmds@latest add nvidia/sbom`
- Raw SKILL.md: https://api.skillmd.com/api/skills/nvidia/sbom/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Data & Analytics
- Author: NVIDIA (https://skillmd.com/u/nvidia)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/nvidia/sbom

---


# SBOM Generation and License Resolution

Generate CycloneDX SBOMs, resolve missing licenses, and export to CSV for compliance review.

## Overview

The OpenShell SBOM tooling produces source-tree CycloneDX JSON SBOMs using Syft, resolves missing or hash-based licenses by querying public registries (crates.io, npm, PyPI), and exports the results to CSV for stakeholder review.

SBOMs are **release artifacts only** -- they are generated on demand and not committed to the repository. Output lands in `deploy/sbom/output/` (gitignored).

Pushed gateway and supervisor images carry an SPDX SBOM and minimal SLSA provenance as OCI attestations. Branch E2E, Release Dev, and Release Tag image binaries embed cargo-auditable metadata, so their image SBOMs include linked Rust crates.

## Prerequisites

- `mise install` has been run (installs Syft and other tools)
- The repository is checked out at the root

## Inspecting an Image SBOM

BuildKit uses its default Syft scanner and attaches one SPDX document per platform. Read one without pulling the image:

```bash
docker buildx imagetools inspect ghcr.io/nvidia/openshell/gateway:latest \
  --format '{{ json (index .SBOM "linux/amd64").SPDX }}'
```

Validate the final attestation, requiring a Cargo package for an auditable image:

```bash
tasks/scripts/verify-image-sbom.sh ghcr.io/nvidia/openshell/gateway:latest --require-cargo
```

## Inspecting an Auditable Image Binary

Opt into auditable metadata when staging a local image binary:

```bash
OPENSHELL_AUDITABLE=1 PREBUILT_ARCH=amd64 \
  tasks/scripts/stage-prebuilt-binaries.sh gateway
```

Scan the staged binary rather than the source tree:

```bash
mise x -- syft \
  "file:deploy/docker/.build/prebuilt-binaries/amd64/openshell-gateway" \
  -o cyclonedx-json
```

This output is limited to packages Syft discovers from that binary. Use
`mise run sbom` for the broader source-tree license-compliance inventory.

## Workflow 1: Full SBOM Generation (One Command)

```bash
mise run sbom
```

This single command chains three stages:

1. **Generate** (`sbom:generate`): Syft scans the workspace source tree and produces a CycloneDX JSON SBOM
2. **Resolve** (`sbom:resolve`): Public registry APIs fill in missing or hash-based licenses in the JSON
3. **CSV** (`sbom:csv`): JSON SBOMs are converted to CSV for review

Output directory: `deploy/sbom/output/`

After running, the user can find:
- `deploy/sbom/output/*.cdx.json` -- full CycloneDX SBOMs
- `deploy/sbom/output/*.csv` -- CSV exports ready for spreadsheet review

## Workflow 2: Individual Stages

Run stages independently when debugging or iterating:

```bash
mise run sbom:generate   # Generate JSON SBOMs only (requires Syft)
mise run sbom:resolve    # Resolve licenses in existing JSONs (queries APIs)
mise run sbom:csv        # Convert existing JSONs to CSV
```

## Workflow 3: License Check (CI Advisory)

```bash
mise run sbom:check
```

Reports unresolved licenses without failing. Intended for PR CI as a non-blocking advisory check. Requires that SBOMs have already been generated (`mise run sbom:generate`).

## Workflow 4: Processing External SBOMs

The Python scripts accept explicit file paths, so they can process SBOMs from any source (e.g., NVIDIA nSpect pipeline output):

```bash
uv run python deploy/sbom/resolve_licenses.py /path/to/external-sbom.json
uv run python deploy/sbom/sbom_to_csv.py /path/to/external-sbom.json
```

## License Resolution Details

The resolver queries these public registries:

| Registry | Package URL prefix | Method |
|----------|-------------------|--------|
| crates.io | `pkg:cargo/*` | REST API |
| npm | `pkg:npm/*` | Registry API |
| PyPI | `pkg:pypi/*` | JSON API |
| Go modules | `pkg:golang/*` | Known license map (no API) |
| Debian/Ubuntu | `pkg:deb/*` | Known license map |

Components from private registries (e.g., `@openclaw/*` npm packages) are not resolved and will appear in the "unresolved" report.

## Output Files

| Pattern | Description |
|---------|-------------|
| `deploy/sbom/output/openshell-source-{version}.cdx.json` | CycloneDX JSON SBOM |
| `deploy/sbom/output/openshell-source-{version}.csv` | CSV export (name, version, type, purl, licenses, bom-ref) |

## Key Files

| File | Purpose |
|------|---------|
| `deploy/sbom/resolve_licenses.py` | License resolution script |
| `deploy/sbom/sbom_to_csv.py` | JSON-to-CSV converter |
| `tasks/sbom.toml` | Mise task definitions |
| `mise.toml` | Syft tool definition (under `[tools]`) |

## Quick Reference

| Task | Command |
|------|---------|
| Full pipeline | `mise run sbom` |
| Generate only | `mise run sbom:generate` |
| Resolve licenses | `mise run sbom:resolve` |
| Export CSV | `mise run sbom:csv` |
| CI license check | `mise run sbom:check` |
| Process external SBOM | `uv run python deploy/sbom/resolve_licenses.py <file>` |

