SbomService
Verified against commit
942a18727c(2026-09-26). Re-verify with:grep -rnE 'Map(Get|Post|Put|Delete|Group)\(' src/SbomService/StellaOps.SbomService --include=*.cs && ls src/SbomService/__Libraries/StellaOps.SbomService.Persistence/Migrations/*.sql && grep -n -A3 '^ sbomservice:' devops/release/bundle/docker-compose.ymlThe estate-wide service, database, compose and bundle wiring is generated in the service inventory; this dossier describes the module and defers to that inventory for the service list.
The canonical SBOM repository for Stella Ops: storage, versioning, lineage, and the artifact association graph.
Status: Implemented and shipped in the release bundle (compose service sbomservice). Source: src/SbomService/ Domain: SBOM collection is classified under the Scanner fact-collection domain; the implementation stays in the top-level src/SbomService/ root (see src/SbomService/AGENTS.md).
Purpose
SbomService is the system of record for Software Bills of Materials. It stores uploaded and scanner-produced SBOMs in a tenant-scoped, append-only ledger and serves temporal (point-in-time and range) ledger queries, version diffs, dependency-path queries, raw-document export, and artifact lineage graphs.
The service also owns the artifact association graph for source snapshots, build runs, OCI image digests, SBOM documents, scan jobs, detector reports, findings, and evidence bundles. See artifact-links-api.md.
Supported JSON upload formats (validated in
SbomUploadServicethroughSbomFormatSupport): CycloneDX 1.4, 1.5, 1.6, 1.7 and SPDX 2.3 and 3.0. Other versions are rejected with a validation error. Detection keys offbomFormat(CycloneDX) andspdxVersion(SPDX).
Components
Deployable:
StellaOps.SbomService- the host (ASP.NET Core minimal APIs). It registers with the Stella Router as microservicesbomservice; the Router gateway reaches it by the endpoints it publishes. There are no MVC controllers in the host.
Libraries:
StellaOps.SbomService.Contracts- BCL-only producer contract for thesbom.uploaded/sbom.version.retiredv1 payloads, the version-stream routes, and the bounded live-version snapshot. It is the only SbomService source project another service (Findings) may reference.StellaOps.SbomService.Persistence- PostgreSQL persistence (SbomServiceDataSource,SbomServiceConnectionResolver,SbomServiceSchemaTopology, repositories, embedded SQL migrations, startup auto-migration).StellaOps.SbomService.Lineage- source-only lineage library. No production project references it; see architecture.md.
Tests:
src/SbomService/StellaOps.SbomService.Tests- host, endpoint, and service tests.src/SbomService/__Tests/StellaOps.SbomService.Contracts.Tests- wire goldens and closed-graph proof.src/SbomService/__Tests/StellaOps.SbomService.Persistence.Tests- PostgreSQL persistence integration tests.src/SbomService/__Tests/StellaOps.SbomService.Lineage.Tests- tests for the source-only lineage library.
Deployment
- Release bundle: service
sbomserviceindevops/release/bundle/docker-compose.yml(network aliassbomservice.stella-ops.local, depends onpostgresandvalkey). - Local compose:
devops/compose/docker-compose.stella-services.yml(servicesbomservice); owner-database overlaydevops/compose/docker-compose.sbomservice.yml. - Local development ports:
https://localhost:10390,http://localhost:10391. Consumers locate the service throughSTELLAOPS_SBOMSERVICE_URL.
Authentication and authorization
SbomService validates Authority bearer tokens and Router-generated signed identity envelopes through the shared resource-server pipeline. Raw x-tenant-id/x-user-id headers cannot authenticate a request. Named policies are defined in Auth/SbomPolicies.cs and registered in Program.cs:
Sbom.Read/sbom:read- tenant-scoped versions, ledger, lineage, projection, catalog, component lookup, entrypoint, registry-source, and artifact-link reads.Sbom.Write/sbom:write- mutating endpoints (upload, entrypoints, registry sources, artifact-link status, replay verify).Sbom.Attest/sbom:attest- signed lineage evidence-pack export.Sbom.Internal/sbom:operate- installation-wide maintenance, tenant-scoped internal orchestrator control, and the version-stream owner API.Sbom.DoctorHealth/ops.health- the Doctor read path.
The authenticated stellaops:tenant claim is the sole tenant authority. Body/query tenant fields are assertions only: omitted uses the authenticated tenant, equal is accepted, and mismatch is rejected. The authenticated subject also overrides caller-supplied actor fields.
API surface
All routes are minimal-API endpoints mapped in Program.cs, Endpoints/SbomVersionStreamEndpoints.cs, and Services/RegistrySourceEndpointExtensions.cs. Health, readiness, OpenAPI, and build-info routes are anonymous. The generated api-reference.md is produced from a live OpenAPI capture and can lag the source; see architecture.md for the full contract.
Health and metadata:
GET /healthz,GET /readyz,GET /openapi/*, build-info (MapBuildInfoEndpoint).GET /doctor/sbomservice/checks- doctor-check/v1 surface (ops.health); mapped only when the owner database is configured.
SBOM upload, retrieval, and ledger:
POST /sbom/uploadandPOST /api/v1/sbom/upload- upload an SBOM (Write).GET /api/v1/sbom/uploads?artifact=...andGET /api/v1/sbom/uploads/{artifactRef}- ledger history of uploads (Read).GET /api/v1/sbom/subject/{subjectRef}/document- raw uploaded document with its stored media type;GET /api/v1/sbom/subject/{subjectRef}/cyclonedx- raw CycloneDX document (Read). See audit-bundle-sbom-endpoint.md.GET /api/v1/sbom/production-answer- bounded latest-SBOM-per-artifact answer with the accepted format matrix (Read).GET /sbom/versionsandGET /api/v1/sbom/versions- version timeline for an artifact (Read).GET /sbom/ledger/history|/point|/range|/diff|/lineage, plusGET /api/v1/sbom/ledger/diff(Read).GET /api/v1/scan/results- proxy to Scanner’s artifact vulnerability report for audit bundles (Read).
Version stream (mapped only with durable PostgreSQL and SbomService:VersionStream:Enabled=true; absent by default):
GET /api/v1/sbom/version-stream/events,GET /api/v1/sbom/version-stream/snapshot,POST|GET|DELETE /api/v1/sbom/version-stream/consumers[/{consumerId}](Operate). See version-stream.md.
SBOM queries:
GET /api/v1/sbom/catalog(same handler asGET /console/sboms) - the authenticated tenant’s SBOM catalog (Read). Through the gateway only/api/v1/sbom/catalogreaches this service, because the gateway’s static/consoleroute targets Authority.stella sbom listcalls/api/v1/sbom/catalog.GET /components/lookup- tenant-scoped component neighbor lookup (Read).GET /sbom/contextandGET /sbom/paths- tenant timeline and dependency paths (Read;501if no dependency-path backend).GET /sboms/{snapshotId}/projection- stored Link-Not-Merge projection (Read). See api/projection-read.md.GET /entrypoints/POST /entrypoints- service entrypoints (Read/Write).
Artifact links:
POST /api/v1/artifact-links,POST /api/v1/artifact-links/import(Write).GET /api/v1/artifact-links/resolve,/unlinked,/candidates(Read).POST /api/v1/artifact-links/{linkId:guid}/confirm|/reject|/verify(Write).
Registry sources (route group /api/v1/registry-sources):
- CRUD:
GET(list),POST,GET|PUT|DELETE /{id}(Read/Write). POST /test,POST /{id}/test,POST /{id}/trigger,POST /{id}/pause,POST /{id}/resume(Write).GET /{id}/runs- run history with trigger type, counts, scan job ids, and matched images.GET /{id}/discover/repositories,/discover/tags/{repository},/discover/images- discovery previews filtered by enabled mask records;POST /{id}/discover-and-scansubmits Scanner jobs.GET /{id}/imagesand/{id}/images/sbom- matched image rows and SBOM status.- Enabled path/tag mask records require a registry write credential reference (
authRefUri/credentialRef). Mask records do not create independent schedules; the schedule belongs to the source, and a source with no enabled mask is skipped by the nightly refresh.
Lineage graph and compare:
GET /api/v1/lineage/{artifactDigest},/{artifactDigest}/children,/{artifactDigest}/parents(Read).GET /api/v1/lineage/diff,/api/v1/lineage/hover,/api/v1/lineage/compare(Read). VEX deltas in these responses are currently always empty; see architecture.md.POST /api/v1/lineage/diff/export(Attest;413over 50 MB,501if storage or signer is not configured).POST /api/v1/lineage/verify(Write),POST /api/v1/lineage/compare-drift(Read).POST /api/change-traces/build,GET /api/change-traces/{traceId}- change-trace shim (Read).GET /api/compare/baselines/{scanDigest}- baseline recommendation stub (Read).
Internal/operational (Sbom.Internal / sbom:operate):
GET /internal/sbom/events,/asset-events,/inventory,/resolver-feed,/resolver-feed/export(NDJSON),/ledger/audit,/analysis/jobs.POST /internal/sbom/events/backfill,/inventory/backfill,/resolver-feed/backfill,/retention/prune.GET|POST /internal/orchestrator/sources,/control,/watermarks.
Configuration
Configuration is bound from appsettings.json plus environment variables prefixed SBOM_ (and the unprefixed host environment). Most keys live under the SbomService root.
STELLAOPS_POSTGRES_SBOMSERVICE_CONNECTION- canonical owner-database variable (CoC §8.2 / ADR-039), read as a raw environment variable. The configuration keyPostgres:SbomService:ConnectionStringis the only other accepted source. A present-but-blank value of either throws. The database isstellaops_sbomservice; the schema inside it issbom. The former keySbomService:PostgreSQL:ConnectionStringis retired and ignored. Without a connection the host refuses to start unless an explicit local harness is enabled (SbomService:LocalHarness:Enabled=truein Development/Testing, or theDevelopmentLocalHarness/TestingLocalHarnessenvironment).SbomService:PostgreSQL(PostgresOptions) - still bound forSchemaName, command timeout, and pool sizes.SbomService:Ledger(SbomLedgerOptions) - retention:MaxVersionsPerArtifact(default 50),MaxAgeDays,MinVersionsToKeep(default 1). See retention-policy.md.SbomService:RegistrySourceRunRetention- hourly sweep of terminal registry-source runs ranked past the newest 500 of their source (Enableddefault true,RunsKeptPerSource,BatchSize,MaximumBatchesPerPass,Interval,MaximumRunRows). Queued and Running runs are never reclaimed. Retention classes of every table, and the retirement ofsbom.verdict_links, are in retention-policy.md with the 2026-09-23 verification receipt.SbomService:VersionStream:Enabled- defaultfalse. Until enabled it suppressessbom.versionsappends and fences, owner/pruner registration, and all stream, snapshot, and consumer routes. Activation requires explicitSbomService:VersionStream:RemoteConsumerLease,SbomService:VersionStream:Admission:*, andEventing:OutboxRetentionvalues; the procedure is in version-stream.md.Eventing:OutboxRetention- outbox window, cadence, and batch controls. The pruner runs in every host that embeds the eventing chain; until the stream is declared it measures and reclaims nothing.SbomService:HoverCache(UseDistributed,Ttl) andSbomService:CompareCache(UseDistributed) - lineage caches over the signed Router messaging cache factory.SbomService:LineageExport(StorageRootPath,AccessTtlDays) - content-addressed evidence-pack storage.SbomService:DependencyPaths(Enabled,MaxVersionsPerRun) - startup backfill of dependency graphs from raw sidecars.SbomService:RegistrySources- registry-source query bounds (DefaultPageSize,MaxPageSize,MaxRunHistoryLimit) and nightly refresh (NightlyRefreshEnabled,NightlyRefreshHourUtc,NightlyRefreshMinuteUtc,NightlyRefreshPollSeconds; default on at 02:00 UTC, 60-second poll).SbomService:RegistryHttp,SbomService:ScannerHttp- outbound HTTP timeouts andAllowedHosts.SbomService:ScannerUrl,SbomService:BatchScanSize,SbomService:BatchScanDelayMs- Scanner job submission and the Scanner report proxy.SbomService:Integrations- registry-credential resolution over the Integrations owner API (Enabled,BaseAddress,Scope,Tenant,TimeoutSeconds,FailClosed,Authority:*), withIntegrations:SecretProtectionKey.Doctor:Registration:*- opt-in registration with the Platform doctor registry (default off; cannot be enabled together withSbomService:Integrations:Authority:Enabled).- Local-harness fixture paths:
SbomService:ComponentLookupPath,SbomService:CatalogPath,SbomService:ProjectionsPath. SbomService:Concelier:*is retired and binds to nothing.- Router (
Routersection), Authority resource server, and audit emission (AuditEmission:TimelineBaseUrl).
Persistence
PostgreSQL database stellaops_sbomservice, schema sbom. Migrations are embedded SQL in src/SbomService/__Libraries/StellaOps.SbomService.Persistence/Migrations/ (excluding _archived/) and applied on startup through AddStartupMigrations(...); forward-only. The shared Eventing reliability migrations are applied in the same database. The ordered list and what each migration does are in architecture.md.
Doctor
Doctor/SbomServiceDoctorChecks.cs provides:
doctor.sbomservice.database.own-database-cutoverdoctor.sbomservice.schema.table-censusdoctor.sbomservice.schema.foreign-co-authoritydoctor.sbomservice.retention.registry-run-backlog
Observability
- Meter
StellaOps.SbomService(Observability/SbomMetrics.cs) and ActivitySourceStellaOps.SbomService(Observability/SbomTracing.cs); the instrument list is in architecture.md. - A Grafana dashboard ships at
src/SbomService/StellaOps.SbomService/Observability/sbomservice-grafana-dashboard.json.
Dependencies
- PostgreSQL (own database
stellaops_sbomservice). - Authority and Router - validated bearer or signed-envelope identity and canonical scopes.
- Scanner - job submission for registry sources and the artifact vulnerability report behind
/api/v1/scan/results. - Integrations - registry credential resolution.
- Timeline - audit emission target.
- Signed Router messaging cache factory (Valkey in the standard profile) - distributed hover and compare caches when
UseDistributedis set.
Consumers
- Console (Web) and the
stella sbom/stella artifact linkCLI commands. - Findings - consumes the
sbom.versionsowner stream and raw documents (HttpAdvisorySbomOwnerClient). - OfflineKit audit bundles -
ExportCenter:SbomAuditandExportCenter:VulnAuditpoint at this service. - AdvisoryAI - SBOM context through
/sbom/context.
Related documentation
- Architecture: architecture.md
- API reference (generated): api-reference.md
- Version publication stream: version-stream.md
- Retention: retention-policy.md
- Artifact links API: artifact-links-api.md
- Audit-bundle SBOM endpoints: audit-bundle-sbom-endpoint.md
- Ledger and lineage: ledger-lineage.md, lineage-ledger.md, lineage/architecture.md
- Registry sources: sources/architecture.md
- SBOM upload: byos-ingestion.md
- Determinism: DETERMINISM.md
- Scanner: …/scanner/
