SBOM Validation Overview
The minimum supported CycloneDX version for SBOM validation is CycloneDX 1.5.
The hopctl validate sbom
command (introduced in Hoppr v1.11.0) is used to validate that an SBOM:
- is using the current latest CycloneDX specification version
- is populated with the minimum fields recommended by NTIA
- has valid license data with no expired or soon-to-expire licenses
The command can be configured to simply emit warnings or optionally return a failing exit code using various strictness flags when missing fields or invalid values are encountered.
Command Line Options
Usage: hopctl validate sbom [OPTIONS]
Validate SBOM file(s)
| Options | Flag | Type | Description |
| ---------------------------- | ---- | --------- | ----------------------------------------------------------------------------------- |
| --manifest
| --sbom | -s | FILE | Path to SBOM file (can be specified multiple times) |
| --sbom-dir | -d | DIRECTORY | Directory containing SBOM files (can be specified multiple times) |
| --sbom-url
| --strict | -S | | Enable all strict validation options |
| --strict-ntia-minimum-fields | -n | | Raise error if minimum fields recommended by NTIA are not set |
| --strict-license-fields | -l | | Raise error if SBOM license or SBOM/component license expiration fields are not set |
| --expiration-days | -d | FLOAT | Number of days allowed by license expiration check |
| --output-format | -f | [json] | Format for output file [default: json] |
| --output-file | -o | FILE | Path to output file |
| --help | -h | | Show this message and exit. |
| Experimental | Flag | Type | Description |
| --------------------------------- | ------------------------------ | ------------------------------- | ------------------------------------------------------------------------------ |
| --profile | -p | [strict|licensing|ntia|default] | Profile of configuration presets to apply (supersedes --strict* flags) │
│ --config | -c | FILE | Path to a validation config file [env var: HOPPR_CONFIG] |
Checks
Components of type operating-system
are not evaluated since they often don't contain the required fields.
NTIA Minimum Recommended Fields
The following checks will be performed on the SBOM document and its metadata:
- Is this SBOM using the latest CycloneDX specification version?
- Does the SBOM specify the
metadata
field?- Does the SBOM metadata specify one of the
authors
ortools
fields? - Does the SBOM metadata specify the
timestamp
field?
- Does the SBOM metadata specify one of the
The following checks will be performed on each component in the SBOM's components
array:
- Does the component specify the
supplier
field? - Does the component specify the
name
field? - Does the component specify the
version
field? - Does the component specify one of the unique identifier fields
cpe
,purl
, orswid
?
License Fields
The following checks will be performed on the SBOM's metadata
field and each component in the components
array:
- Does the metadata or component specify the
licenses
field?
The following checks will be performed on each license in the metadata or component licenses
array:
- Does the license specify one of the
id
orname
fields? - Does the license specify the
licensing
field?
License Expiration
The following checks will be performed on each license in the metadata or component licenses
array:
- If present, does the
licensing
field specify theexpiration
field? - Is the date in the
expiration
field in the past (expired), or within the minimum allowable number of days in the future (about to expire)?
The minimum allowable number of days for a license's expiration to pass
validation is configured via the --expiration-days
option (default: 30)
Strictness Flags
The command line options --strict
, --strict-ntia-minimum-fields
, and --strict-license-fields
control whether a validation failure will be displayed as a warning or a failure, as well as
whether to return a failing exit code of 1
upon completion.
Validating with no strictness options specified (warn only) will still report validation errors,
but will be logged in the log file at the WARN
log level, displayed with a warning symbol in the
result summary, and return an exit code of 0
.
Experimental
SBOM validation has been updated in version 1.12 to allow for the customization of check severity.
Experiemental validation works as a set of profiles in place of the existing strictness flags.
Profile
licensing
- licensing check failures are treated aserrors
ntia
- minimum recommended NTIA fields check failures are treated aserrors
strict
- applies configurations from thelicensing
andntia
profilesdefault
- license or missing NTIA field checks are treated aswarnings
Configuration
The supplied configuration file for sbom validation is what allows for the customization of how the check results are interpreted. It will be merged with the selected profile (or default) and take priority over any shared existing keys.
Each check listed will accept a value of either ignore
, warn
, or error
to configure
desired response behavior on failure.
An example of the strict check override configuration. The other built in profiles can be found in the hoppr project here.
---
sbom-checks:
components-field: warn
unique-id: warn
vulnerabilities-field: warn
metadata-checks:
licenses:
name-or-id: error
last-renewal: warn
purchase-order: warn
license-types: error
licenses-field: error
authors: error
timestamp: error
component-checks:
licenses:
name-or-id: error
license-types: error
licenses-field: error
name-field: error
supplier-field: error
version-field: error
unique-id: error
Items can be excluded from validation altogether by specifying a pattern under the top-level
exclude:
key. Any items matching these patterns will not be evaluated during validation.
A pattern can be one of the following forms:
jmespath:<JMESPath search expression>
- An object representing objects to exclude based on the fields and patterns specified
In the latter form, the name of each first child of the exclude:
object must be one of the
types defined as an array by the CycloneDX specification.
---
exclude:
<CycloneDX array object name>: # e.g. `components`, `licenses`
# multiple fields defined on the same list item represent an AND relationship
- <field name 1>: <field value or pattern>
<field name 2>: <field value or pattern>
# separate list items represent an OR relationship when filtering
- <field name 3>: <field value or pattern>
# alternatively, exclusion filter can be specified with a JMESPath expression
- jmespath:<JMESPath search expression>
The <field value or pattern>
above can be one of:
regexp:/<regular expression identifying elements to exclude>/[gmi]*
- literal string representing the desired exclusion value
Example exclude configuration
# Configuration for items to exclude from validation.
exclude:
# license
license: [{"license": {"id": "SSPL-1.0"}}]
component-checks:
licenses:
name-or-id: error
license-types: error
licenses-field: error
name-field: error
supplier-field: error
version-field: error
unique-id: error
Examples
The following SBOM file named acme.cdx.json
will be used in the subsequent examples:
{
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"serialNumber": "urn:uuid:b6f4e926-6a94-4209-960f-c7045f4e3440",
"version": 1,
"metadata": {
"timestamp": "2023-11-27T23:57:56+00:00",
"licenses": [
{
"license": {
"name": "Acme Software License",
"url": "https://acme-software.com/licenses/LICENSE.txt"
}
}
],
"tools": [],
"component": {
"bom-ref": "pkg:oci/python@sha256%3A31ceea009f42df76371a8fb94fa191f988a25847a228dbeac35b6f8d2518a6ef?arch=amd64\u0026repository_url=index.docker.io%2Flibrary%2Fpython",
"type": "container",
"name": "Acme Software",
"version": "1.0.0",
"purl": "pkg:oci/python@sha256%3A31ceea009f42df76371a8fb94fa191f988a25847a228dbeac35b6f8d2518a6ef?arch=amd64\u0026repository_url=index.docker.io%2Flibrary%2Fpython"
}
},
"components": [
{
"bom-ref": "cd42f200-197b-41df-9d39-f86ce6e8dce4",
"type": "operating-system",
"name": "debian",
"version": "12.2"
},
{
"bom-ref": "pkg:deb/debian/adduser@3.134?arch=all\u0026distro=debian-12.2",
"type": "library",
"supplier": {
"name": "Debian Adduser Developers \u003cadduser@packages.debian.org\u003e"
},
"name": "adduser",
"version": "3.134",
"licenses": [
{
"license": {
"name": "GPL-2.0"
}
}
],
"purl": "pkg:deb/debian/adduser@3.134?arch=all\u0026distro=debian-12.2"
},
{
"bom-ref": "pkg:deb/debian/apt@2.6.1?arch=amd64\u0026distro=debian-12.2",
"type": "library",
"supplier": {
"name": "APT Development Team \u003cdeity@lists.debian.org\u003e"
},
"name": "apt",
"version": "2.6.1",
"licenses": [
{
"license": {
"name": "GPL-2.0"
}
},
{
"license": {
"name": "BSD-3-Clause"
}
},
{
"license": {
"name": "Expat"
}
}
],
"purl": "pkg:deb/debian/apt@2.6.1?arch=amd64\u0026distro=debian-12.2"
}
]
}
Warn Only
$ hopctl validate sbom --sbom acme.cdx.json --log hoppr.log --basic-term
Validating acme.cdx.json...
======================================================== Summary =========================================================
Results for acme.cdx.json:
CycloneDX Specification Version ✔
Minimum NTIA Fields ⚠
1 out of 1 SBOM licenses missing minimum license fields ⚠
1 out of 1 SBOM licenses expired or expiring within 30 days ⚠
0 out of 2 components missing minimum NTIA fields ✔
4 out of 4 component licenses missing minimum license fields ⚠
4 out of 4 component licenses expired or expiring within 30 days ⚠
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
See log file hoppr.log for full results.
$ echo $?
0
Enforce NTIA Minimum Recommended Fields
$ hopctl validate sbom --sbom acme.cdx.json --strict-ntia-minimum-fields --log hoppr.log --basic-term
Validating acme.cdx.json...
======================================================== Summary =========================================================
Results for acme.cdx.json:
CycloneDX Specification Version ✔
Minimum NTIA Fields ❌
1 out of 1 SBOM licenses missing minimum license fields ⚠
1 out of 1 SBOM licenses expired or expiring within 30 days ⚠
0 out of 2 components missing minimum NTIA fields ✔
4 out of 4 component licenses missing minimum license fields ⚠
4 out of 4 component licenses expired or expiring within 30 days ⚠
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
See log file hoppr.log for full results.
$ echo $?
1
Enforce Required License Fields
$ hopctl validate sbom --sbom acme.cdx.json --strict-license-fields --log hoppr.log --basic-term
Validating acme.cdx.json...
======================================================== Summary =========================================================
Results for acme.cdx.json:
CycloneDX Specification Version ✔
Minimum NTIA Fields ⚠
1 out of 1 SBOM licenses missing minimum license fields ❌
1 out of 1 SBOM licenses expired or expiring within 30 days ❌
0 out of 2 components missing minimum NTIA fields ✔
4 out of 4 component licenses missing minimum license fields ❌
4 out of 4 component licenses expired or expiring within 30 days ❌
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
See log file hoppr.log for full results.
$ echo $?
1
Enforce All Validation Checks
The --strict
option is equivalent to including both the --strict-ntia-minimum-fields
and --strict-license-fields
options.
$ hopctl validate sbom --sbom acme.cdx.json --strict --log hoppr.log --basic-term
Validating acme.cdx.json...
======================================================== Summary =========================================================
Results for acme.cdx.json:
CycloneDX Specification Version ✔
Minimum NTIA Fields ❌
1 out of 1 SBOM licenses missing minimum license fields ❌
1 out of 1 SBOM licenses expired or expiring within 30 days ❌
0 out of 2 components missing minimum NTIA fields ✔
4 out of 4 component licenses missing minimum license fields ❌
4 out of 4 component licenses expired or expiring within 30 days ❌
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
See log file hoppr.log for full results.
$ echo $?
1