Run a release against your own requirement list
Your requirement list compared with what this run recorded; SBOMFlow did not write, interpret or review these requirements and states nothing about conformity.
Many teams answer to a list SBOMFlow does not ship: a questionnaire a customer sends each renewal, an internal release policy, a premarket or process checklist your own staff wrote from a standard you hold, or a requirement list a customer issued with a contract. SBOMFlow cannot tell you what any of those lists means, and it does not try. What it can do is let you tie each of your questions to a fact a run records, and write down, run after run, what that fact was.
Every command on this page is offline.
Write the list#
A requirement catalog is a local regime profile — the file regime-profile init writes. There is no second format. Start from an empty one:
sbomflow regime-profile init release-policy.json --organisation 'Example Devices Ltd' --profile-id our-release-policy --title 'Our release policy'The scaffold holds no requirements, only an inert example, and records supplier: customer_authored and legal_review: not_reviewed. Replace the example with your own rows. Each row is an ask:
{
"ask_id": "REL-02",
"title": "A cold-start boot trace is kept for every release",
"citation": "Release policy section 4.2",
"selector": "preserved_artifact_kind:runtime_trace",
"note": "Written by the release team; reviewed each quarter."
}ask_id, title, note and the optional citation are yours and are copied into the run's view verbatim. The selector is the one thing SBOMFlow reads: it names a fact the run records.
| Selector | What it looks for in the run |
|---|---|
artifact_present:NAME | a file the run wrote into its output directory |
evidence_signal:SIGNAL | an evidence item with that signal, and whether a person reviewed it |
preserved_artifact_kind:KIND | declared preserved-artifact rows of one kind of the closed kind vocabulary, with rows carrying an applied accepted decision counted separately |
review_decision_present:REVIEW_KEY | whether a human decision applies to one preserved-artifact review key |
manual | nothing: a person answers this row |
| approval_present or approval_present:role:ROLE | an approval the release gate counts, or one role the gate lists in satisfied_roles; the roles are the ones the run recorded | | gate_recorded or gate_recorded:policy_requirement:NAME | the gate's recorded evaluation, or its outcome for one policy, quoted verbatim | | artifact_digest_recorded:NAME | a SHA-256 the release record carries for a file the run produced | | release_comparison_present | a comparison with a previous release (--previous-output) |
sbomflow regime-profile inspect FILE explains every selector, and sbomflow regime-profile validate FILE lists every problem with a file at once. Set provenance.legal_review to what your organisation actually recorded; SBOMFlow copies it and never assesses it.
Ask about the release process#
A control list often asks how a release was made rather than what it contains: was it approved, and by whom; did the release gate run; is the SBOM's digest on record; was the release compared with the one before it. The run already holds each of those facts, and four selectors read them. A generic three-row list:
{
"asks": [
{
"ask_id": "CTL-1",
"title": "The release manager signs off every release",
"selector": "approval_present:role:release-manager",
"note": "The role name is the one our approvals ledger uses."
},
{
"ask_id": "CTL-2",
"title": "The release gate evaluates evidence gaps",
"selector": "gate_recorded:policy_requirement:fail_on_gaps",
"note": "Asked in every renewal questionnaire."
},
{
"ask_id": "CTL-3",
"title": "Each release is compared with the previous one",
"selector": "release_comparison_present",
"note": "Run with --previous-output."
}
]
}What the view records for each:
approval_present:role:release-managerreadsevidence_observedwhen the release gate lists that role insatisfied_roles, andevidence_not_observedwhen the gate lists it inmissing_rolesor when no approval or required role the run recorded carries it. The roles the run did record are quoted underrecorded; SBOMFlow never invents one. A role that appears on an approval but that no policy required readsnot_evaluable, because the gate did not evaluate it.gate_recorded:policy_requirement:fail_on_gapsreadsevidence_observedwhen the gate recorded an outcome for that policy, and quotes the outcome, the gate's enforcement mode, its exit code and its own sentence exactly asrelease-gate.jsonholds them. An informational run keeps its "No release-gate policy enforced" sentence; nothing is restated as a pass.release_comparison_presentreadsevidence_observedwhen the run recorded a comparison with a previous release, quoting its identity, andevidence_not_observedwhen it recorded none or could not read the previous release.artifact_digest_recorded:NAMEreadsevidence_observedwhenrelease-record.jsoncarries a SHA-256 for that file, quoting it, andevidence_not_observedfor a file the run did not produce.
approval_present and gate_recorded read the gate after it has decided: the list asks about the gate and is never an input to it.
Name it in the product's config#
requirement_catalogs:
- catalogs/release-policy.json # relative to sbomflow.yaml
- catalogs/customer-questionnaire.jsonThe key is file-only: an SBOMFLOW_* environment variable cannot set it. Then run as usual:
sbomflow analyze . --output outRead the view#
out/requirement-catalog-view.json holds, per list, the path the config named, your profile_id, a content digest, who authored it and its legal_review, and per row your text and one of four states:
| State | Meaning |
|---|---|
evidence_observed | the selector found, in this run's own records, the fact it names; what that means for your row is a person's decision |
evidence_not_observed | the selector ran and the run's records do not hold that fact |
manual_review | a person answers it: the selector is manual, or the fact is held and nobody has reviewed or accepted it yet |
not_evaluable | the selector could not be evaluated; never the same as not observed |
START-HERE.md lists the view with the sentence this page opens with, and sbomflow validate out checks it. Each list is registered for the run as a customer-authored view profile that is not packaged, so a list can never take an id SBOMFlow ships (cra, none, sbomflow-demo, cra-article-14).
When a list cannot be used#
A list that is missing, cannot be read, is not JSON, or is refused by the validator — an unsupported selector, a kind outside the vocabulary, an id SBOMFlow ships or another list in the run already uses, or text that states a conformity outcome — raises requirement_catalog_unreadable on stderr. The run continues, and the view names that list not_evaluable with every problem. It is never dropped from the view.
What never changes#
The view is composed after the release gate from files the run already wrote. release-gate.json, evidence-pack.json, release-record.json and the approval digest are the same with or without a list, whatever --fail-on-* policy you enforce, and under requirement_regime: cra or none. No state is a score, a readiness figure or a conformity outcome, and SBOMFlow ships no list content.
See also#
- Outputs — the view's fields.
- Requirement regimes —
regime-profileandregime-view, which reads the same list over a finished output directory. - Use SBOMFlow without CRA assessment.