Data directory¶
Everything lives under one directory (~/.bomify, or --data-dir).
Every path is derived in internal/layout and
nowhere else.
Source: docs/diagrams/data-directory.mmd
version.jsonis the directory's version (see Versioning).manifests/<hash>.jsonholds two kinds of record, told apart by hash space:- a build's manifest: the SBOM copied verbatim, keyed by its SHA-256
(
internal/build). Tags point at these. - a component's pull manifest: its SBOM entry with the computed hash
merged in, keyed by
layout.PurlHash(internal/plugin). This is what lets an identical component be reused across builds.internal/oci/pullwrites one for every component it restores, too. layers/<purlHash>/is a component's pulled content.vulnerabilities/<purlHash>/<scanner>.jsonis each scanner's latest vulnerability report of a component (see Security scanning), shared by every package containing that purl.provenance/<sbomHash>.jsonis a build's SLSA provenance, if it was built with--provenance(see Build provenance).package/repositories.jsonmapsrepo -> tag -> sbom hash.conf/*.jsonare the rule files:distribution.json(bomify distributeendpoints),trust.json(signature verification), andscan.json(scan policy). All three go throughinternal/rules: a JSON array with one rule per identity, written atomically, resolved by the most specific/-segment prefix match (internal/prefix).conf/signers.jsonis the named signerspush/save --signuse (bomify signer create): each a signing plugin and its options, such as a private key's path, never key material. It's stored withinternal/rulestoo, one entry per name, but never matched against a reference.conf/auth.jsonis registry credentials, in Docker'sconfig.jsonformat (see Credentials).vex/andkeys/are named, content-addressed stores (internal/namedstore):<sha256><ext>copies plus anindex.jsonof names. Rules refer to entries by name, so they survive the original files moving. Re-adding a name is the only way to change its content, a copy is deleted once no name uses it, and a name can't be removed while a rule uses it.vex/holds VEX documents that scan policy rules list.keys/holds public keys and certificates that trust rules' key options name. Only public material is accepted: every PEM block must parse as aCERTIFICATE, PKIXPUBLIC KEY, or PKCS#1RSA PUBLIC KEY, so a private key never lands here, even mislabeled.--option key=<path>still reads a file directly.plugins/holds installedbomify-plugin-<kind>[.exe]binaries, the only place bomify looks (plugin.Find; neverPATH), plusinstalled.jsonrecording wherebomify plugin installgot each.logs/<purlHash>.logis a plugin's log for one invocation. It is deleted when the plugin exits.
Every write that matters is atomic: a temp file or directory, renamed
into place once complete and verified (fsutil.WriteFileAtomic,
fsutil.WriteJSON, internal/oci/pull). A crash leaves a missing
file, never a corrupt one, and a missing file just means redo.
Versioning¶
version.json records which version of this layout the directory is
in. Every command that uses the directory checks it first
(layout.CheckVersion);
version, help, completion, and docs generation skip the check.
| Directory | bomify |
|---|---|
| Missing or empty | Records the current version. |
| Current version | Uses it. |
| Older version | Migrates it in place, one version at a time, recording each step as it completes, so a crash resumes where it stopped. |
| Newer version | Refuses, naming both versions. |
| Content but no version | Refuses: a pre-alpha bomify wrote it, and pre-alpha data doesn't carry over. |
Build tooling that puts files into a data directory before bomify has
run starts it with version.json first, through init_data_dir in
hack/common.sh:
make install-plugins (and so a container image built from a checkout)
and hack/push-plugin-packages.sh.
The version covers the layout above and the schemas of the files bomify
reads back: the conf/ rule files and signers.json,
repositories.json, the keys/ and vex/ indexes, installed.json,
and the manifest and provenance records. Changing any of them in a way an
older bomify would misread bumps layout.CurrentVersion and adds a
migration in the same change. Adding an optional field doesn't. The
conf/ rule files are read strictly, so an older bomify refuses a
field it doesn't know rather than verifying or gating less than the
rule says; their fields are in Signing and
Security scanning. auth.json
isn't covered: it's Docker's format, not bomify's.