CycloneDX JSON exporter#
The exporter accepts one resolved conda environment and returns a CycloneDX 1.7 JSON document ending with a newline.
Format identity#
Field |
Value |
|---|---|
Distribution |
|
Conda plugin entry point |
|
Canonical format name |
|
Aliases |
|
Default filename pattern |
|
Specification |
CycloneDX 1.7 JSON |
Platform support |
One platform per document |
The canonical name is pinned to CycloneDX 1.7 and will not change meaning. The
unversioned cyclonedx-json alias may advance to a later supported CycloneDX
JSON version. Use the canonical name in automation that must remain on 1.7.
All four format names select the same exporter. A filename ending in
.cdx.json lets conda detect the format without --format:
conda export --name my-environment --file my-environment.cdx.json
A custom filename requires the explicit format name:
conda export --name my-environment \
--format cyclonedx-json \
--file inventory.json
Omit --file to write the document to standard output. conda-sboms does not
add a separate command-line interface.
Input contract#
The exporter receives one conda.models.environment.Environment through
conda’s conda_environment_exporters hook. explicit_packages must contain at
least one exact PackageRecord. The callback does not solve an environment,
read a prefix, read a lockfile, or access the network.
Conda and other clients construct the Environment before invoking the
exporter. This is why installed prefixes and resolved workspace locks work but
an unresolved list of requirements does not.
Python API#
Added in version 0.2.0: The public object API and explicit per-call metadata.
Added in version 0.3.0: The output_reproducible argument and exporter state.
The object API consists of four public classes:
Class |
Responsibility |
|---|---|
|
Validate caller-supplied product and author metadata |
|
Map one exact |
|
Build dependency edges and select product roots |
|
Build and serialize the complete CycloneDX document |
The exact call signatures are:
CycloneDXExportMetadata(
product_name: str | None = None,
product_version: str | None = None,
product_manufacturer: str | None = None,
product_manufacturer_url: str | None = None,
author_name: str | None = None,
author_email: str | None = None,
author_organization: str | None = None,
author_organization_url: str | None = None,
)
CycloneDXPackage(record: PackageRecord)
CycloneDXDependencyGraph(packages: list[CycloneDXPackage])
CycloneDXDependencyGraph.root_references(
requested_packages: list[MatchSpec],
) -> list[BomRef]
CycloneDXExporter(
environment: Environment,
*,
metadata: CycloneDXExportMetadata | None = None,
output_reproducible: bool = False,
)
CycloneDXExporter.export() -> str
Their public state is part of the API:
Class |
Public members |
|---|---|
|
|
|
|
|
|
|
|
CycloneDXExportMetadata instances are immutable. Construction strips
surrounding whitespace from string values and converts empty values to None.
Use CycloneDXExporter directly when calling the exporter from Python:
from conda_sboms.cyclonedx import CycloneDXExporter
from conda_sboms.settings import CycloneDXExportMetadata
document = CycloneDXExporter(
environment,
metadata=CycloneDXExportMetadata(
product_name="Acme Runtime",
product_version="2026.08",
),
).export()
The conda plugin hook uses the public callback with this signature:
export_cyclonedx_json(
environment: Environment,
*,
metadata: CycloneDXExportMetadata | None = None,
output_reproducible: bool = False,
) -> str
When metadata is None, the callback reads conda’s active plugin settings.
An explicit CycloneDXExportMetadata object replaces those settings for that
call. CycloneDXExporter follows the same rule.
An exporter instance is a snapshot of its environment, metadata, and timestamp policy. Construct a new instance after changing any of those inputs.
Document metadata#
CycloneDX field |
Source |
|---|---|
|
CycloneDX 1.7 JSON schema URL |
|
|
|
|
|
|
|
Current UTC time, |
|
|
|
|
|
Configured organization that authored the SBOM |
|
Configured person who authored the SBOM |
|
The exported environment or configured product |
The optional serialNumber is omitted so unchanged inputs can produce
byte-for-byte identical output.
The author fields are omitted when their values are absent. They describe who
created the SBOM and remain separate from the conda-sboms generating tool.
Product metadata settings#
Added in version 0.2.0: Conda plugin settings for product, manufacturer, and SBOM author metadata.
The exporter reads these optional values from conda’s plugin configuration:
Conda setting |
CycloneDX field |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The environment-variable form uppercases the setting and prefixes it with
CONDA_PLUGINS_. For example,
plugins.conda_sboms_product_name becomes
CONDA_PLUGINS_CONDA_SBOMS_PRODUCT_NAME.
Values are stripped of surrounding whitespace, and empty values are omitted. The product name and version must be configured together, and a product manufacturer requires both. An author email requires an author name. An organization URL requires the corresponding organization name. URLs must use HTTP or HTTPS and must not contain credentials, whitespace, query strings, fragments, or malformed percent escapes. Product versions longer than 1024 characters are rejected to match the CycloneDX 1.7 component limit.
These settings are caller-owned data. The exporter never fills them from a conda channel. See Add product and author metadata for commands and lifecycle guidance.
Root component#
The environment is an application component. When product name and version
are configured, they identify that component and its BOM reference. Otherwise a
safe logical environment name is preserved. A path-shaped name from
conda export --prefix becomes conda-environment so the document does not
expose the local prefix.
The root has these properties:
Property |
Meaning |
|---|---|
|
Conda subdir represented by the document |
|
Always |
|
|
|
Count of known non-conda packages not represented |
|
Count of virtual packages not represented as components |
|
Count of declared dependency edges whose target is absent from the records |
The three omission properties appear only when their count is nonzero.
Package components#
Each exact conda package record becomes a library component.
CycloneDX field |
Conda record data |
|---|---|
|
Package name and version |
|
Conda package URL with available build, channel, subdir, and archive type qualifiers |
|
Available SHA-256 and MD5 archive hashes |
|
Raw conda license text represented as a named license |
|
Sanitized remote package URL with type |
|
Build string, build number, subdir, canonical channel, filename, and archive size when available |
License text is not treated as an SPDX expression because legacy conda records may contain arbitrary text. A channel is not treated as the package supplier, producer, or manufacturer.
Dependency graph#
Package edges come from PackageRecord.depends. Each dependency MatchSpec is
matched by package name to the resolved record. constrains entries are not
dependencies and are not mapped.
The document contains one dependency entry for the root and one for every
package component. Known leaves have an explicit empty dependsOn array.
When requested_packages is non-empty, names also present in the resolved
records become root dependencies. Requested names absent from the records are
silently omitted and do not currently produce an incompleteness marker.
Otherwise the exporter infers graph roots and adds a stable representative for
any disconnected cycle so every serialized component is reachable from the
root.
Completeness#
The root assembly composition is unknown when conda metadata cannot establish
whether all product constituents are represented. It is incomplete when the
input reports omitted external packages.
When roots are inferred, the root reference is also listed under dependencies
in the root composition. It uses the same aggregate as the assembly, normally
unknown, or incomplete when external packages were reported. A package with
a declared dependency absent from the resolved record set appears in a separate
incomplete dependency composition.
Privacy behavior#
The exporter removes basic authentication, Anaconda token path segments, query strings, and fragments from remote distribution URLs. Channel identity comes from conda’s canonical channel name. Local file URLs, local file channels, and local environment paths are omitted. Package filenames are reduced to their basename before serialization.
Errors#
The exporter explicitly rejects:
input without exact package records
a supplied SHA-256 or MD5 value with the wrong length or non-hex data
a product name or version is supplied without the other value
a product manufacturer is supplied without product identity
an author email or organization URL is supplied without its corresponding name
a product version exceeds the CycloneDX 1024-character limit
an author email is malformed
an organization URL is not HTTP or HTTPS or contains credentials, whitespace, a query, a fragment, or malformed percent escapes
SOURCE_DATE_EPOCHis negative, malformed, or outside the platform’s supported timestamp range
Failures occur before conda writes the output returned by the exporter.