Push and pull¶
internal/oci/push and
internal/oci/pull store a package as an ordinary
OCI artifact (artifact type application/vnd.bomify.package.v1+json;
every type and annotation is listed in Registry format):
Source: docs/diagrams/oci-artifact.mmd
- The config is the SBOM (
application/vnd.cyclonedx+jsonor+xml, sniffed). - A component's layers, annotated
land.bomify.purl, are tars of its files undertransfer.LargeFileSize(64 MiB), and each larger file as raw parts of at mosttransfer.MaxLayerSize(4 GiB), so no layer outgrows a registry's limit.transfer.WriteTarzeroes mtimes and uid/gid, so a tar's digest depends only on names, modes, and content; otherwise re-pushing a component bomify had pulled would re-upload it. A part is the file's own bytes, so an unchanged large file is the same blob in every package, and uploads once. - Signatures, the report referrer, VEX referrers, and the provenance attestation (see Build provenance) are OCI referrers, so none changes the package digest.
Source: docs/diagrams/registry-layout.mmd
Source: docs/diagrams/registry-signatures.mmd
Layers transfer concurrently (--concurrency), each verified against
its digest and size as it streams, with a progress bar per blob. push
skips blobs the target already has. That's required, not an
optimization: a local content/oci.Store rejects re-pushing a digest,
which save hits when tags share a component. A part streams straight
from its file, read once to hash and once to upload, so a large file is
never copied; tars go through a temporary file.
pull restores a component from all its layers into a temporary
directory and swaps it into place only once every layer verifies (see
pull.restoreComponent). It checks the parts' annotations before
downloading anything, creates each large file at full size, then
unpacks the tars, refusing any entry naming a file that exists, and
writes each part at its offset.
Save and load¶
bomify save/load (internal/oci/save) run
push/pull unchanged against a local OCI image layout instead of a
registry, then tar or untar it. Shared components are stored once, and
signatures and report referrers travel inside the tarball, so load
verifies and restores exactly as pull does.
Source: docs/diagrams/save-load.mmd
Credentials¶
internal/auth is the one source of registry
credentials, for login/logout, push/pull, and plugins through
pkg/auth. login/logout write only
<dataDir>/conf/auth.json, a Docker-format config backed by the native
credential store as Docker's is. Reads try it first, then Docker's own
config.json, so an existing docker login still works and bomify
logout never removes it. Native helpers key secrets by host alone, so
both tools share one secret for a host logged into with both.
Login verifies a credential before storing it, and falls back to
plaintext in auth.json (with a warning) only when no credential helper
exists, as docker login does. login --verify=false (Save) stores
one unverified instead, the same way, for a host that isn't an OCI
registry and so can't be checked: a Hugging Face hub
bomify-plugin-huggingface pulls from and pushes to, or an HTTPS server
bomify-plugin-generic downloads from. bomify exports the data
directory in use as BOMIFY_DATA_DIR to the plugins it runs, so
pkg/auth finds the same auth.json under --data-dir.