Help us shape the future of Go! Take the 2026 Go Developer Survey

ocidex

module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 20, 2026 License: MIT

README

OCIDex

A metadata catalog for your software supply chain.

OCIDex ingests CycloneDX SBOMs, links them to the software artifacts they describe, and gives you a searchable inventory of every component, version, and license across your entire portfolio — with a changelog that shows exactly what changed between releases.

OCIDex dashboard showing artifact list

Changelog of the image over time

Details for a particular package


Features

  • SBOM Ingestion — POST a CycloneDX JSON document and OCIDex validates, parses, and stores it with full component and dependency graph data.
  • Artifact Tracking — SBOMs are grouped by artifact (container image, library, application). Browse the full version history of any artifact.
  • Changelog — See exactly which components were added, removed, or changed between any two SBOMs for an artifact.
  • SBOM Diffing — Pick any two SBOMs across any artifacts and compare them side by side.
  • Component Search — Find any package by name, group, or type across all ingested SBOMs. See which artifacts use it and how many versions exist.
  • License Inventory — Every license found across your SBOMs in one place, categorized as permissive, weak-copyleft, or copyleft, with per-artifact summaries.
  • Enrichment Pipeline — After ingestion, background workers enrich SBOMs with additional data. The built-in OCI metadata enricher pulls image labels, architecture, and build info directly from container registries.
  • OpenAPI Documentation — The API spec is generated from code at startup via huma. Browse it at /docs.

Quick Start

With Docker Compose

The fastest way to get a running instance with seed data:

git clone https://github.com/pfenerty/ocidex.git
cd ocidex
cp .env.example .env   # fill in GitHub OAuth credentials and SESSION_SECRET
docker compose up -d

This starts PostgreSQL, NATS JetStream, the OCIDex API server (port 8080), the scanner and enrichment workers, and the web frontend (port 3000). Database migrations run automatically on startup.

Then open http://localhost:3000.

To populate it with real-world SBOMs from public container images, log in with GitHub, create an API key under Settings → API Keys, and run the seeder:

export OCIDEX_API_KEY=ocidex_...
flox activate -- make seed

This registers a set of well-annotated public repositories from quay.io and ghcr.io and triggers a scan on each. It exits once the first artifacts appear; the remaining images continue scanning in the background.

From Source

OCIDex uses Flox to manage its development environment (Go, Node, npm, oras, syft, and other tools).

git clone https://github.com/pfenerty/ocidex.git
cd ocidex
flox activate

# Go dev tools are pinned in tools/go.mod and build on first use (no install step)

# Start PostgreSQL and NATS (via docker-compose, or provide your own)
docker compose up -d postgres nats

# Configure — SESSION_SECRET is always required, plus at least one identity
# provider: GITHUB_CLIENT_ID + GITHUB_CLIENT_SECRET, or OIDC_ISSUER_URL +
# OIDC_CLIENT_ID, or both. Edit DATABASE_URL / NATS_URL if needed
cp .env.example .env

# Run migrations and build
make migrate-up
make build
make frontend

# Start the server
make run

.env is read by docker-compose and by the make targets, which export it before running anything. The binaries themselves read only the process environment — so ./bin/ocidex invoked directly ignores .env and exits on the required variables. Export them first if you want to run it outside make:

set -a; . ./.env; set +a
./bin/ocidex

The API serves on :8080 by default. For frontend development with hot reload:

make frontend-dev   # Vite dev server on :3000, proxies /api/* to :8080
Installing the CLI

ocidex-cli is the command-line client for the API — registry, sbom, artifact, component, job and key subcommands, plus login. It ships two ways, and building the repo is not one of them:

# With a Go toolchain
go install github.com/pfenerty/ocidex/cmd/ocidex-cli@latest
ocidex-cli version

# Without one
docker run --rm ghcr.io/pfenerty/ocidex-cli:main --help

A go installed binary carries no -ldflags, so ocidex-cli version reports the module version and VCS stamps the toolchain embedded instead; the published image reports the CI-injected version. Point it at a server with OCIDEX_URL and authenticate with OCIDEX_API_KEY, or run ocidex-cli login to write ~/.config/ocidex/config.yaml. See ADR-029 for the full configuration precedence and exit codes.

Connecting an Agent

ocidex-mcp serves the catalog to MCP clients over stdio, reusing the credentials ocidex-cli login already wrote:

go install github.com/pfenerty/ocidex/cmd/ocidex-mcp@latest
claude mcp add ocidex -- ocidex-mcp

Fourteen tools cover lookup, diff, changelog, vulnerabilities and ingest. See the MCP Server guide for the full list, client configuration and troubleshooting.

Ingest Your First SBOM

Generate an SBOM with syft and send it to OCIDex:

syft registry:docker.io/library/nginx:latest -o cyclonedx-json | \
  curl -X POST http://localhost:8080/api/v1/sbom \
    -H "Content-Type: application/json" \
    -d @-

Tech Stack

Layer Technology
Language Go
HTTP chi + huma (code-first OpenAPI 3.1)
Database PostgreSQL (pgx driver, sqlc query gen, goose migrations)
Messaging NATS JetStream (scan and enrichment job queue)
Frontend SolidJS + TanStack Query + Tailwind CSS
API Client openapi-fetch with generated TypeScript types
Testing matryer/is (unit), testcontainers-go (integration)
Container Docker multi-stage build — distroless static-debian13 for Go, Chainguard nginx for the web tier (ADR-038)
Dev Environment Flox

Project Structure

cmd/ocidex/              API server entry point, wiring, graceful shutdown
cmd/scanner-worker/      OCI registry scanner (NATS daemon + --once K8s Job mode)
cmd/oci-metadata-worker/ Per-enricher workers, one per enrichment_jobs partition
cmd/git-worker/          (NATS daemon + --once K8s Job mode; see ADR-033)
cmd/user-enricher-worker/
cmd/provenance-worker/
cmd/vuln-worker/         Matches SBOMs against the grype vulnerability DB (ADR-049)
internal/api/            HTTP handlers and routing (chi + huma)
internal/service/        Business logic interfaces and implementations
internal/repository/     Data access layer (sqlc-generated queries)
internal/enrichment/     Pluggable enrichment pipeline
internal/scanner/        OCI registry scanning (Syft engine)
internal/nats/           NATS JetStream client helpers
internal/jobqueue/       Generic outbox-pattern worker (Postgres → NATS doorbell)
internal/config/         Environment-based configuration
db/migrations/           SQL schema migrations (goose)
db/queries/              SQL query definitions (sqlc source of truth)
web/                     SolidJS frontend (Vite + Tailwind)
tests/                   Integration tests (testcontainers)
charts/                  Helm charts (ocidex, ocidex-operator)
docs/                    Architecture docs, ADRs, development guide

API Overview

All endpoints are under /api/v1. The full OpenAPI spec is served at /openapi.json and an interactive docs UI at /docs.

Method Path Description
POST /api/v1/sbom Ingest a CycloneDX JSON SBOM
GET /api/v1/sbom List SBOMs (paginated, filterable)
GET /api/v1/sbom/{id} Get SBOM detail
GET /api/v1/sbom/{id}/components List components in an SBOM
GET /api/v1/sbom/{id}/dependencies Get dependency graph
GET /api/v1/artifacts List tracked artifacts
GET /api/v1/artifacts/{id} Get artifact detail
GET /api/v1/artifacts/{id}/sboms List SBOMs for an artifact
GET /api/v1/artifacts/{id}/changelog Get changelog between SBOMs
GET /api/v1/artifacts/{id}/license-summary License breakdown for latest SBOM
GET /api/v1/components Search components
GET /api/v1/components/distinct Deduplicated component search
GET /api/v1/licenses List all licenses
GET /api/v1/diff Diff any two SBOMs

Errors follow RFC 7807 problem details format.

Configuration

OCIDex is configured via environment variables:

See docs/CONFIGURATION.md for the full reference. Key variables:

Variable Default Description
DATABASE_URL — PostgreSQL connection string (required)
NATS_URL — NATS server URL (required for API + both workers)
PORT 8080 HTTP listen port (API server)
LOG_LEVEL info Log level (debug, info, warn, error)
ENVIRONMENT development Runtime environment
GITHUB_CLIENT_ID — GitHub OAuth app client ID (set with the secret, or leave both unset)
GITHUB_CLIENT_SECRET — GitHub OAuth app client secret
OIDC_ISSUER_URL — OIDC discovery base; enables the generic OIDC provider
SESSION_SECRET — Session signing key (always required; generate with openssl rand -hex 32)
FRONTEND_URL http://localhost:3000 Frontend origin (used for CORS and OAuth redirect)
NATS_STREAM_NAME ocidex JetStream stream name
SCANNER_MAX_CONCURRENCY 10 Max parallel scans per scanner-worker pod
ENRICHMENT_MAX_CONCURRENCY 10 Max parallel enrichments per enricher worker pod

Documentation

Document Description
Architecture System design, data model, and component overview
Development Guide Coding patterns, testing strategy, and stack examples
Configuration All environment variables with descriptions and defaults
Deployment Production deployment guide (K8s + Flux)
Releasing Release checklist, tag pipeline, verification, and rollback
Upgrading Upgrade paths, backups, rollback, and per-version upgrade steps
Ephemeral Jobs K8s Job / --once mode for scanner and enrichment workers
MCP Server Serving the catalog to agents over stdio: setup, tools, troubleshooting
API Versioning Versioning policy and breaking-change definition
Frontend Development Dev rigs, browser verification, contract tests
Tekton CI Fast pipeline iteration, gotchas, task script syntax
Architecture Decision Records 43 ADRs documenting every major technical choice
How AI Was Used Transparent account of AI's role in development

Releases

OCIDex follows semantic versioning. Compatibility guarantees are defined in ADR-052; upgrade steps are in docs/UPGRADING.md. See CHANGELOG.md for the per-version history (generated by git-cliff from conventional commits).

To cut a new release from main:

make release VERSION=v0.1.0
git push origin main v0.1.0

The Tekton tag pipeline then builds multi-arch (linux/amd64, linux/arm64) images for every component and pushes them to ghcr.io/pfenerty/ocidex-*, tagged with the semver version (plus latest for stable releases). It publishes the three Helm charts with their image digests pinned, and creates a GitHub Release whose body is the version's CHANGELOG section. Images carry the standard org.opencontainers.image.* annotations, and binaries embed their build version (ocidex --version). The full checklist, the verification steps and the rollback steps are in docs/RELEASING.md.

Supply chain security

Every published image (ghcr.io/pfenerty/ocidex-*) carries build provenance and an SBOM, and is signed by Tekton Chains (cosign + public Rekor). See docs/verifying-artifacts.md for copy-paste verification, and cosign.pub for the signing key:

cosign verify --key cosign.pub ghcr.io/pfenerty/ocidex-api@sha256:<digest>

To report a vulnerability, see SECURITY.md — please do not open a public issue.

AI Acknowledgment

This project was built with significant AI assistance (Claude). Architecture decisions, technology selection, and code review are human-driven; implementation, refactoring, and documentation are collaborative. See How AI Was Used for the full picture.

License

MIT

Every container image also carries the license texts of the third-party code it ships, at /licenses/THIRD_PARTY_NOTICES. The web UI serves its own at /third-party-licenses.txt.

Directories

Path Synopsis
api
v1alpha1
Package v1alpha1 contains API types for the ocidex.io/v1alpha1 API group.
Package v1alpha1 contains API types for the ocidex.io/v1alpha1 API group.
cmd
authmatrix command
Package main renders the authorization matrix to stdout.
Package main renders the authorization matrix to stdout.
git-worker command
k8s-agent command
Command k8s-agent reports the container images running in a Kubernetes cluster to OCIDex.
Command k8s-agent reports the container images running in a Kubernetes cluster to OCIDex.
mock-idp command
Command mock-idp runs a mock OpenID Connect issuer for local development.
Command mock-idp runs a mock OpenID Connect issuer for local development.
ocidex command
Package main is the entry point for the OCIDex server.
Package main is the entry point for the OCIDex server.
ocidex-cli command
Command ocidex-cli is a command-line client for the OCIDex API.
Command ocidex-cli is a command-line client for the OCIDex API.
ocidex-cli/output
Package output renders command results in the format selected by --output.
Package output renders command results in the format selected by --output.
ocidex-mcp command
Command ocidex-mcp exposes the OCIDex catalog to agents as a Model Context Protocol server over stdio.
Command ocidex-mcp exposes the OCIDex catalog to agents as a Model Context Protocol server over stdio.
operator command
Package main is the entry point for the OCIDex K8s operator.
Package main is the entry point for the OCIDex K8s operator.
scanner-worker command
Package main is the entry point for the OCIDex scanner worker.
Package main is the entry point for the OCIDex scanner worker.
specgen command
Package main exports the OpenAPI spec generated by huma to stdout.
Package main exports the OpenAPI spec generated by huma to stdout.
specto30 command
Package main converts the OpenAPI 3.1 spec to 3.0 for oapi-codegen, which does not support 3.1 yet.
Package main converts the OpenAPI 3.1 spec to 3.0 for oapi-codegen, which does not support 3.1 yet.
vuln-parity command
Command vuln-parity compares grype's matches for stored SBOMs against the OSV-derived package_vulnerability mappings (ADR-049).
Command vuln-parity compares grype's matches for stored SBOMs against the OSV-derived package_vulnerability mappings (ADR-049).
vuln-worker command
Command vuln-worker maintains the package-keyed vulnerability store by matching stored SBOMs against the grype vulnerability database (ADR-049).
Command vuln-worker maintains the package-keyed vulnerability store by matching stored SBOMs against the grype vulnerability database (ADR-049).
Package db provides embedded database migration files.
Package db provides embedded database migration files.
internal
api
Package api's request and response types are split by domain, one file per handler file: types_sbom.go beside sbom.go, types_registry.go beside registry.go, and so on.
Package api's request and response types are split by domain, one file per handler file: types_sbom.go beside sbom.go, types_registry.go beside registry.go, and so on.
audit
Package audit implements an extension that emits structured audit log lines for every event published on the event bus.
Package audit implements an extension that emits structured audit log lines for every event published on the event bus.
auth
Package auth holds the identity providers OCIDex can authenticate against.
Package auth holds the identity providers OCIDex can authenticate against.
authz
Package authz holds the capability model: what a namespace role may do.
Package authz holds the capability model: what a namespace role may do.
cliconfig
Package cliconfig holds the server URL and credential handling shared by the user-facing client binaries — ocidex-cli and ocidex-mcp.
Package cliconfig holds the server URL and credential handling shared by the user-facing client binaries — ocidex-cli and ocidex-mcp.
config
Package config handles application configuration loaded from environment variables.
Package config handles application configuration loaded from environment variables.
controller
Package controller implements controller-runtime reconcilers for OCIDex CRDs.
Package controller implements controller-runtime reconcilers for OCIDex CRDs.
dbaudit
Package dbaudit inspects the live database for state that migrations or the application cannot repair themselves — principally object ownership.
Package dbaudit inspects the live database for state that migrations or the application cannot repair themselves — principally object ownership.
devidp
Package devidp is a mock OpenID Connect issuer for local development and tests.
Package devidp is a mock OpenID Connect issuer for local development and tests.
enrichment
Package enrichment defines the enrichment pipeline for post-ingestion data enrichment.
Package enrichment defines the enrichment pipeline for post-ingestion data enrichment.
enrichment/git
Package git implements the git source enricher.
Package git implements the git source enricher.
enrichment/names
Package names holds the string values written to the enrichments table.
Package names holds the string values written to the enrichments table.
enrichment/oci
Package oci implements the OCI registry metadata enricher.
Package oci implements the OCI registry metadata enricher.
enrichment/ocivalidate
Package ocivalidate provides a lightweight OCI manifest-type validator.
Package ocivalidate provides a lightweight OCI manifest-type validator.
enrichment/provenance
Package provenance implements signature and attestation discovery for container images.
Package provenance implements signature and attestation discovery for container images.
enrichment/subject
Package subject defines the identity type enrichers use to locate the artifact being enriched.
Package subject defines the identity type enrichers use to locate the artifact being enriched.
enrichment/user
Package user provides the user enricher, which stores caller-supplied metadata (architecture, build date, subject version) as an enrichment record immediately after SBOM ingestion.
Package user provides the user enricher, which stores caller-supplied metadata (architecture, build date, subject version) as an enrichment record immediately after SBOM ingestion.
event
Package event defines the in-process event bus for OCIDex.
Package event defines the in-process event bus for OCIDex.
extension
Package extension provides the lifecycle interface for OCIDex extensions.
Package extension provides the lifecycle interface for OCIDex extensions.
gosymbols
Package gosymbols defines how the function symbols linked into a Go binary travel inside a CycloneDX document and how their names are normalized (ADR-050).
Package gosymbols defines how the function symbols linked into a Go binary travel inside a CycloneDX document and how their names are normalized (ADR-050).
health
Package health provides a tiny HTTP health server for the worker binaries.
Package health provides a tiny HTTP health server for the worker binaries.
jobqueue
Package jobqueue implements the outbox-pattern job worker loop shared by scanner-worker and the per-enricher workers.
Package jobqueue implements the outbox-pattern job worker loop shared by scanner-worker and the per-enricher workers.
mainmodule
Package mainmodule identifies an SBOM's main module — the package built from the image's own source repository — and recovers its version when the scanner could not.
Package mainmodule identifies an SBOM's main module — the package built from the image's own source repository — and recovers its version when the scanner could not.
nats
Package nats provides a JetStream client for optional outbound event forwarding.
Package nats provides a JetStream client for optional outbound event forwarding.
netguard
Package netguard decides which addresses OCIDex may open outbound connections to on behalf of a user.
Package netguard decides which addresses OCIDex may open outbound connections to on behalf of a user.
repository
Package repository provides the data access layer for OCIDex.
Package repository provides the data access layer for OCIDex.
scanner
Package scanner defines the scan request type, the Scanner interface, and the lightweight OCI catalog/walker/submitter machinery used by the API.
Package scanner defines the scan request type, the Scanner interface, and the lightweight OCI catalog/walker/submitter machinery used by the API.
scanner/engine
Package engine houses the scan + ingest dispatcher used by the scanner-worker.
Package engine houses the scan + ingest dispatcher used by the scanner-worker.
secretbox
Package secretbox encrypts credentials stored in the database (ADR-051).
Package secretbox encrypts credentials stored in the database (ADR-051).
service
Package service contains business logic interfaces and implementations.
Package service contains business logic interfaces and implementations.
trust
Package trust defines the per-host signature verification configuration shared by internal/service (which resolves it from stored registry settings) and internal/enrichment/provenance (which consumes it to verify signatures).
Package trust defines the per-host signature verification configuration shared by internal/service (which resolves it from stored registry settings) and internal/enrichment/provenance (which consumes it to verify signatures).
version
Package version exposes build-time metadata, injected via -ldflags where the build controls the link step and recovered from the Go module's own build information where it does not.
Package version exposes build-time metadata, injected via -ldflags where the build controls the link step and recovered from the Go module's own build information where it does not.
vuln
Package vuln holds the domain types and Postgres store of the package-keyed vulnerability store.
Package vuln holds the domain types and Postgres store of the package-keyed vulnerability store.
vuln/grypematch
Package grypematch matches SBOM documents against the grype vulnerability database (ADR-049).
Package grypematch matches SBOM documents against the grype vulnerability database (ADR-049).
worker/enrichment
Package enrichmentworker provides the shared daemon scaffolding used by all per-enricher worker binaries.
Package enrichmentworker provides the shared daemon scaffolding used by all per-enricher worker binaries.
pkg
client module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL