Mirror Architecture
Scope. Where the mirror capability lives in
src/today: producing offline copies of Stella Ops content for sealed or bandwidth-limited estates, and applying them on the far side. Mirror is a capability, not a service. It has nosrc/Mirrorroot, no host, no database and no gateway route of its own.
0) Mission & boundaries
Mission. Let an air-gapped or disconnected estate stay current without direct access to upstream vulnerability feeds, by moving signed, digest-verified content across the gap.
Where the responsibilities live. Each part of the capability sits with the service that owns its data (/AGENTS.md rule 14):
| Responsibility | Owner | Live code |
|---|---|---|
| Holding the mirrored vulnerability and VEX data, importing seeds, publishing the corpus | Vulnerabilities hub | src/Vulnerabilities/ (section 4.2) |
| Building, validating, importing and delivering mirror seeds from an operator host | CLI | src/Cli/StellaOps.Cli/Commands/MirrorSeedCommandGroup.cs (section 4.1) |
| Producing mirror bundles from a mirror export profile | OfflineKit export plane | src/OfflineKit/__Libraries/StellaOps.ExportCenter.* (section 2) |
| Carrying a seed or bundle into a sealed estate and handing it to its owner | OfflineKit custody plane | src/OfflineKit/StellaOps.OfflineKit.WebService/Imports/ (section 4.3) |
Boundaries.
- The mirror capability redistributes content the hub already holds. It does not originate vulnerability data; online ingestion is the hub’s connector plane (connectors).
- The hub’s mirrored data is tenant-free. Seed commands take no seed-level tenant; the tenant only scopes the caller’s access token (mirror seeds).
- OfflineKit never activates domain content itself. A verified carrier part is handed to its owning service through that service’s API; OfflineKit never writes to a sibling database (OfflineKit dossier, section 1).
1) Retired predecessors and where their responsibilities went
The mirror capability used to be spread across Concelier and a standalone src/Mirror tree. Neither exists in src/ today.
| Predecessor | Status | Responsibility now held by |
|---|---|---|
Concelier service, including its federation bundle export/import library and its stella-mirror feed connector | Retired; the service stopped at the VULN-G1 cutover and its source is frozen under src/__Obsoleted/Concelier/ (Concelier) | The Vulnerabilities hub owns the data; the mirror seed (section 4) replaces the federation bundle as the offline exchange for vulnerability data |
Concelier-based seed archive and devops/mirror seed scripts | Retired with the VULN-B1 source cutover; scripts frozen under devops/mirror/_archived/vuln-b1/ | stella mirror seed and the hub’s seed import endpoint (section 4) |
src/Mirror/StellaOps.Mirror.Creator planning core | The tree moved to OfflineKit when OfflineKit absorbed Mirror; the planning semantics were re-authored as the mirror export profile kind (section 2) | OfflineKit export plane |
Two remnants were removed on 2026-09-26:
- The old planning interface, its models and
FailClosedMirrorCreatorService, which threw on every call, were withdrawn with their test project and the two shell scripts (make-thin-v1.sh,schedule-export-center-run.sh) tosrc/__Obsoleted/OfflineKit/__Libraries/StellaOps.Mirror.Creator/. Nothing outside the test project used them; the scripts readscripts/mirror/*.py, which does not exist, and posted to the retired/export-center/runsroute. - The CLI
feedsercommand group for federation bundles was removed on 2026-09-26. Its server routes (/api/v1/federation/*) were retired at the gateway and had no live server.
The stella mirror create command fails closed with exit code 9 and error mirror_create_not_implemented, and writes no files.
2) Mirror export profile (OfflineKit)
Mirror bundle production is a kind of export profile, not a second engine (design challenge DC-22). The OfflineKit dossier owns the run lifecycle; this section only places the mirror parts.
- Profile. An export profile with
ExportProfileKind.Mirror(value5) carries aMirrorProfileScopein itsscope_json:sources[]withsourceId,sourceUri,contentKinds[](advisories,vex,sbom,images,dashboards, serialised as strings) andenabled. Source:StellaOps.ExportCenter.Application/Mirror/MirrorProfileScope.cs. - Planning.
MirrorProfilePlanner.Planis pure and deterministic: source ids are normalised to trimmed lower case, enabled sources are ordered ordinally, and the plan id is a content hash, so the same profile and cursors give a byte-identical plan. A source with a cursor from its last successful run is plannedIncremental, otherwiseFull. Planning refuses a profile that is not a mirror profile, has no scope, repeats a source id or has no enabled source, rather than returning an empty plan. - Execution.
MirrorExportRunMaterializerruns onofflinekit-workerthrough the export-run executor (AddExportRunExecution). AsourceUrimust be an absolute path or afile://URI; any other scheme is refused, so a run never reaches the network from a sealed estate. It resumes fromexport_center.mirror_run_cursorsand writes the bundle throughMirrorBundleBuilder(StellaOps.ExportCenter.Core/MirrorBundle/). Every bundle is self-contained (variant Full), also when the source read was incremental; the per-source mode is recorded in the bundle metadata. Cursors advance only after the run succeeds and its artifacts are recorded. - Carrier. The run’s artifacts are packed into an OfflineKit carrier when a signing key is configured (OfflineKit dossier, carrier paragraph).
Bundle layout: mirror bundles. Profile options: export profiles.
3) Contracts and interfaces
| Surface | Contract | Source |
|---|---|---|
| CLI seed commands | stella mirror seed export, validate, import, download | src/Cli/StellaOps.Cli/Commands/MirrorSeedCommandGroup.cs |
| Seed format | manifest.json, advisories.jsonl, advisory-index.jsonl; digests, lengths, counts and the advisory state-index digest | mirror seeds |
| Seed import | POST /api/vulnerabilities/v1/mirror/seeds/import | src/Vulnerabilities/StellaOps.Vulnerabilities.WebService/Serving/MirrorSeedEndpoints.cs |
| Seed export input | The hub’s current corpus publication, /api/vulnerabilities/v1/corpus/publications/current | corpus artifact |
| Offline Kit seed part | Domain vulnerabilities, media type application/vnd.stellaops.mirror-seed+ndjson | StellaOps.Vulnerabilities.Contracts/Mirror/MirrorBundleStream.cs and StellaOps.Vulnerabilities.Contracts/OfflineKit/ |
| Mirror export profile | ExportProfileKind.Mirror, MirrorProfileScope | src/OfflineKit/__Libraries/StellaOps.ExportCenter.Application/Mirror/ |
The mirror capability declares no Authority scopes of its own; there are no mirror:* constants in StellaOpsScopes. Seed export and import use the advisory and VEX scopes named on the mirror seeds page. A mirror export run is started like any other profile run, under the OfflineKit ExportOperator policy (StellaOps.ExportCenter.Application/Api/ExportApiEndpoints.cs).
4) Mirror seed — the current offline distribution path
The operator reference is Vulnerability mirror seeds; it owns the command options, token scopes, tenant order, the seed format and the owner endpoint contract. This section only places the seed surface in the architecture. The Concelier-based seed archive this section described before (a
--profileoption, a Concelier persistence seed engine, a standalone seed tool and thedevops/mirrorseed scripts) was retired with the VULN-B1 source cutover; its scripts are frozen underdevops/mirror/_archived/vuln-b1/and the historical v1 seed catalogue underdevops/mirror/seeds/is not an input to the current importer.
4.1 CLI: the stella mirror seed group
src/Cli/StellaOps.Cli/Commands/MirrorSeedCommandGroup.cs defines the group under the top-level mirror command; src/Cli/StellaOps.Cli/Services/HubMirrorSeedClient.cs is its client.
export— builds a seed directory from the vulnerability hub’s current retained corpus publication over HTTP (--output-directory, optional--source,--ecosystem,--osv-upstream,--delta-baseline,--overwrite). No database connection. Every record names its upstreams (origins);--osv-upstreamapplies the per-record OSV upstream rule shared with the importer inStellaOps.Vulnerabilities.Contracts/Mirror/MirrorSeedOrigins.cs.validate— checks a seed directory’s format, digests, length and advisory count locally (--seed-directory); no network, no database.import— validates the seed and replays it through the owner API (--seed-directory,--validate-only,--replace-existing,--delta-apply).download— copies a verified seed to a delivery directory (--source-directory,--destination-directory,--overwrite).
4.2 Owner: the Vulnerabilities service
The vulnerability hub owns the mirrored data. src/Vulnerabilities/StellaOps.Vulnerabilities.WebService/Serving/MirrorSeedEndpoints.cs maps POST /api/vulnerabilities/v1/mirror/seeds/import (advisory and VEX ingest policies); src/Vulnerabilities/__Libraries/StellaOps.Vulnerabilities.Ingestion/Mirror/ validates and applies a seed through the ordinary ingestion paths; and src/Vulnerabilities/StellaOps.Vulnerabilities.Worker/MirrorSeedPublicationWorker.cs publishes the corpus after a local import, also when online ingestion is disabled or the estate is sealed. Export reads the published corpus at /api/vulnerabilities/v1/corpus/publications/current.
4.3 Offline Kit carrier
An Offline Kit carrier can hold a mirror seed part. The Offline Kit service activates it against the same owner API (src/OfflineKit/StellaOps.OfflineKit.WebService/Imports/VulnerabilityMirrorSeedActivator.cs), using the exchange contract in StellaOps.Vulnerabilities.Contracts/OfflineKit/.
4.4 Module-boundary note
The seed surface belongs to the Vulnerabilities module (data owner) with the CLI and the Offline Kit as clients. It has no code under a src/Mirror root; this section is its pointer from the mirror dossier.
Related documentation
- Vulnerability mirror seeds (operator reference):
../vulnerabilities/mirror-seed.md - Vulnerabilities hub:
../vulnerabilities/architecture.md - OfflineKit (export runs, carriers, part activation):
../offlinekit/architecture.md - Mirror bundle layout:
../export-center/mirror-bundles.md - AirGap posture:
../airgap/architecture.md - Concelier (retired 2026-09-26, archived):
docs-archive/modules/concelier/README.md - Provenance observers (draft):
./provenance/observers.md
