Mirror Architecture
VULN-B1 source cutover, 2026-09-11. The Concelier source and bootstrap tooling are frozen. Current seeding uses the Vulnerabilities mirror API and CLI; current federation uses the retained corpus and OfflineKit carrier. The predecessor mechanisms below are historical and must not be used for an installation.
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
