Evidence outputs
Every SBOMFlow run writes plain files into a directory you choose. There is no database and no hidden state: what you see in the output directory is the system of record. This page explains each artifact — what it contains, whether it is a default or opt-in output, whether it carries an observation or a human decision, and who should look at it.
Note
Observation vs decision is the most important column. An observation is
what the engine derived from files and hashes. A decision exists only when
a named human recorded one. The two are never merged.
The 14 default artifacts
Produced by every analyze/audit run, offline, with no flags:
| Artifact | What it is | Observation or decision | Who reads it |
|---|---|---|---|
evidence-pack.json | The complete machine-readable record: components with provenance, dependency edges, evidence items, gaps, findings, signals. | Observations, plus reviewer status fields that default to unreviewed | Engineers and integrators; everything else derives from this |
artifact-manifest.json | SHA-256, size, and classification for every scanned file, with whether it contributed components or evidence. | Observation | Anyone verifying that evidence traces to exact bytes |
scan-warnings.json | Every malformed or recognized-but-unsupported input, with a stable code and exact path. Nothing is silently dropped. | Observation | The engineer running the scan; CI in strict mode |
cyclonedx-sbom.json | CycloneDX 1.6 SBOM with purls, licenses, and the dependency graph. Structurally validated. | Observation | Customers, importers, security tooling |
spdx-sbom.json | SPDX 2.3 SBOM with purl external references and relationships. | Observation | Customers and license workflows |
cra-coverage.json | Observed evidence mapped to a versioned model of CRA Annex I. Manual-only areas are labelled not_automatically_assessable — never failed, never passed. | Observation | Product-security and compliance owners |
reachability.json | Conservative source-reference triage per finding. not_observed means "our deterministic scanners did not observe a reference" — never "safe". | Observation | Vulnerability triage |
release-gate.json | The gate evaluation: which policies were enforced, what blocked, what was suppressed by reviewed VEX, and the exit code. Informational unless you enforce --fail-on-*. | Observation of your configured policy | Release engineering and CI |
release-record.json | This release's identity, counts, artifact hashes, and SBOM references — the unit that release comparison consumes. | Observation | Release history workflows |
issues.json / issues.md | Actionable items from gaps and findings, with stable keys, lifecycle states, and suggested owners. Known-exploited findings sort first. | Observation | Whoever fixes things; trackers |
audit-log.jsonl | Append-only, hash-chained run and decision events. Later modification breaks the chain and fails validation. | Record of events, including human decisions when they happen | Auditors and reviewers |
assessment-report.html | A single-file, human-readable report of all of the above. Opens in any browser, no server. | Observation | Everyone — start here |
vuln-source-health.json | Which vulnerability sources ran, their freshness, and whether any produced no usable intelligence. | Observation | Anyone asking "why were no CVEs found?" |
Opt-in artifacts
Each appears only when you ask for it; all remain offline unless stated:
| Artifact | Flag / command | Observation or decision |
|---|---|---|
vex.json (OpenVEX) and cyclonedx-vex.json | --emit-vex | Decision-bearing: statuses come from your recorded vulnerability reviews; not_affected without a valid justification is downgraded, never emitted |
ssvc.json | --emit-ssvc | Observation — a suggested priority from the CISA decision table; never sets status or blocks a gate |
Technical-documentation pack + eu-declaration-of-conformity.DRAFT.* | --emit-techdoc | Observation assembled for humans; the declaration is an UNSIGNED DRAFT and the watermark is validator-enforced |
cra-article14-*.DRAFT.json/.md | --emit-incident-report | Drafts with submitted: false; SBOMFlow never files or transmits them |
release-drift.json | --previous-output or compare-releases | Observation: added/removed/changed components, findings, evidence, gates, and support periods between two releases |
evidence-bundle.json/html/zip | audit (ZIP via --zip) | Portable reviewer handoff copied from existing artifacts; byte-reproducible ZIP; adds no new claims |
| Sharing pack | sharing flags on audit | A redacted, documented subset for importers/distributors |
issues.csv, SARIF, PDF summary | export flags | Observations reformatted for spreadsheets, code-scanning UIs, and print |
reviews.json, vulnerability_reviews.json, waivers, approvals | review / approve commands | Decisions — recorded with reviewer identity, timestamps, and audit events |
| Importer evidence (OCI layout, CMake, linker map, Zephyr, MCUboot, update manifests, provenance checks) | dedicated commands | Observations from explicitly supplied local inputs |
How to verify an output directory
sbomflow validate ./evidenceValidation checks structure, cross-artifact consistency (counts, references, finding keys), hashes, the audit-log hash chain, and draft watermarks. A tampered or partially copied directory fails with exit code 4. Optional extras add official JSON-Schema validation when installed; without them the structural baseline still runs and says exactly what was skipped.
Determinism
With a fixed --as-of timestamp, repeat runs over the same inputs are byte-identical — including the bundle ZIP. Without --as-of, only documented runtime timestamps (and fields derived from them, such as the audit-log hash chain) differ; components, edges, gaps, warnings, and purls do not. That is what makes the artifacts diff-able and reviewable.
Next: read your first bundle · warning codes · exit codes