Documentation
¶
Overview ¶
Pure core of the SBOM lens: the wire types, the CycloneDX parser, the row builder, and the datastore value coercers. Everything here is I/O-free so the tests drive it with inline documents — no datastore needed — exactly as the analytics lens proves out its assemblers. The handlers (sbom.go) are the thin orchestration that persists these rows and reads them back.
Registry pull — the CONSUMER half of the SBOM lane. The registry is the source of truth: CI produces the CycloneDX SBOM and `cosign attach`es it to the image DIGEST. This file reads that attached artifact back with go-containerregistry (pure-Go, no binary deps) and hands the raw CycloneDX document to the SAME server-side parser the POST /v1/sbom path uses (parseComponents), so ingest and pull share one component-flattening code path.
Two attachment conventions are honored, in order:
- cosign SBOM tag — `cosign attach sbom` writes an image tagged `sha256-<hex>.sbom` in the SAME repo as the subject. Deterministic, no referrers API needed. Tried first.
- OCI 1.1 referrers — the registry's /referrers response for the digest lists manifests that declare the subject; we pick the CycloneDX one by its artifactType/mediaType. Fallback for registries/producers that use referrers.
A pull failure is NON-FATAL to the caller: pull-on-miss simply falls back to the honest 404. Nothing here fabricates components — a document must parse as CycloneDX or it is ignored.
Package sbom mounts the Hanzo Cloud /v1/sbom/* surface: the backend half of "SBOM visible in console on deployments + tracked in the datastore globally". CI POSTs a CycloneDX SBOM keyed by image digest; the console GETs it back by digest or image ref.
GLOBAL BY DESIGN. Unlike the analytics lens (which is strictly per-org), an SBOM belongs to an image DIGEST, not a tenant — the digest is content-addressed, so any tenant deploying that image resolves the SAME component set. The store is therefore cross-tenant on purpose: ingest is gated to super-admin/CI (the build fleet), and resolve exposes only the immutable bill-of-materials of an image, no tenant data. This is why there is no org predicate here.
ONE datastore client. Like clients/analytics, this package rides the SAME datastore-go client the ai subsystem opens in the shared Bootstrap (ai/object.DatastoreExec/DatastoreQuery). It never opens a second connection.
Surface (/v1 only):
POST /v1/sbom ingest a CycloneDX SBOM (super-admin / CI only)
GET /v1/sbom/{ref} resolve by image digest OR image ref (for the console)
GET /v1/sbom/health liveness + datastore connectivity (not JWT-gated)
Registered as id "sbom" with cloud.HealthOwner + order 137: it serves its own /v1/sbom/health, so serve.go skips the generic liveness route. Order 137 binds /v1/sbom/* before the ai subsystem's /v1/* catch-all (150).
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Prefetch ¶
Prefetch materializes the SBOM for a deployed image ref if it is not already in the datastore, on a deploy-digest signal from the platform. It is the deploy-time trigger: idempotent (a hit is a no-op), best-effort (a miss/pull-failure logs and returns, never blocks a deploy), and safe to call from a goroutine. Exported so clients/platform can fire it after a deployment goes live WITHOUT this package importing platform (dependency points platform → sbom, one direction).
Types ¶
type SbomComponent ¶
type SbomComponent struct {
Name string `json:"name"`
Version string `json:"version"`
Type string `json:"type"`
Purl string `json:"purl"`
License string `json:"license"`
}
SbomComponent is one flattened dependency: name/version/type/purl + a single license string (first id | name | expression found, else "").
type SbomIngest ¶
type SbomIngest struct {
ImageDigest string `json:"imageDigest"`
ImageRef string `json:"imageRef"`
SourceRepo string `json:"sourceRepo"`
GitSha string `json:"gitSha"`
Format string `json:"format"`
Document json.RawMessage `json:"document"`
}
SbomIngest is the POST /v1/sbom body from CI: the image identity + a raw CycloneDX document whose components[] we flatten and persist.
type SbomView ¶
type SbomView struct {
ImageDigest string `json:"imageDigest"`
ImageRef string `json:"imageRef"`
SourceRepo string `json:"sourceRepo"`
GitSha string `json:"gitSha"`
IngestedAt string `json:"ingestedAt"`
ComponentCount int `json:"componentCount"`
Truncated bool `json:"truncated,omitempty"`
Components []SbomComponent `json:"components"`
}
SbomView is the GET /v1/sbom/{ref} response the console renders.