Export Center Mirror Bundles
Mirror bundles package StellaOps evidence, policy overlays, and indexes for air-gapped or bandwidth-constrained environments. They are produced by the mirror:full and mirror:delta profiles described in Epic 10 (Export Center) and implemented across Sprints 35-37 (EXPORT-SVC-35-004, EXPORT-SVC-37-001, EXPORT-SVC-37-002). This guide details bundle layouts, delta mechanics, encryption workflow, import procedures, and operational best practices.
Status (verified against commit
942a18727c, 2026-09-26). Mirror production is a profile kind (ExportProfileKind.Mirror= 5, DC-22) executed byMirrorExportRunMaterializeronofflinekit-worker, which writesmirror-<runId>.tar.gzthroughsrc/OfflineKit/__Libraries/StellaOps.ExportCenter.Core/MirrorBundle/MirrorBundleBuilder.cs. §2 below is the layout that builder writes. The delta summary (§3) is paths-verified only. The design-era encryption workflow andoffline-kit/bin/mirrorimport tool were removed from this page: see §4 for what exists. When the worker has a carrier signing key, the run also writes an OfflineKit carrier thatstella airgap pull/stella airgap importmove to another estate.
1. Bundle overview
| Profile | Contents | Typical use cases | Distribution |
|---|---|---|---|
mirror:full | Complete snapshot of raw evidence, normalized records, indexes, policy snapshots, provenance, signatures. | Initial seeding of an air-gapped mirror, disaster recovery drills. | Download bundle, optional OCI artifact. |
mirror:delta | Changes since a specified base export: added/updated/removed advisories, VEX statements, SBOMs, indexes, manifests. | Incremental updates, bandwidth reduction, nightly refreshes. | Download bundle, optional OCI artifact. |
Raw source data and policy outputs live under separate data/ subdirectories.
2. Filesystem layout
Entries written by MirrorBundleBuilder, in order (paths relative to the archive root; there is no enclosing mirror/ directory):
manifest.yaml
export.json
provenance.json
checksums.txt
README.md
verify-mirror.sh # executable; validates checksums.txt
indexes/
advisories.index.json
vex.index.json
sbom.index.json
findings.index.json
attestations.index.json
referrers.index.json
data/
raw/... # raw source records; SBOMs under data/raw/sboms/[<subject>/]
normalized/... # normalized source records
policy/snapshot.json
policy/<evaluations>
consensus/<vex consensus>
findings/<findings>
attestations/<attestations>
referrers/<OCI referrer artifacts>
delta/removed/ # delta variant only
advisories.jsonl
vex.jsonl
sboms.jsonl
The archive is gzip-compressed PAX tar with a deterministic gzip header. manifest.yaml summarises profile metadata, selectors, counts, sizes and SHA-256 digests; export.json and provenance.json are the JSON manifests (signing: MirrorBundleSigning.cs). There is no signatures/ directory.
Example manifest.yaml:
profile: mirror:full
runId: run-20251029-01
tenant: acme
selectors:
products:
- registry.example.com/app:*
timeWindow:
from: 2025-10-01T00:00:00Z
to: 2025-10-29T00:00:00Z
counts:
advisories: 15234
vex: 3045
sboms: 872
policyEvaluations: 19876
artifacts:
- path: data/raw/advisories/a0.jsonl.zst
sha256: 9f4b...
bytes: 7340021
3. Delta mechanics
Delta bundles reference a previous full or delta run via baseExportId and baseManifestDigest. They contain:
delta/
changed/
data/raw/advisories/*.jsonl.zst
...
removed/
advisories.jsonl # list of advisory IDs removed
vex.jsonl
sboms.jsonl
manifest.diff.json # summary of counts, hashes, base export metadata
- Base lookup: The worker verifies that the base export is reachable (download path or OCI reference). If missing, the run fails with
ERR_EXPORT_BASE_MISSING. - Change detection: Uses deterministic hashing of normalized records to compute additions/updates. Indexes are regenerated only for affected subjects.
- Application order: Consumers apply deltas sequentially. A
resetBaseline=trueflag instructs them to drop cached state and apply the bundle as a full refresh. - Removals: the builder writes the
delta/removed/*.jsonllists;verify-export-kit.shenforces tombstones on kits it checks, but the service writes notombstonesfield at this commit. - Integrity headers: the design called for
Digest,X-Stella-SignatureandX-Stella-Immutabilityheaders derived from anio.stellaops.export.manifest-digestOCI annotation; the annotation and the immutability header have no producer at this commit (see determinism.md).
Example manifest.diff.json (delta):
{
"baseExportId": "run-20251025-01",
"baseManifestDigest": "sha256:aa11...",
"resetBaseline": false,
"added": {
"advisories": 43,
"vex": 12,
"sboms": 5
},
"changed": {
"advisories": 18,
"vex": 7
},
"removed": {
"advisories": 2,
"vex": 0,
"sboms": 0
}
}
4. Moving a mirror bundle
- Download: list and fetch the run’s artifacts through
GET /api/offlinekit/v1/exports/runs/{runId}/artifactsandGET …/artifacts/{artifactId}/download(scopeexport.viewer). - Verify: run the bundled
verify-mirror.shagainst the archive, which checkschecksums.txt. - Carrier path: when
Export:Carrier:SigningKeyIdis configured onofflinekit-worker, the run also writes an OfflineKit carrier; move it withstella airgap pull --run <runId>andstella airgap import(see../airgap/guides/importer.md). - Resume: incremental mirror runs resume from
export_center.mirror_run_cursors, written only after a run succeeds.
Encryption: MirrorBundleBuilder records an encryption block (mode, strict, recipients) in manifest.yaml when a request asks for it, and the envelope library exists (StellaOps.ExportCenter.Core/Encryption/, …/Crypto/Encryption/, pattern in operations/kms-envelope-pattern.md). At this commit MirrorExportRunMaterializer requests no encryption and no production host registers an age or KMS key wrapper, so mirror runs are written unencrypted. There is no offline-kit/bin/mirror import tool.
5. Troubleshooting
| Symptom | Meaning | Action |
|---|---|---|
| Run fails before writing a bundle with a refused source | a sourceUri that is neither an absolute path nor a file:// URI | fix the profile scope (../offlinekit/architecture.md§4) |
| Run completes but writes no carrier | no carrier signing key id on the worker (EXPORT_RUN_CARRIER_NOT_WRITTEN) | set Export:Carrier:SigningKeyId |
verify-mirror.sh reports a checksum mismatch | files changed after extraction or transfer damage | re-download and re-verify; do not import |
6. References
- OfflineKit architecture §4 (export run engine)
- Export profiles
- Determinism
- Registry compatibility (OCI referrer discovery used for
data/referrers/)
