Generate your first SBOM#

This tutorial creates a small conda environment, exports its resolved package graph as CycloneDX 1.7 JSON, and inspects the result.

Prerequisites#

  • conda 26.3 or newer

  • network access to conda-forge and your configured conda channels

Install conda-sboms#

conda activate base
conda install --channel conda-forge "conda-sboms>=0.3.0"

Confirm that conda discovered the exporter:

conda export --help

The available environment formats should include cyclonedx-json-v1.7 with the aliases cyclonedx-json, cyclonedx, and cdx-json.

Create an environment to describe#

Create a local prefix with Python and Requests:

conda create \
  --prefix ./build/tutorial-environment \
  --channel conda-forge \
  --yes \
  python=3.13 requests
conda create `
  --prefix ./build/tutorial-environment `
  --channel conda-forge `
  --yes `
  python=3.13 requests

This command gives conda both the requested packages and the complete solved package set. The exporter uses both parts of that record.

Export the SBOM#

conda export \
  --prefix ./build/tutorial-environment \
  --from-history \
  --format cyclonedx-json \
  --file build/tutorial-environment.cdx.json
conda export `
  --prefix ./build/tutorial-environment `
  --from-history `
  --format cyclonedx-json `
  --file build/tutorial-environment.cdx.json

--from-history asks conda to retain python and requests as the requested roots. The exporter still writes every resolved conda package as a component.

Inspect the document#

Print the format, root component, root source, and component count:

python - <<'PY'
import json
from pathlib import Path

path = Path("build/tutorial-environment.cdx.json")
document = json.loads(path.read_text(encoding="utf-8"))
root = document["metadata"]["component"]
properties = {item["name"]: item["value"] for item in root["properties"]}

print(document["bomFormat"], document["specVersion"])
print(root["name"])
print(properties["conda:environment:root-dependency-source"])
print(len(document["components"]), "components")
PY
@'
import json
from pathlib import Path

path = Path("build/tutorial-environment.cdx.json")
document = json.loads(path.read_text(encoding="utf-8"))
root = document["metadata"]["component"]
properties = {item["name"]: item["value"] for item in root["properties"]}

print(document["bomFormat"], document["specVersion"])
print(root["name"])
print(properties["conda:environment:root-dependency-source"])
print(len(document["components"]), "components")
'@ | python -

The result reports CycloneDX 1.7, uses conda-environment instead of exposing the local prefix path, and reports requested-packages as the root dependency source. The exact component count depends on the current solve.

Open build/tutorial-environment.cdx.json and find the requests component. Its fields include the exact version and build, a conda package URL, available archive hashes, the sanitized distribution URL, and conda package properties. The corresponding entry in dependencies points to its resolved dependencies.

Clean up#

Remove the tutorial environment and generated SBOM:

conda remove \
  --prefix ./build/tutorial-environment \
  --all \
  --yes
rm build/tutorial-environment.cdx.json
conda remove `
  --prefix ./build/tutorial-environment `
  --all `
  --yes
Remove-Item build/tutorial-environment.cdx.json

Next steps#