Stella Ops — Deterministic Replay Specification

Version: 1.0
Status: Draft / Internal Technical Reference
Audience: Core developers, module maintainers, and audit engineers.

This specification defines the on-disk manifest, execution rules, and verification flow for byte-for-byte replay. For the module surface (service, API, persistence) see the Replay module overview and architecture; for the platform-wide invariant, see the Determinism Specification.


1. Purpose

Deterministic Replay allows any completed Stella Ops scan to be reproduced byte-for-byte with full cryptographic validation.
It guarantees that SBOMs, Findings, and VEX evaluations can be re-executed later to:

Replay requires that all inputs and environmental conditions are captured, hashed, and sealed at scan time.


2. Architecture Overview

graph TD
A[Scanner.WebService] --> B[Replay Manifest]
A --> C[InputBundle]
A --> D[OutputBundle]
B --> E[DSSE Envelope]
C --> F[Concelier Snapshot Export]
C --> G[Policy/Lattice Bundle]
D --> H[DSSE Outputs (SBOM, Findings, VEX)]
E --> I[PostgreSQL: replay_runs]
C --> J[Blob Store: Input/Output Bundles]

Core Artifacts

ArtifactDescriptionFormat
Replay ManifestImmutable JSON describing all scan inputs and outputs.JSON (canonicalized)
InputBundleFeeds, rules, policies, tool binaries (hashed)..tar.zst
OutputBundleSBOM, Findings, VEX, logs..tar.zst
DSSE EnvelopeSigned metadata for each artifact.JSON / JWS
Merkle MapLayer and feed chunk trees.JSON (embedded or sidecar)

3. Replay Manifest Schema (v1)

3.1 Top-level Layout

{
  "schemaVersion": "1.0",
  "scan": {
    "id": "uuid",
    "time": "2025-10-29T13:05:33Z",
    "mode": "record",
    "scannerVersion": "10.1.3",
    "cryptoProfile": "FIPS-140-3+GOST-R-34.10-2012"
  },
  "subject": {
    "ociDigest": "sha256:abcd...",
    "layers": [
      { "layerDigest": "...", "merkleRoot": "...", "leafCount": 144 }
    ]
  },
  "inputs": {
    "feeds": [
      {
        "name": "nvd",
        "snapshotHash": "sha256:...",
        "snapshotTime": "2025-10-29T12:00:00Z",
        "merkleRoot": "..."
      }
    ],
    "rulesBundleHash": "sha256:...",
    "tools": [
      { "name": "sbomer", "version": "10.1.3", "sha256": "..." },
      { "name": "scanner", "version": "10.1.3", "sha256": "..." },
      { "name": "vexer", "version": "10.1.3", "sha256": "..." }
    ],
    "env": {
      "os": "linux",
      "arch": "x64",
      "locale": "en_US.UTF-8",
      "tz": "UTC",
      "seed": "H(scan.id||merkleRootAllLayers)",
      "flags": ["offline"]
    }
  },
  "policy": {
    "latticeHash": "sha256:...",
    "mutes": [
      { "id": "MUTE-1234", "reason": "vendor ack", "approvedBy": "authority@example.com", "approvedAt": "2025-10-29T12:55Z" }
    ],
    "trustProfile": "sha256:..."
  },
  "outputs": {
    "sbomHash": "sha256:...",
    "findingsHash": "sha256:...",
    "vexHash": "sha256:...",
    "logHash": "sha256:..."
  },
  "reachability": {
    "graphs": [
      {
        "kind": "static",
        "analyzer": "scanner/java@sha256:...",
        "casUri": "cas://replay/scan-123/reachability/static-graph.tar.zst",
        "sha256": "abc123"
      },
      {
        "kind": "framework",
        "analyzer": "scanner/framework@sha256:...",
        "casUri": "cas://replay/scan-123/reachability/framework-graph.tar.zst",
        "sha256": "def456"
      }
    ],
    "runtimeTraces": [
      {
        "source": "zastava",
        "casUri": "cas://replay/scan-123/reachability/runtime-trace.ndjson.zst",
        "sha256": "feedface",
        "recordedAt": "2025-11-07T11:10:00Z"
      }
    ]
  },
  "provenance": {
    "signer": "scanner.authority",
    "dsseEnvelopeHash": "sha256:...",
    "rekorEntry": "optional"
  }
}

3.2 Reachability Section

The optional reachability block captures the inputs needed to replay explainability decisions:

FieldDescription
reachability.graphs[]References to static/framework callgraph bundles. Each entry records the producing analyzer (analyzer/version), the CAS URI under cas://replay/<scan-id>/reachability/graphs/, and the SHA-256 digest of the tarball.
reachability.runtimeTraces[]References to runtime observation bundles (e.g., Zastava ND-JSON traces). Each item stores the emitting source, CAS URI (typically cas://replay/<scan-id>/reachability/traces/), SHA-256, and capture timestamp.

Replay engines MUST verify every referenced artifact hash before re-evaluating reachability. Missing graphs downgrade affected signals to reachability:unknown and should raise policy warnings.

Producer note: default clock values in StellaOps.Replay.Core are UnixEpoch to avoid hidden time drift; producers MUST set scan.time and reachability.runtimeTraces[].recordedAt explicitly.


4. Deterministic Execution Rules

4.1 Environment Normalization

4.2 Concurrency & I/O

4.3 Feeds & Policies

4.4 Library hooks (StellaOps.Replay.Core)

Use the shared helpers in src/__Libraries/StellaOps.Replay.Core to keep outputs deterministic:


5. DSSE and Signing

5.1 Envelope Structure

{
  "payloadType": "application/vnd.stellaops.replay+json",
  "payload": "<base64-encoded canonical JSON>",
  "signatures": [
    { "keyid": "authority-root-fips", "sig": "..." },
    { "keyid": "authority-root-gost", "sig": "..." }
  ]
}

5.2 Verification Steps

  1. Decode payload → verify canonical form.
  2. Verify each signature chain against RootPack (offline trust anchors).
  3. Recompute hash and compare to dsseEnvelopeHash in manifest.
  4. Optionally verify Rekor inclusion proof.

5.3 Default payload type

Replay DSSE envelopes emitted by DssePayloadBuilder use payload type application/vnd.stellaops.replay+json. Consumers should treat this as canonical unless a future manifest revision increments the schema and payload type together.


6. CLI Interface

6.1 Recording a Scan

stella scan image:tag --record ./out/

Produces:

out/
 ├─ manifest.json
 ├─ manifest.dsse.json
 ├─ inputbundle.tar.zst
 ├─ outputbundle.tar.zst
 └─ signatures/

6.2 Verifying

stella verify manifest.json

6.3 Replaying

stella replay manifest.json --strict
stella replay manifest.json --what-if --vary=feeds

6.4 Diffing

stella diff manifestA.json manifestB.json

Shows field-level differences (feed snapshot, tool, or policy hash).


7. PostgreSQL Schema

7.1 replay_runs

{
  "_id": "uuid",
  "manifestHash": "sha256:...",
  "status": "verified|failed|replayed",
  "createdAt": "...",
  "updatedAt": "...",
  "signatures": [{ "profile": "FIPS", "verified": true }],
  "outputs": {
    "sbom": "sha256:...",
    "findings": "sha256:..."
  }
}

7.2 bundles

{
  "_id": "sha256:...",
  "type": "input|output|rootpack",
  "size": 4123123,
  "location": "/var/lib/stella/bundles/<sha>.tar.zst"
}

7.3 subjects

{
  "ociDigest": "sha256:abcd...",
  "layers": [
    { "layerDigest": "...", "merkleRoot": "...", "leafCount": 120 }
  ]
}

8. Layer Merkle Implementation

8.1 Algorithm

static string ComputeMerkleRoot(string layerTarPath)
{
    const int ChunkSize = 4 * 1024 * 1024;
    var hashes = new List<byte[]>();
    using var fs = File.OpenRead(layerTarPath);
    var buffer = new byte[ChunkSize];
    int read;
    using var sha = SHA256.Create();
    while ((read = fs.Read(buffer, 0, buffer.Length)) > 0)
        hashes.Add(sha.ComputeHash(buffer, 0, read));
    while (hashes.Count > 1)
        hashes = hashes
            .Select((h, i) => (h, i))
            .GroupBy(x => x.i / 2)
            .Select(g => sha.ComputeHash(g.SelectMany(x => x.h).ToArray()))
            .ToList();
    return Convert.ToHexString(hashes.Single());
}

8.2 Stored Values

{
  "layerDigest": "sha256:...",
  "merkleRoot": "b81f...",
  "leafCount": 240,
  "leavesHash": "sha256:..."
}

9. Replay Engine Implementation Notes (.NET 10)

9.1 Manifest Parsing

Use System.Text.Json with deterministic ordering:

var options = new JsonSerializerOptions {
    WriteIndented = false,
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    TypeInfoResolverChain = { new OrderedResolver() }
};

9.2 Stable Output

Normalize SBOM/Findings/VEX JSON:

string Canonicalize(string json) =>
    JsonSerializer.Serialize(
        JsonSerializer.Deserialize<JsonDocument>(json),
        options);

9.3 Verification Flow

var manifest = Manifest.Load("manifest.json");
VerifySignatures(manifest);
VerifyHashes(manifest);
if (mode == Strict) RunPipeline(manifest);
else RunPipelineWithVariation(manifest, vary);

9.4 Failure Modes

ConditionAction
Missing snapshot or bundleError: InputBundleMissing
Feed hash mismatchError: FeedSnapshotDrift
Tool binary hash mismatchReject replay
Output hash drift in strict modeMark as failed, emit diff log
Invalid signatureReject manifest

10. Crypto Profiles and RootPack

10.1 Example Profiles

ProfileAlgorithmsNotes
FIPS-140-3ECDSA-P256 / SHA-256 / AES-GCMDefault for US/EU
GOSTGOST R 34.10-2012 / GOST R 34.11-2012Russia
SMSM2 / SM3 / SM4China
eIDASRSA-PSS / SHA-256EU qualified signatures

10.2 Dual-Signing Example

stella sign manifest.json --profiles=FIPS,GOST

Produces:

signatures/
 ├─ manifest.dsse.fips.json
 └─ manifest.dsse.gost.json

11. Test Strategy

TestDescriptionExpected Result
Golden ReplayRepeat identical scan → same outputs✅ identical hashes
Feed Drift TestReplay with updated feedsOnly inputs.feeds changes
Tool Upgrade TestReplay with new scanner versionReject or diff by tools
Policy Change TestDifferent lattice/mutesDiff by policy section
Cross-Arch Testx64 vs arm64Identical outputs
Corrupted BundleTamper bundleVerification fails

12. Example Verification Output

$ stella verify manifest.json

[✓] Manifest integrity: OK
[✓] DSSE signatures (FIPS,GOST): OK
[✓] Feeds snapshot hash: OK
[✓] Policy + mutes hash: OK
[✓] Toolchain hash: OK
[✓] SBOM/VEX outputs: OK

Result: VERIFIED

13. Future Extensions


14. Summary

Deterministic Replay freezes every element of a scan:

image → feeds → policy → toolchain → environment → outputs → signatures.

By enforcing canonical input/output states and verifiable cryptographic bindings, Stella Ops achieves regulatory-grade replayability, regional crypto compliance, and immutable provenance across all scans.


See also