Profile format

Every key a profile file accepts.

  1. A complete example
  2. Identity
  3. Composition
  4. schema
  5. rules
    1. What field can name
    2. File scope, and the two kinds of absence
    3. When a clause accepts more than one field
  6. license_policy
  7. scoring
  8. Using your own profile
  9. Environment variables

A complete example

This is ntia-min-elements trimmed to two rules, showing every top-level section:

id: ntia-min-elements
name: NTIA Minimum Elements for an SBOM
version: "2021-07"
sources:
  - name: NTIA
    ref: "The Minimum Elements For a Software Bill of Materials (SBOM), 2021-07-12"
    url: https://www.ntia.gov/report/2021/minimum-elements-software-bill-materials-sbom

schema:
  min_versions:
    spdx: "2.2"
    cyclonedx: "1.3"

rules:
  - id: ntia-timestamp
    scope: document
    severity: MUST
    category: Freshness
    citation: "NTIA: Timestamp"
    field: timestamp
    validators: [present, rfc3339_utc]

  - id: ntia-supplier
    scope: component
    severity: MUST_WHERE_AVAILABLE
    category: Completeness
    citation: "NTIA: Supplier Name"
    field: supplier
    validators: [present]

scoring:
  weights:
    Completeness: 0.40
    Accuracy: 0.15
    Consistency: 0.15
    Provenance: 0.20
    Freshness: 0.10
  thresholds:
    version_coverage_min: 0.90

Identity

Key Required Description
id yes Stable identifier, and what --profile takes. Must match the filename — a profile is found by filename, and a mismatch is refused when it loads.
name yes Human-readable name, shown in reports and ossbomer profiles.
version no Version of the standard this tracks, not of ossbomer.
sources no Where the requirements come from: name, ref, url. Worth filling in, since it is how a reader checks your work.

Composition

Key Description
extends List of profile ids to inherit rules from.
excludes List of rule ids to drop from what was inherited.
extends: [eu-cra-annex-i, fedramp-sbom]
excludes: [cra-top-level-dependencies]

Your own rules are added on top. Referring to inherited rules by id means catalog updates reach you without a merge.

schema

Covered in full on Schema policy.

Key Description
min_versions Per-format version floor, e.g. spdx: "2.3".
require_signature Require a signature to be present.
deprecated_versions_forbidden Reject versions the format has retired.
deprecated_versions Override the default deprecated set per format.

rules

Key Required Description
id yes Unique within the profile. This is what excludes targets, so treat it as API.
scope yes document, component, file, or dependency. An unknown value is refused at load time.
severity yes MUST, MUST_WHERE_AVAILABLE, SHOULD, or MAY.
category yes One of the five scoring categories.
citation yes The clause this comes from, quoted in the finding.
field usually The IR field to check. Omitted when the validator works on the whole scope.
fields no Alternative IR fields for a requirement satisfiable more than one way. Takes precedence over field.
validators yes Validators to run, in order.

scope decides what the rule runs against: once for document, once per component for component, once per file entry for file, and over the dependency graph for dependency.

Available validators are listed by ossbomer validators and in the CLI reference.

What field can name

field names an attribute on the normalized document, not a path in the source file, so one rule works across SPDX and CycloneDX. Both formats are mapped onto the same shape.

Document scope:

Field Holds
creators Everyone credited with creating the SBOM: people, organizations and tools.
tools The tool-only subset of creators.
tool_versions Versions of those tools, kept separate so a rule can ask whether one was declared at all.
timestamp When the SBOM data was last changed.
sbom_version The revision of the SBOM document. Not the spec version, and not the version of what it describes.
lifecycles The lifecycle phase it was generated in, such as build. CycloneDX 1.5+ only.
name, namespace, supplier, data_license Document metadata.

Component scope:

Field Holds
name, version, type Component identity.
purl, cpe, bom_ref Identifiers.
supplier, author, publisher Who produced it.
licenses Effective license strings: the normalized SPDX form where one resolved, otherwise the raw text.
license_declarations The full record per declaration: raw text, which slot it came from, what it normalized to and how. What license_spdx_normalized reads.
hashes Algorithm to digest.
external_refs, properties Passed through from the source.

File scope:

Field Holds
name The file’s path. SPDX writes it as fileName, CycloneDX as the component name.
spdx_id The element identifier. SPDX’s SPDXID, CycloneDX’s bom-ref.
hashes Algorithm to digest, the same shape as a component’s, so one validator serves both.
licenses, copyright Per-file declarations, where the document makes them. On SPDX 3.0 licenses is empty: licensing there is a relationship to a separate license element rather than a field, and nothing resolves it yet — components are in the same position.

Anything not listed falls back to a dotted lookup into the component’s raw source mapping, so field: raw.someVendorExtension works for data the IR does not model.

File scope, and the two kinds of absence

The file inventory is optional in both formats, and a dependency-level SBOM legitimately has none. So a file rule answers two different questions and only one of them can be a violation:

Situation Verdict
No file inventory at all WARN, whatever the rule’s severity
A file entry present, required field missing the rule’s severity decides
A file entry present, field valid PASS

The first row does not follow the severity on purpose. A MUST file rule would otherwise fail every SBOM that simply does not enumerate files, which inverts the requirement. It reports WARN rather than nothing so that “not checked” stays distinguishable from “checked and satisfied”.

Within an entry the severity governs as usual, so a MUST rule still fails a file whose checksum is missing — which is what SPDX 2.3 §8.4 asks for, since it makes FileChecksum mandatory on an entry that exists.

Adding a file rule to a profile stops that profile ever returning PASS for an SBOM with no file inventory — which is most package-level SBOMs. The no-inventory WARN is not a MUST violation, so the verdict is WARN rather than FAIL, but WARN is not PASS and no amount of otherwise-perfect data clears it. Weigh that before putting a file rule in a profile that also has to judge dependency-level documents. Composing it as a separate profile, and running both, keeps the two answers separate.

A file with no checksum reaches a rule only from CycloneDX. spdx-tools refuses to parse an SPDX file entry that has none, enforcing §8.4 before any profile runs.

CycloneDX has no files section: a file is a component whose type is file. Those appear in the file inventory and stay in the component list, so existing component rules see exactly what they saw before.

When a clause accepts more than one field

Some requirements are satisfiable in more than one way. BSI TR-03183-2 §5.2.4 asks for “other unique identifiers (CPE or purl)”: either one meets it. Use fields for these, listed in precedence order:

- id: bsi-component-identifier
  scope: component
  severity: MUST_WHERE_AVAILABLE
  category: Completeness
  citation: "BSI TR-03183-2 §5.2.4: Other unique identifiers (CPE or purl), if it exists"
  fields: [purl, cpe]
  validators: [present, component_identifier]

The first field carrying a real value is what the validators see; NOASSERTION and friends do not count, so a null purl does not shadow a usable CPE. When none of them holds a value the rule reports absence, which for MUST_WHERE_AVAILABLE is a WARN rather than a violation.

Pick validators that suit every field listed. purl_wellformed alongside fields: [purl, cpe] would reject a CPE for not being a purl, which is why component_identifier decides the form per value from its prefix.

Not every field exists in every format. SPDX 2.x has no document-version or lifecycle-phase field, so sbom_version and lifecycles are empty there and a rule requiring them fails for SPDX 2.x documents. That is a true statement about the format rather than a defect in the document, and cisa-2026-min reports it as such.

license_policy

Covered in full on License policy.

Key Description
engine ospac, or omit to use only inline rules.
use_case Passed to ospac as distribution_type.
policy_path Your own ospac policy directory, relative to the profile file.
context Extra keys your policy matches on, e.g. linking_type.
rules Per-identifier overrides: spdx_id, allowed, reason.

spdx_id is required in an override, and must be a single SPDX identifier. Overrides are matched by exact identifier, so a rule without one would match nothing; that is an error at load time rather than a silently inert rule. An expression key is rejected for the same reason, so use the engine for expression-level decisions.

scoring

Key Description
weights Relative weight per category in the composite.
thresholds Signal thresholds, e.g. version_coverage_min.

Weights are normalized, so they do not have to sum to 1.0. Set a category to 0 to keep it out of the composite while still reporting it.

scoring is inherited through extends like everything else, so a profile that extends a parent and omits scoring scores with the parent’s weights rather than falling back to the built-in defaults.

Using your own profile

Put the file in a directory and point at it:

ossbomer validate --profile acme-shipping-bar --file sbom.json --profile-path ./private-profiles

--profile-path accepts several directories separated by the platform path separator. Overlays are searched before the bundled catalog, so a file sharing an id with a shipped profile replaces it.

You can also set the search path in the environment, which is often tidier for CI:

export OSSBOMER_PROFILE_PATH=/opt/acme/profiles:/opt/acme/overlays
ossbomer validate --profile acme-shipping-bar --file sbom.json

The order is --profile-path, then OSSBOMER_PROFILE_PATH, then the bundled catalog. --profile also accepts a path to a file directly, which skips the search entirely.

Environment variables

Variable Effect
OSSBOMER_PROFILE_PATH Extra profile directories, os.pathsep-separated. Searched before the bundled catalog.
OSSBOMER_LICENSE_ALIASES Extra license normalization tables, os.pathsep-separated. See License policy.