An SBOM (Software Bill of Materials) often contains thousands of components with licenses, suppliers, checksums, and other metadata. Not all SBOMs are created equal — some may miss critical information or include risky components.
Policies help us automatically validate SBOMs against organizational requirements. They act like guardrails:
- Enforce approved licenses
- Reject banned components
- Ensure required metadata exists
In short, a policy defines what “good” looks like in an SBOM and how to react if something does not meet that expectation.
A policy file is a YAML defintion that contains.
name--> A unique identifier for the policytype--> `The kind of check (whitelist, blacklist, required)rules--> A list of conditions applied to SBOM fieldsaction--> What happens if violations are found (fail, warn, or pass)
Example:
policy:
- name: approved_licenses
type: whitelist
rules:
- field: license
values: [MIT, Apache-2.0, BSD-3-Clause]
action: failThis policy ensures every component license is one of the approved or defined values. If not(or violates), the policy fails as per the defined action.
A rule describes a specific check on a single SBOM field. Each rule contains:
field→ The SBOM attribute to check (e.g., license, supplier, version)values→ Allowed values (for whitelist/blacklist)patterns→ Regex patterns to match field valuesoperator(future support) → To extend comparisons (in, not_in, matches, not_matches)
- Multiple rules in a policy → combined with AND (all must pass)
- Multiple values/patterns in a rule → combined with OR (any value passes)
The type defines how rules are interpreted:
Ensures field values are only from the allowed set.
- Rule passes if the field value is in the values list, Therefore Pass.
- Violation if the value is outside the whitelist, Therefore action as per defined.
Example:
policy:
- name: approved_licenses
type: whitelist
rules:
- field: license
values: [MIT, Apache-2.0, BSD-3-Clause]
action: fail
- ✔ Components with MIT or Apache-2.0 →
pass - ✘ Components with GPL-3.0 → violation, therefore action will be
fail
Ensures field values are not in the banned set.
- Rule passes if the field value is not in the list/pattern, Therefore, Pass.
- Violation if it matches, Therefore, as per defined action.
policy:
- name: banned_components
type: blacklist
rules:
- field: name
patterns: ["log4j-1.*", "commons-collections-3.2.1"]
action: fail- ✔ Component okio-1.6.0 → pass
- ✘ Component log4j-1.2.17 → violation
Ensures the field is present (not missing).
policy:
- name: required_metadata
type: required
rules:
- field: supplier
- field: version
- field: license
action: fail- ✔ Component with supplier, version, and license → pass
- ✘ Component missing supplier → violation
The action defines what happens when a violation is found:
fail→ Mark the policy as failed (exit code non-zero, block CI/CD pipeline)warn→ Report the violation but continue (exit code zero)pass→ Force pass even if violations exist (useful for dry-runs)
- Rules satisfied → outcome is always
pass. - Rules violated → outcome is whatever the policy’s
actionsays:
fail→ mark as failedwarn→ mark as warningpass→ override violations and still pass
This separation lets you define what to check (type + rules) and how serious it is (action).
- Load policies (from file or CLI).
- For each policy:
- For each rule: check field values in the SBOM.
- Collect violations.
- Decide policy outcome (pass/warn/fail).
- Aggregate all results into a final compliance report.
policy:
- name: approved_licenses
type: whitelist
rules:
- field: license
values: [MIT, Apache-2.0]
action: fail
- name: banned_components
type: blacklist
rules:
- field: name
patterns: ["log4j*"]
action: fail
- name: required_metadata
type: required
rules:
- field: supplier
- field: license
action: warnOutput:
$ sbomqs policy -f samples/policy/custom/custom-policies.yaml samples/policy/in-complete.spdx.sbom.json
+-------------------+-----------+--------+--------+---------+------------+----------------------+
| POLICY | TYPE | ACTION | RESULT | CHECKED | VIOLATIONS | GENERATED AT |
+-------------------+-----------+--------+--------+---------+------------+----------------------+
| approved_licenses | whitelist | warn | warn | 6 | 6 | 2025-09-16T08:24:57Z |
| banned_components | blacklist | fail | fail | 6 | 1 | 2025-09-16T08:24:57Z |
| required_metadata | required | fail | pass | 6 | 0 | 2025-09-16T08:24:57Z |
+-------------------+-----------+--------+--------+---------+------------+----------------------+
$ sbomqs policy -f samples/policy/custom/custom-policies.yaml samples/policy/complete-sbom.spdx.json
+-------------------+-----------+--------+--------+---------+------------+----------------------+
| POLICY | TYPE | ACTION | RESULT | CHECKED | VIOLATIONS | GENERATED AT |
+-------------------+-----------+--------+--------+---------+------------+----------------------+
| approved_licenses | whitelist | warn | pass | 5 | 0 | 2025-09-16T08:25:05Z |
| banned_components | blacklist | fail | pass | 5 | 0 | 2025-09-16T08:25:05Z |
| required_metadata | required | fail | pass | 5 | 0 | 2025-09-16T08:25:05Z |
+-------------------+-----------+--------+--------+---------+------------+----------------------+Policies can be applied in two ways:
- From a policy file (YAML format)
- Directly from the CLI (inline rules)
sbomqs policy -f samples/policy/custom/custom-policies.yaml samples/policy/complete-sbom.spdx.json sbomqs apply \
--name approved_licenses \
--type whitelist \
--rules "field=license,values=MIT,Apache-2.0" \
--action fail \
samples/policy/complete-sbom.spdx.jsonExample: 2
sbomqs apply \
--name supplier_noassertion_rule \
--type blacklist \
--rules "field=supplier,values=NOASSERTION" \
--action fail \
samples/policy/in-complete-sbom.spdx.jsongraph TD
A[Start sbomqs apply] --> B{Has -f ?}
B -->|yes| C[Load policies from YAML]
B -->|no| D[Build policy from CLI flags]
C --> E[Load SBOM input]
D --> E
E --> F{Get SBOM Document}
F -->|SPDX| G[Normalize SPDX to model]
F -->|CycloneDX| H[Normalize CycloneDX to model]
G --> I[Create extractor]
H --> I
I --> J{For each policy}
J --> K{Aginst SBOM,
For each component}
K --> L{For each rule}
L -->|required| M[ok = HasField]
L -->|whitelist| N[ok = any match]
L -->|blacklist| O[ok = not any match]
M --> P{ok?}
N --> P
O --> P
P -->|no| Q[Record violation]
P -->|yes| R[Rule passed]
Q --> S{More rules?}
R --> S
S -->|yes| L
S -->|no| T[AND across rules]
T --> U{More components?}
U -->|yes| K
U -->|no| V[Decide policy outcome]
V --> W{More policies?}
W -->|yes| J
W -->|no| X[Aggregate results]
X --> Y{Output format?}
Y -->|table| Z1[Print table]
Y -->|json| Z2[Print JSON]
Y -->|yaml| Z3[Print YAML]
Z1 --> AA[Set exit code]
Z2 --> AA
Z3 --> AA
AA --> AB[End]