11 KiB
Replay Manifest Guide
Sprint: SPRINT_20251228_001_BE_replay_manifest_ci (T6) Purpose: Complete reference for Replay Manifest export, verification, and CI integration.
Overview
The Replay Manifest is a self-contained JSON document that captures everything needed to reproduce a scan: inputs, toolchain versions, policies, and expected outputs. When verified, it provides cryptographic proof that a scan is deterministic and reproducible.
Quick Start
# Export replay manifest after scanning
stella replay export --scan-id <scan-uuid> --output replay.json
# Or export for a specific image
stella replay export --image myregistry/app:v1.0.0 --output replay.json
# Verify determinism (strict mode)
stella replay verify --manifest replay.json --strict-mode
# Verify with drift failure (for CI)
stella replay verify --manifest replay.json --fail-on-drift
Schema Reference
Schema Version
Current version: 1.0.0
Schema location: src/__Libraries/StellaOps.Replay.Core/Schemas/replay-export.schema.json
Top-Level Structure
{
"version": "1.0.0",
"snapshot": { ... },
"toolchain": { ... },
"inputs": { ... },
"outputs": { ... },
"verification": { ... }
}
snapshot Object
Identifies the scan snapshot this manifest represents.
| Field | Type | Description |
|---|---|---|
id |
string | Unique snapshot ID (snapshot:<sha256>) |
createdAt |
ISO 8601 | UTC timestamp when scan completed |
artifact |
object | Reference to scanned artifact (digest, repository, tag) |
Example:
{
"id": "snapshot:a1b2c3d4e5f6...",
"createdAt": "2025-12-28T14:30:00Z",
"artifact": {
"digest": "sha256:abc123...",
"repository": "myregistry/app",
"tag": "v1.0.0"
}
}
toolchain Object
Captures exact versions of all tools used during the scan.
| Field | Type | Description |
|---|---|---|
scannerVersion |
string | StellaOps Scanner version |
policyEngineVersion |
string | Policy Engine version |
platform |
string | Platform identifier (e.g., linux-x64) |
sbomerVersion |
string | SBOM generator version |
vexerVersion |
string | VEX processor version |
Example:
{
"scannerVersion": "0.42.0",
"policyEngineVersion": "0.42.0",
"platform": "linux-x64",
"sbomerVersion": "0.42.0",
"vexerVersion": "0.42.0"
}
inputs Object
All inputs consumed during the scan, with content hashes.
| Field | Type | Description |
|---|---|---|
sboms |
array | SBOM inputs (if layered) |
vex |
array | VEX documents used |
feeds |
array | Vulnerability feed snapshots |
policies |
object | Policy bundle reference |
Feed snapshot example:
{
"feeds": [
{
"name": "nvd",
"snapshotId": "nvd:2025-12-28T00:00:00Z",
"digest": "sha256:def456...",
"recordCount": 245678
}
]
}
outputs Object
Expected outputs from the scan, used for verification.
| Field | Type | Description |
|---|---|---|
verdictDigest |
string | SHA256 of verdict JSON |
decision |
enum | allow, deny, or review |
sbomDigest |
string | SHA256 of generated SBOM |
findingsDigest |
string | SHA256 of findings JSON |
verification Object
Helper commands and expected hashes for verification.
| Field | Type | Description |
|---|---|---|
command |
string | CLI command to reproduce scan |
expectedSbomHash |
string | Expected SBOM content hash |
expectedVerdictHash |
string | Expected verdict content hash |
CLI Commands
stella replay export
Export a replay manifest from a completed scan.
stella replay export [OPTIONS]
| Option | Required | Description |
|---|---|---|
--scan-id <uuid> |
One of | Scan ID to export |
--image <ref> |
One of | Image reference (uses latest scan) |
--output <path> |
No | Output path (default: replay.json) |
--include-feed-snapshots |
No | Include full feed snapshot refs |
--no-verification-script |
No | Skip verification command generation |
stella replay verify
Verify a replay manifest by re-executing the scan and comparing outputs.
stella replay verify [OPTIONS]
| Option | Required | Description |
|---|---|---|
--manifest <path> |
Yes | Path to replay manifest |
--strict-mode |
No | Require bit-for-bit identical outputs |
--fail-on-drift |
No | Exit code 1 on any drift |
--output-diff <path> |
No | Write diff report to file |
Exit Codes
| Code | Meaning |
|---|---|
0 |
Verification passed, outputs match |
1 |
Drift detected, outputs differ |
2 |
Verification error (missing inputs, invalid manifest, etc.) |
CI Integration
Gitea Actions
name: SBOM Replay Verification
on:
push:
branches: [main]
pull_request:
jobs:
verify-determinism:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t ${{ github.repository }}:${{ github.sha }} .
- name: Scan with replay export
run: |
stellaops scan \
--image ${{ github.repository }}:${{ github.sha }} \
--output-sbom sbom.json \
--output-replay replay.json
- name: Verify determinism
run: |
stellaops replay verify \
--manifest replay.json \
--fail-on-drift \
--strict-mode
- name: Upload replay manifest
uses: actions/upload-artifact@v4
with:
name: replay-manifest
path: replay.json
retention-days: 90
GitHub Actions
name: SBOM Replay Verification
on:
push:
branches: [main]
pull_request:
jobs:
verify-determinism:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up StellaOps
uses: stellaops/setup-stella@v1
with:
version: '0.42.0'
- name: Build and scan
run: |
docker build -t myapp:${{ github.sha }} .
stella scan --image myapp:${{ github.sha }} \
--output-sbom sbom.json \
--output-replay replay.json
- name: Verify replay
run: stella replay verify --manifest replay.json --fail-on-drift
- name: Upload attestations
uses: actions/upload-artifact@v4
with:
name: sbom-attestations
path: |
sbom.json
replay.json
GitLab CI
sbom-replay:
stage: security
image: stellaops/cli:latest
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- stella scan --image $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA --output-replay replay.json
- stella replay verify --manifest replay.json --fail-on-drift
artifacts:
paths:
- replay.json
expire_in: 90 days
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "main"
Troubleshooting Drift Detection
Common Drift Causes
| Cause | Symptom | Fix |
|---|---|---|
| Feed update | findingsDigest differs |
Pin feed snapshot version |
| Policy change | verdictDigest differs |
Version policy bundles |
| Tool upgrade | All digests differ | Lock toolchain versions |
| Non-deterministic SBOM | sbomDigest differs |
Enable deterministic mode |
| Timezone issues | Timestamps drift | Ensure UTC everywhere |
Debugging Steps
-
Export diff report:
stella replay verify --manifest replay.json --output-diff drift-report.json -
Compare inputs:
stella replay diff --manifest-a old.json --manifest-b new.json --show-inputs -
Check feed versions:
stella feeds list --show-snapshots -
Verify toolchain:
stella version --all
Feed Snapshot Pinning
For reproducible CI, pin feed snapshots:
# List available snapshots
stella feeds snapshots --feed nvd
# Pin specific snapshot
stella scan --image myapp:v1.0.0 \
--feed-snapshot nvd:2025-12-28T00:00:00Z \
--output-replay replay.json
Best Practices for Deterministic Builds
1. Lock All Dependencies
# In CI, always specify exact versions
stellaops/cli:0.42.0 # Not :latest
2. Pin Feed Snapshots
# Export current snapshot ID
stella feeds export-snapshot --output feeds-snapshot.json
# Use in subsequent scans
stella scan --feed-snapshot-file feeds-snapshot.json
3. Version Policy Bundles
# Store policies in version control
git add policies/
git commit -m "Policy bundle v2.3.0"
# Reference by commit in manifest
stella scan --policy-ref policies@abc123
4. Use Strict Mode in CI
# Always use strict mode in CI pipelines
stella replay verify --manifest replay.json --strict-mode --fail-on-drift
5. Archive Replay Manifests
Store replay manifests alongside release artifacts for audit trail:
# Archive with release
cp replay.json releases/v1.0.0/replay.json
API Reference
IReplayManifestExporter
public interface IReplayManifestExporter
{
/// <summary>
/// Exports a replay manifest for a completed scan.
/// </summary>
Task<ReplayExportResult> ExportAsync(
string scanId,
ReplayExportOptions options,
CancellationToken ct = default);
}
ReplayExportOptions
public sealed record ReplayExportOptions
{
/// <summary>Include exact toolchain versions.</summary>
public bool IncludeToolchainVersions { get; init; } = true;
/// <summary>Include feed snapshot references.</summary>
public bool IncludeFeedSnapshots { get; init; } = true;
/// <summary>Generate verification shell command.</summary>
public bool GenerateVerificationScript { get; init; } = true;
/// <summary>Output file path.</summary>
public string OutputPath { get; init; } = "replay.json";
}
ReplayExportResult
public sealed record ReplayExportResult
{
/// <summary>Path to exported manifest.</summary>
public required string ManifestPath { get; init; }
/// <summary>SHA256 digest of manifest content.</summary>
public required string ManifestDigest { get; init; }
/// <summary>Path to verification script (if generated).</summary>
public string? VerificationScriptPath { get; init; }
}
Related Documentation
- Deterministic Replay - Core concepts and architecture
- Developer Guide: Replay - Implementation details
- Replay Manifest v2 Acceptance - Schema evolution
- Test Strategy - Replay testing approach
Changelog
| Version | Date | Changes |
|---|---|---|
| 1.0.0 | 2025-12-28 | Initial schema and CLI commands |