Summary
Introduce a supply-chain graph for the CSSC Framework reference implementation that indexes the flow of container images through the supply chain — acquisition, base-image lineage, dependencies (SBOM), vulnerabilities, builds, promotion, and deployments — and supports multi-hop provenance/reachability queries across multiple images.
Decision: Use Kùzu — an embedded, serverless property-graph database with Cypher — as the graph store.
Motivation
We already produce rich supply-chain signals that form a natural DAG:
- OCI image annotations (
org.opencontainers.image.*, com.toddysm.*, base name/digest, build run URL)
- SPDX SBOM referrers (OCI 1.1)
- SLSA provenance referrers (OCI 1.1)
- GHCR package listings (
quarantine/*, golden/*, apps/*)
- Promotion-pending / CI-failure tracking issues
Relational joins are awkward for the questions we actually want to ask (variable-length, multi-hop). A graph store lets us answer, e.g.:
- Full provenance chain of a given image digest
- Which deployments run an image that transitively depends on a package with CVE-X (blast radius)
- What upstream image a golden image was mirrored/promoted from
Proposed graph model (grounded in existing artifacts)
Nodes: Image (per digest), Tag, BaseImage, Package/Component, Vulnerability, Build, Deployment, Issue, Source.
Edges:
Image -[MIRRORED_FROM]-> UpstreamImage
Image -[BUILT_FROM]-> BaseImage (base pinned by digest)
Image -[CONTAINS]-> Package (from SBOM)
Package -[AFFECTED_BY]-> Vulnerability
Build -[PRODUCED]-> Image, Build -[FROM_SOURCE]-> Source
Image -[PROMOTED_FROM]-> QuarantineImage (+ related Issue)
Deployment -[RUNS]-> Image
Tag -[POINTS_TO]-> Image
Alternatives considered
Requirements that drove the decision (agreed with maintainer): build it ourselves / in-repo / Python-native, embedded (no server, single on-disk store, ships inside a service), and programmatic/API querying is sufficient (the dashboard renders its own views; interactive graph-browser visualization is not a first-class requirement).
Broader landscape (rejected before narrowing to embedded)
| Option |
Model |
Why not chosen |
| GUAC (Graph for Understanding Artifact Composition) |
Purpose-built supply-chain graph; ingests SBOM/SLSA/in-toto/OCI; GraphQL |
Highest domain alignment, but requires running a server + DB and is "adopt a tool" rather than "build it ourselves"; less illustrative as a reference implementation |
| Neo4j / Memgraph |
Server property graph, Cypher |
Best interactive visualization tooling, but requires a running server; visualization is not a first-class requirement here |
| PostgreSQL + Apache AGE |
Relational + openCypher in one DB |
Viable single-store option, but pulls in a Postgres server; heavier than needed for an embedded demo |
| RDF triple store (Jena / GraphDB / Oxigraph) |
RDF / SPARQL |
Most standards-pure for provenance, but steepest learning curve; overkill for this reference implementation |
Embedded candidates (the shortlist)
| Option |
Why not first choice |
| SQLite + recursive CTEs |
Zero new deps, but hand-written recursion; variable-length path queries get painful as the model grows |
| DuckDB |
Excellent columnar analytics + recursive CTEs, but not a graph model — property-graph traversals are verbose |
| NetworkX |
Pure-Python with rich algorithms, but in-memory only — no durable single-file store, so it's a compute layer, not a source of truth |
Decision: Kùzu
- Embedded, serverless — persists to a single on-disk database, no server process ("SQLite for graphs"); matches the no-server / ships-inside-a-service constraint.
- Python-native —
pip install kuzu; drops into the existing apps/python-app/ FastAPI structure.
- Cypher — declarative multi-hop path queries for the provenance/reachability questions above.
- Columnar / fast for analytical multi-image traversals.
Optional hybrid: keep Kùzu as the source of truth and hydrate small subgraphs into NetworkX for algorithms Cypher doesn't express well (centrality, blast-radius scoring). Start with Kùzu alone.
Proposed placement in the repo
apps/python-app/libs/cssc_common/ — graph model (node/rel schemas) + ingesters reading OCI annotations, SPDX SBOM referrers, SLSA provenance referrers, GHCR packages, and tracking issues.
apps/python-app/services/graph-service/ — FastAPI service owning the Kùzu DB, exposing query endpoints (provenance chain, blast radius, deployment inventory); dashboard-web renders views on top.
- Deployment — Kùzu DB directory on a mounted volume (PVC in kind), or rebuilt on ingest for a stateless demo; Helm subchart consistent with existing services.
Next steps
Summary
Introduce a supply-chain graph for the CSSC Framework reference implementation that indexes the flow of container images through the supply chain — acquisition, base-image lineage, dependencies (SBOM), vulnerabilities, builds, promotion, and deployments — and supports multi-hop provenance/reachability queries across multiple images.
Decision: Use Kùzu — an embedded, serverless property-graph database with Cypher — as the graph store.
Motivation
We already produce rich supply-chain signals that form a natural DAG:
org.opencontainers.image.*,com.toddysm.*, base name/digest, build run URL)quarantine/*,golden/*,apps/*)Relational joins are awkward for the questions we actually want to ask (variable-length, multi-hop). A graph store lets us answer, e.g.:
Proposed graph model (grounded in existing artifacts)
Nodes:
Image(per digest),Tag,BaseImage,Package/Component,Vulnerability,Build,Deployment,Issue,Source.Edges:
Image -[MIRRORED_FROM]-> UpstreamImageImage -[BUILT_FROM]-> BaseImage(base pinned by digest)Image -[CONTAINS]-> Package(from SBOM)Package -[AFFECTED_BY]-> VulnerabilityBuild -[PRODUCED]-> Image,Build -[FROM_SOURCE]-> SourceImage -[PROMOTED_FROM]-> QuarantineImage(+ relatedIssue)Deployment -[RUNS]-> ImageTag -[POINTS_TO]-> ImageAlternatives considered
Requirements that drove the decision (agreed with maintainer): build it ourselves / in-repo / Python-native, embedded (no server, single on-disk store, ships inside a service), and programmatic/API querying is sufficient (the dashboard renders its own views; interactive graph-browser visualization is not a first-class requirement).
Broader landscape (rejected before narrowing to embedded)
Embedded candidates (the shortlist)
Decision: Kùzu
pip install kuzu; drops into the existingapps/python-app/FastAPI structure.Optional hybrid: keep Kùzu as the source of truth and hydrate small subgraphs into NetworkX for algorithms Cypher doesn't express well (centrality, blast-radius scoring). Start with Kùzu alone.
Proposed placement in the repo
apps/python-app/libs/cssc_common/— graph model (node/rel schemas) + ingesters reading OCI annotations, SPDX SBOM referrers, SLSA provenance referrers, GHCR packages, and tracking issues.apps/python-app/services/graph-service/— FastAPI service owning the Kùzu DB, exposing query endpoints (provenance chain, blast radius, deployment inventory);dashboard-webrenders views on top.Next steps
docs/architecture/cross-cutting/supply-chain-graph.md) — spans acquire/build/catalog/deploy/run.