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:

sh
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:

json
{
  "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.

SelectorWhat it looks for in the run
artifact_present:NAMEa file the run wrote into its output directory
evidence_signal:SIGNALan evidence item with that signal, and whether a person reviewed it
preserved_artifact_kind:KINDdeclared preserved-artifact rows of one kind of the closed kind vocabulary, with rows carrying an applied accepted decision counted separately
review_decision_present:REVIEW_KEYwhether a human decision applies to one preserved-artifact review key
manualnothing: 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:

json
{
  "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-manager reads evidence_observed when the release gate lists that role in satisfied_roles, and evidence_not_observed when the gate lists it in missing_roles or when no approval or required role the run recorded carries it. The roles the run did record are quoted under recorded; SBOMFlow never invents one. A role that appears on an approval but that no policy required reads not_evaluable, because the gate did not evaluate it.
  • gate_recorded:policy_requirement:fail_on_gaps reads evidence_observed when 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 as release-gate.json holds them. An informational run keeps its "No release-gate policy enforced" sentence; nothing is restated as a pass.
  • release_comparison_present reads evidence_observed when the run recorded a comparison with a previous release, quoting its identity, and evidence_not_observed when it recorded none or could not read the previous release.
  • artifact_digest_recorded:NAME reads evidence_observed when release-record.json carries a SHA-256 for that file, quoting it, and evidence_not_observed for 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#

yaml
requirement_catalogs:
  - catalogs/release-policy.json      # relative to sbomflow.yaml
  - catalogs/customer-questionnaire.json

The key is file-only: an SBOMFLOW_* environment variable cannot set it. Then run as usual:

sh
sbomflow analyze . --output out

Read 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:

StateMeaning
evidence_observedthe 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_observedthe selector ran and the run's records do not hold that fact
manual_reviewa person answers it: the selector is manual, or the fact is held and nobody has reviewed or accepted it yet
not_evaluablethe 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#