Replay
Verified against commit
942a18727c(2026-09-26, DOC-2 of SPRINT_20260926_001). Re-verify by reading the evidence paths listed in the Evidence section of architecture.md.
Service wiring (image, database and role, compose profile, bundle presence) is generated in the service inventory; this dossier does not restate it.
Deterministic replay engine for reproducing Stella Ops vulnerability verdicts.
Purpose
Replay lets auditors and operators reproduce a vulnerability verdict exactly. Given identical inputs (SBOM, policy, feeds, toolchain), Stella Ops MUST produce identical outputs — and Replay provides the infrastructure to capture, store, and verify these deterministic execution chains, so any past decision can be re-derived and proven byte-for-byte.
Quick Links
- Architecture - Technical design and implementation details
- API Reference - Endpoint summary
- OpenAPI Spec - Machine-readable API definition
- Guides - Replay verification guides
- Schemas - Replay manifest and proof schemas
- Replay Proof Schema - Detailed proof format
Status
| Attribute | Value |
|---|---|
| Service | StellaOps.Replay.WebService; compose/bundle service replay-web (Router consumer group replay) |
| Core libraries | StellaOps.Replay.Core, StellaOps.Replay.Anonymization |
| Dev URLs | https://localhost:10410, http://localhost:10411 (alias replay.stella-ops.local, env STELLAOPS_REPLAY_URL) |
Key Features
- Replay Tokens: SHA-256 replay tokens cryptographically bound to input digests (feed manifests, rules/lattice policy versions and hashes, input/evidence hashes, scoring config) and to the caller’s tenant
- Verdict Replay: Execute a captured audit bundle in an isolated, offline context and compare the replayed verdict/decision against the original, reporting input drift and divergence
- Point-in-Time Advisory Queries: Resolve an advisory’s state at a given timestamp, across providers, with timeline and diff views
- Feed Snapshots: Immutable, content-addressed (digest-keyed) point-in-time snapshots of vulnerability feeds, with integrity verification and bundling
- Determinism Verification: Canonical-JSON verdict digesting with a determinism score and difference report
API Surface
Business routes are versioned under /v1. The service authenticates via the StellaOps resource-server bearer scheme (and the Router identity envelope). Read and deterministic verification endpoints use the replay.token.read policy, which requires replay:read; explicit token, bundle, and snapshot production uses replay.token.write, which requires replay:write. Endpoint policies own this split, so the resource server has no global required scope that would be ANDed with both policies.
Replay tokens
POST /v1/replay/tokens- Generate a replay token (write)POST /v1/replay/tokens/verify- Verify a replay token (read)GET /v1/replay/tokens/{tokenCanonical}- Parse token details (read)
Verdict replay
POST /v1/replay/verdict- Execute a verdict replay from an audit bundle (read)POST /v1/replay/verdict/verify- Check replay eligibility (read)POST /v1/replay/verdict/compare- Compare two replay executions (read)POST /v1/replay/verdict/bundle- Capture the current Policy.Engine decision and seal a replay-readable AuditPack bundle (write)POST /v1/replay/verdict/by-subject- Console adapter: verify the subject against Release Orchestrator’s recorded gate decisions, then produce and replay a bundle in-process (read)GET /v1/replay/verdict/{manifestId}/status- Replay status (read) — currently returns501 Not Implemented(no durable replay-execution history is configured)
Point-in-time advisory & feed snapshots
GET /v1/pit/advisory/{cveId}- Advisory state at a point in time (read)POST /v1/pit/advisory/cross-provider- Advisory across multiple providers (read)GET /v1/pit/advisory/{cveId}/timeline- Advisory timeline (read)POST /v1/pit/advisory/diff- Compare advisory between two timestamps (read)POST /v1/pit/snapshots- Capture a feed snapshot (write, audited)GET /v1/pit/snapshots/{digest}- Get a snapshot by digest (write)GET /v1/pit/snapshots/{digest}/verify- Verify snapshot integrity (write)POST /v1/pit/snapshots/bundle- Create a snapshot bundle (write)
Operational
GET /healthz- Health checkGET /.well-known/openapi- Inline OpenAPI 3.1 document (tokens API subset)GET /buildinfo.json,GET /api/v1/buildinfo- Image provenance (anonymous)GET /doctor/replay/checks- doctor-check/v1 results; requiresops.health; mapped only when a PostgreSQL connection is configured
Persistence & Configuration
- Database: own database
stellaops_replay, connection fromSTELLAOPS_POSTGRES_REPLAY_CONNECTION(configuration keyPostgres:Replay:ConnectionString); noConnectionStrings:Defaultfallback. Resolution lives inStellaOps.Replay.Persistence(ReplayConnectionResolver). - Schema: PostgreSQL schema
replay; tablereplay.feed_snapshot_indexkeyed on(provider_id, captured_at, digest), append-only, retention classsource-of-truth. Migrations embedded inStellaOps.Replay.Persistence(001_initial_schema.sql,002_replay_retention_classes.sql) auto-apply on startup viaAddStartupMigrations. - Storage driver (
Replay:Storage:Driver, defaultpostgres):postgresfor live runtime;inmemoryis permitted only in theTestingenvironment. - Blob store (
Replay:Storage:ObjectStore:Driver, defaultseed-fs):seed-fs(filesystem, default rootdata/replay/snapshots). Therustfsdriver is explicitly unsupported in the current runtime contract. - Config: section
Replay, environment-variable prefixREPLAY_, optional../etc/replay.yaml. Authority binding underReplay:Authority(issuer, metadata address, audiences). Outbound lanesReplay:PolicyEngine(verdict re-computation) andReplay:SubjectVerification(Release Orchestrator lookup) are off by default in code and enabled in the release bundle.
Dependencies
Replay deliberately avoids direct project references on upstream domain libraries (and their transitive Postgres/Redis/DSSE graphs). Instead it defines digest-addressed upstream ports in StellaOps.Replay.Core/Providers/UpstreamPorts.cs that production wiring adapts to the real modules.
Upstream (this module reads from, via ports)
- Concelier - Digest-addressed feed snapshot reads (
IConcelierFeedSnapshotReader); production wiring binds this to the Replay-internalFeedSnapshotService - Excititor / VexLens - Digest-addressed raw VEX document reads (
IExcititorVexRawReader) - Policy - Digest-addressed policy bundle reads (
IPolicyBundleReader/IPolicyBundleVerifier). Note: as of SPRINT_20260502_014 this port is BLOCKED / not production-wired because Policy does not yet expose a public digest-addressed bundle reader.
Outbound calls
- Policy Engine -
Replay:PolicyEngine: re-computes a verdict from a sealed basis forPOST /v1/replay/verdictand the bundle producer. - Release Orchestrator -
Replay:SubjectVerification: recorded gate-decision lookup forby-subject(service-token scoperelease:read).
Downstream (modules that depend on this)
- Scanner - WebService, Worker and
StellaOps.Scanner.Corereference the closed contract libraryStellaOps.Replay.Contracts(manifest, canonical JSON, deterministic hash). - Web console - calls
POST /v1/replay/verdict/by-subject(src/Web/StellaOps.Web/src/app/core/api/replay-verdict.client.ts).
Notes
- Replay does not make vulnerability decisions; it captures inputs and outputs
- Feed snapshots are stored content-addressed by digest, not by mutable feed contents; the index records only
(provider_id, digest, captured_at, epoch_timestamp) - All timestamps are UTC
DateTimeOffsetvalues sourced from an injectedTimeProvider(neverDateTimeOffset.UtcNow) so two runs over identical input produce byte-identical records - Verdict-digest comparison uses canonical JSON + SHA-256; the
ReplayId/JobIdcorrelation handles are operational labels and are deliberately excluded from the content-addressed audit state (see the Determinism Analyzer notes insrc/Replay/AGENTS.md)
