From 953cffe63bfea18cce1537dc8c4ae9290edffe68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Garc=C3=ADa=20Veytia=20=28Puerco=29?= Date: Tue, 8 Sep 2026 15:03:37 -0600 Subject: [PATCH 1/2] Expand README with backend overview and quick-start example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Adolfo García Veytia (Puerco) --- README.md | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0150a22..f3eed07 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,104 @@ -# storage -Storage backends for protobom +# protobom storage + +[![Go Reference](https://pkg.go.dev/badge/github.com/protobom/storage.svg)](https://pkg.go.dev/github.com/protobom/storage) + +Storage backends for [protobom](https://github.com/protobom/protobom), the +format-neutral SBOM data model. Each backend implements the +[`storage.Backend`](https://pkg.go.dev/github.com/protobom/protobom/pkg/storage#Backend) +interface from protobom, so a `sbom.Document` parsed from SPDX or CycloneDX can +be persisted and retrieved from a database or object store with the same +`Store` / `Retrieve` calls. + +## Backends + +| Package | Storage | Notes | +| ----------------------- | --------------------------- | ------------------------------------------------------------------------------------------- | +| `backends/ent` | SQLite via [ent](https://entgo.io) | Fully relational schema, in-memory or file-backed. Supports document and node annotations. | +| `backends/clickhouse` | [ClickHouse](https://clickhouse.com) | Stores the serialized document plus wide node and edge tables for analytical queries. | +| `backends/gcs` | Google Cloud Storage | Object-store backend with a key index for lookups by identifier, hash and name. | +| `backends/objectstore` | Any object store | Provider-agnostic core used by `gcs`. Implement the `ObjectStore` interface to add S3, MinIO, etc. | + +## Installation + +```console +go get github.com/protobom/storage +``` + +## Quick start + +The example below parses a CycloneDX SBOM, stores it in an in-memory SQLite +database using the `ent` backend, and reads it back by document ID. + +```go +package main + +import ( + "fmt" + + "github.com/protobom/protobom/pkg/reader" + + "github.com/protobom/storage/backends/ent" +) + +func main() { + // Parse an SBOM (SPDX or CycloneDX) into a protobom document. + doc, err := reader.New().ParseFile("sbom.cdx.json") + if err != nil { + panic(err) + } + + // Create the backend. The default database is ":memory:"; + // use ent.WithDatabaseFile("sboms.db") to persist to disk. + backend := ent.NewBackend() + if err := backend.InitClient(); err != nil { + panic(err) + } + defer backend.CloseClient() + + // Store the document. + if err := backend.Store(doc, nil); err != nil { + panic(err) + } + + // Retrieve it again by its ID. + stored, err := backend.Retrieve(doc.GetMetadata().GetId(), nil) + if err != nil { + panic(err) + } + + fmt.Printf("%s has %d nodes\n", stored.GetMetadata().GetId(), len(stored.GetNodeList().GetNodes())) +} +``` + +Switching backends only changes the constructor. For example, to use ClickHouse: + +```go +backend := clickhouse.NewBackend( + clickhouse.WithAddr("localhost:9000"), + clickhouse.WithCredentials("default", ""), +) +``` + +or Google Cloud Storage: + +```go +backend := gcs.NewBackend(gcs.WithBucket("my-sboms")) +``` + +See the `Example` test in [`backends/ent/example_test.go`](backends/ent/example_test.go) +for a complete, runnable round trip and the per-package documentation on +[pkg.go.dev](https://pkg.go.dev/github.com/protobom/storage) for all options. + +## Development + +```console +make help # list all targets +make lint # run golangci-lint +make test-unit # ent backend unit tests (no external services) +make test-clickhouse # needs a ClickHouse server; see CLICKHOUSE_ADDR/USER/PASSWORD +make test-gcs # needs STORAGE_EMULATOR_HOST or GCS credentials +``` + +## License + +Apache-2.0. See [LICENSE](LICENSE). From 4fca429bf1b738c61c5cbecd759ff197d79cdfa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adolfo=20Garc=C3=ADa=20Veytia=20=28Puerco=29?= Date: Tue, 8 Sep 2026 15:04:39 -0600 Subject: [PATCH 2/2] Cut patch release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is an intentionally empty commit that records release intent. It makes no source changes, its only payload is the git trailers below, which the Carabiner tagger reads when the pull request is merged to create a signed, policy-checked semantic version tag. Removing this commit before merge simply cancels the release request. Tag-commit-as: patch Signed-off-by: Adolfo García Veytia (Puerco)