Mirror Architecture
Vulnerability feed mirror and distribution service.
Scope. Architecture for Mirror: mirroring vulnerability feeds from upstream sources for offline distribution and reduced external dependencies.
0) Mission & boundaries
Mission. Provide local mirrors of vulnerability feeds (NVD, OSV, GHSA, etc.) for offline operation and reduced latency. Enable air-gapped deployments to receive updates via signed bundle import.
Boundaries.
- Mirror redistributes Concelier’s canonical advisory data; it does not originate vulnerability data.
- Bundle production lives in
StellaOps.Concelier.Federation(export) and thesrc/Mirror/StellaOps.Mirror.Creatorplanning core (see §3); bundle consumption lives in theStellaOps.Concelier.Connector.StellaOpsMirrorfeed connector. - Bundles are cryptographically verified (per-file
sha256:digests, optional detached JWS signature) before ingest.
1) Integration with Concelier
Mirror functionality is split across two Concelier libraries plus the standalone src/Mirror/ planning core (see §3):
src/Concelier/__Libraries/
├─ StellaOps.Concelier.Federation/ # Bundle export/import (produces & ingests bundles)
└─ StellaOps.Concelier.Connector.StellaOpsMirror/ # Feed connector that consumes a published mirror
1.1 Federation library (StellaOps.Concelier.Federation)
Produces and ingests offline federation bundles. Key components grounded in source:
Export/BundleExportService(IBundleExportService) andExport/DeltaQueryService(IDeltaQueryService) — build full/delta bundles.Import/BundleImportService(IBundleImportService),BundleReader,BundleVerifier(IBundleVerifier),BundleMergeService(IBundleMergeService) — import, verify, and merge bundles into the canonical store.Signing/IBundleSignerwith a defaultNullBundleSigner(signing is opt-in; seeBundleExportOptions.Sign, defaulttrue).Compression/ZstdCompression— bundle payloads are Zstandard-compressed (BundleExportOptions.CompressionLevel, default3).Publishers/IFederationBundlePublisherwithLocalDiskFederationBundlePublisherandS3FederationBundlePublisher.- DI via
BundleFederationServiceCollectionExtensions.
1.2 Mirror connector (StellaOps.Concelier.Connector.StellaOpsMirror)
StellaOpsMirrorConnector is an IFeedConnector (source name stella-mirror) that consumes a published StellaOps mirror — it does not generate bundles. It runs the standard Fetch -> Parse -> Map pipeline:
- Fetch downloads the mirror index (
MirrorIndexDocument), selects the configuredDomainId, downloads the domain manifest + bundle, verifies eachsha256:digest, optionally verifies a detached JWS signature, and stores the bundle for parsing. It short-circuits (INFO log, noerror_countincrement) when disabled or pointed at the default placeholder host. - Parse deserializes the
MirrorBundleDocumentand persists a DTO (schemastellaops.mirror.bundle.v1). - Map projects bundle advisories via
MirrorAdvisoryMapperinto the advisory store.
Configuration (StellaOpsMirrorConnectorOptions, bound under Concelier:Sources:StellaopsMirror):
| Key | Default | Notes |
|---|---|---|
Enabled | true | Master toggle; false makes Fetch a no-op. |
BaseAddress | https://mirror.stella-ops.org | Placeholder default; override via env STELLA_MIRROR_BASE_URL. |
IndexPath | /concelier/exports/index.json | Relative path to the mirror index. |
DomainId | primary | Preferred mirror domain when several are published. |
HttpTimeout | 30s | Per-request timeout. |
Signature.Enabled | false | Require a valid detached JWS when true. |
Signature.KeyId | "" | Expected JWS kid. |
Signature.Provider | null | Crypto provider hint. |
Signature.PublicKeyPath | null | Fallback PEM EC public key path. |
2) Bundle & index format
The shapes below are grounded in the actual records, not illustrative placeholders.
2.1 Mirror index / bundle descriptors
The connector consumes a mirror index laid out as MirrorIndexDocument -> MirrorIndexDomainEntry -> MirrorFileDescriptor (StellaOps.Concelier.Connector.StellaOpsMirror.Internal):
{
"schemaVersion": 1,
"generatedAt": "2025-01-15T10:30:00Z",
"targetRepository": "primary",
"domains": [
{
"domainId": "primary",
"displayName": "Primary mirror",
"advisoryCount": 1234,
"manifest": { "path": "...", "sizeBytes": 0, "digest": "sha256:...", "signature": null },
"bundle": {
"path": "...",
"sizeBytes": 0,
"digest": "sha256:...",
"signature": {
"path": "...",
"algorithm": "ES256",
"keyId": "...",
"provider": "...",
"signedAt": "2025-01-15T10:30:00Z"
}
},
"sources": [
{ "source": "nvd", "firstRecordedAt": null, "lastRecordedAt": null, "advisoryCount": 0 }
]
}
]
}
The bundle payload itself is a MirrorBundleDocument (schemaVersion, generatedAt, targetRepository, domainId, displayName, advisoryCount, advisories[], sources[]).
Signatures are detached JWS, not DSSE.
MirrorSignatureVerifiervalidates an unencoded-payload detached JWS (header..signature,b64=falserequired as acritparameter) over the bundle bytes, supportingES256/ES384/ES512. There is no DSSE envelope in this path.
2.2 Federation export manifest
The Federation export side emits a BundleManifest (feedser-bundle/1.0):
{
"version": "feedser-bundle/1.0",
"siteId": "...",
"exportCursor": "...",
"sinceCursor": null,
"exportedAt": "2025-01-15T10:30:00Z",
"counts": { "canonicals": 0, "edges": 0, "deletions": 0 },
"bundleHash": "sha256:...",
"signature": { "keyId": "...", "algorithm": "...", "issuer": "..." }
}
sinceCursor: null denotes a full export; a non-null value denotes a delta. counts.total is derived (canonicals + edges + deletions).
3) Mirror Creator Core (2026-02-08)
Sprint SPRINT_20260208_041_Mirror_mirror_creator adds a deterministic core library at:
src/Mirror/StellaOps.Mirror.Creator/StellaOps.Mirror.Creator.Core.csproj
Implemented Contracts
IMirrorCreatorServiceUpsertSourceAsync(MirrorSourceConfiguration source, CancellationToken cancellationToken = default)GetSourcesAsync(string tenantId, CancellationToken cancellationToken = default)CreateSyncPlanAsync(MirrorSyncRequest request, CancellationToken cancellationToken = default)RecordSyncResultAsync(MirrorSyncResult result, CancellationToken cancellationToken = default)
- Model types in
MirrorModels.cs:MirrorSourceConfiguration(TenantId,SourceId,SourceUri,TargetUri,ContentKinds,Enabled; exposes normalized lowercase-trimmedNormalizedTenantId/NormalizedSourceId)MirrorSyncRequest(TenantId, optionalRequestedAt)MirrorSyncPlan(PlanId,TenantId,CreatedAt,Items) andMirrorSyncPlanItem(SourceId,Mode,ContentKinds,Cursor,OutputPath)MirrorSyncResult(PlanId,TenantId,SourceId,Succeeded,NewCursor,CompletedAt)[Flags] MirrorContentKind—Advisories=1,Vex=2,Sbom=4,Images=8,Dashboards=16MirrorSyncMode—Full=0,Incremental=1
- Options in
MirrorCreatorOptionswith configurableOutputRoot. - DI registration in
MirrorServiceCollectionExtensions.AddMirrorCreator(...).- Runtime default: registers
FailClosedMirrorCreatorServiceso production hosts cannot accidentally run on transient cursor/source state. - Tests replace
IMirrorCreatorServiceexplicitly with test-local fixtures; production assemblies do not expose a volatile mirror creator registration.
- Runtime default: registers
Determinism Guarantees
- Tenant and source IDs are normalized to lowercase-trimmed values.
- Source ordering is stable (ordinal sort by source ID per tenant).
- Plan IDs are generated from canonical plan content using SHA-256.
- Output bundle path format is stable:
<outputRoot>/<tenant>/<source>/<yyyyMMddHHmmss>.bundle.json
- Sync mode behavior:
Fullwhen no prior cursor exists.Incrementalafter successful cursor recording viaRecordSyncResultAsync.
Test Evidence
- Test project:
src/Mirror/__Tests/StellaOps.Mirror.Creator.Core.Tests/ - Executed:
dotnet test src/Mirror/__Tests/StellaOps.Mirror.Creator.Core.Tests/StellaOps.Mirror.Creator.Core.Tests.csproj - Result on 2026-02-08: Passed
4/4tests. (Frozen point-in-time note — the count below reflects current source; re-run rather than trusting this date.) - Current source (
MirrorCreatorServiceTests.cs) carries 5[Fact]cases: deterministic full plan, incremental planning afterRecordSyncResultAsync, fail-closed registration surface, fail-closed throw-when-used, and unknown-plan rejection. ATesting/InMemoryMirrorCreatorServicefixture provides the deterministic in-memory implementation used by tests (SHA-256 plan IDs, ordinal source ordering).
Current Boundaries
- Runtime persistence is fail-closed until a durable Mirror Creator store is implemented.
- Test-only planning fixtures live under
src/Mirror/__Tests/**; runtime hosts must bind a durableIMirrorCreatorService. - The planning core has no dedicated HTTP endpoint. A top-level
stella mirrorCLI group exists, butmirror createdeliberately returns exit code9withmirror_create_not_implementedand writes no files until it is backed by an authoritative exporter. Operators usestella feedser bundle exportfor Concelier bundles orstella mirror seed exportfor database seed bundles. - Runtime mirror transport/execution remains the responsibility of future integration work.
4) Mirror seed archive — the working offline distribution path
The Mirror Creator core (§3) is a fail-closed planning stub with no runtime. The surface operators actually use to move the vulnerability corpus into an air-gapped install is the mirror seed archive, which is fully implemented. It lives across the CLI, a Concelier persistence engine, a standalone tool, and DevOps scripts — none of it under
src/Mirror. This section documents that surface (added 2026-07-12, CLO-7).
4.1 CLI: stella mirror seed { export | validate | import | download }
src/Cli/StellaOps.Cli/Commands/MirrorSeedCommandGroup.cs implements the group (wired under the top-level mirror group in CommandFactory). It operates on the local advisory / VEX / scanner projection database.
export— writes a seed archive. Options:--profile {full | compact | source-only}(defaultfull, parsed atParseProfile),--delta-baseline <manifest-or-bundle>(export only rows newer than the baseline watermarks),--allow-active-sources(export while source jobs run, recording checkpointed work in the manifest),--skip-vexhub-projection(disk-safe exports that omit VexHub projection tables), plus source/ecosystem scoping and a safe-destination guard.validate— verifies an archive (manifest + chunks) without importing rows.import— imports an archive into the local DB;--forcereplaces existing imported mirror rows,--validate-onlychecks without writing.download— fetches a published archive for offline transfer.
4.2 Engine: StellaOps.Concelier.Persistence seed services
src/Concelier/__Libraries/StellaOps.Concelier.Persistence/Postgres/MirrorSeed/ is the produce/import/validate implementation (schema vuln): IMirrorSeedArchiveService / PostgresMirrorSeedArchiveService, MirrorSeedManifestReader, MirrorSeedRebuildService, MirrorSeedParityReport (import parity check), MirrorSeedRemapReset, and MirrorSeedArchiveModels. An archive is a manifest.json (profile, watermarks, per-table row counts, checksums) plus compressed data chunks.
4.3 Tool and DevOps scripts
- Standalone tool:
src/Concelier/StellaOps.Concelier.MirrorSeedTool(its ownProgram.cs) for out-of-service seed operations. - Ops scripts:
devops/mirror/{export-concelier-seed.ps1, prepare-concelier-seed-import.ps1, test-concelier-seed-import-e2e.ps1, test-bdu-mirror-fallback-e2e.ps1}, with the archive layout underdevops/mirror/seeds/.
4.4 Module-boundary note
“Mirror” as a runtime lives mostly inside Concelier (Federation library + connector, §1) and Concelier.Persistence (the seed engine above); src/Mirror holds only the not-yet-wired planning core. The seed surface therefore has no single owning module dossier — this section is its architectural pointer.
Related documentation
- Concelier:
../concelier/architecture.md - AirGap:
../airgap/architecture.md - Provenance observers:
./provenance/observers.md
