Runtime Evidence Schema Reference
Overview
Runtime evidence is serialized as NDJSON (Newline-Delimited JSON), one event per line. NDJSON is chosen so chunks can be streamed, appended, and hashed incrementally without buffering a whole document, and so that a single corrupt line never invalidates the rest of a chunk. Output is canonicalized (see Determinism Invariants) so the same observed events produce byte-identical files across runs — the property that makes evidence chains reproducible and attestable.
This page is an altitude reference: it describes the record shape, the event taxonomy, and the invariants. It does not enumerate every field — exact field names, types, requiredness, and discriminator values live in the authoritative sources below and are validated against them. When this page and the schema disagree, the schema and the C# records win.
Authoritative sources
| What | Where |
|---|---|
| JSON Schema (field-by-field, the validation authority) | docs/schemas/runtime-evidence-v1.json |
| C# record definitions | src/Signals/__Libraries/StellaOps.Signals.Ebpf/Schema/ (RuntimeEvidence.cs, SyscallEvents.cs, RuntimeCallEvent.cs) |
| Canonical NDJSON writer (ordering, chunking) | src/Signals/__Libraries/StellaOps.Signals.Ebpf/Output/RuntimeEvidenceNdjsonWriter.cs |
| DSSE chunk predicate model | src/Signals/__Libraries/StellaOps.Signals.Ebpf/Signing/RuntimeEvidencePredicate.cs |
| Worked example | docs/modules/scanner/runtime-evidence.example.ndjson |
Schema version: runtime-evidence/v1.
Record shape
Every line is one RuntimeEvidenceRecord (Schema/RuntimeEvidence.cs): a common envelope plus a polymorphic event payload.
{ "ts_ns": <ns since boot>, "src": "<probe name>", "pid": <int>,
"cgroup_id": <int>, "comm": "<process name>",
"event": { "type": "<event type>", ... } }
- Envelope carries timing/identity that is common to all events: a monotonic
ts_ns(nanoseconds since boot, chosen for high-resolution ordering without wall-clock skew), the originating probe (src), process identity (pid,tid,comm,cgroup_id), and the enrichment fields (container_id,image_digest) added post-collection from the cgroup ID. eventis a discriminated union keyed bytype; the discriminator selects one of the event payloads below.
The exact required-vs-optional split and field types are in the JSON Schema and the RuntimeEvidenceRecord record — do not re-document them here.
Event taxonomy
Six event types exist. Each maps to a type discriminator value and an originating probe; the payload fields are defined in the JSON Schema $defs of the same name and the corresponding C# record.
type | Captures | Originating probe |
|---|---|---|
file_open | File open + derived access mode (read/write/read_write) | sys_enter_openat tracepoint |
process_exec | Executed binary, parent pid, argv[0] | sched_process_exec tracepoint |
tcp_state | TCP state transition, peer addr/port, family | inet_sock_set_state tracepoint |
net_connect | connect/accept to a remote addr/port + result | libc uprobes |
ssl_op | Plaintext-side SSL read/write byte counts + session ptr | OpenSSL uprobes |
function_call | Symbol/library/runtime + optional call stack + reachability node_hash | generic function uprobe |
function_call is the join point with static reachability: its node_hash is the canonical hash used to match a runtime-observed call against a graph node.
Note on names: the discriminator values are
file_open,net_connect, andfunction_call(notfile_access,network_op,symbol_call) — verify against the JSON Schema$defsbefore coding to them.
Representative record
A single representative line (a tcp_state event); see the JSON Schema examples and the worked NDJSON file for the others:
{"ts_ns":1234567890123456789,"src":"inet_sock_set_state","pid":1234,"cgroup_id":5678,"container_id":"containerd://abc123...","image_digest":"sha256:...","comm":"curl","event":{"type":"tcp_state","oldstate":"SYN_SENT","newstate":"ESTABLISHED","daddr":"93.184.216.34","dport":443,"family":"inet"}}
TCP state strings and address-family values (inet/inet6) are enumerated in the schema and produced by the TcpStateHelper/IpAddressHelper mappers in Schema/RuntimeEvidence.cs.
Determinism invariants
These are design contracts the writer guarantees so chunk hashes are stable; the mechanics live in Output/RuntimeEvidenceNdjsonWriter.cs.
- Key ordering — JSON keys are emitted in a fixed (alphabetical) order.
- No floating point — all numerics are integers; no float formatting variance.
- String encoding — UTF-8, NFC-normalized.
- Null omission — null/default optional fields are dropped, not written as
null. - Whitespace — compact (
WriteIndented = false), exactly one newline per record, no trailing whitespace.
Chunk metadata & attestation
Evidence is written in rotating chunks. Each chunk is sealed as a DSSE-signed in-toto statement with predicate type stella.ops/runtime-evidence@v1. The predicate links chunks into a hash chain and records collection provenance — shape:
{ "predicateType": "stella.ops/runtime-evidence@v1",
"predicate": { "chunk_id": "sha256:...", "chunk_sequence": <n>,
"previous_chunk_id": "sha256:...", "event_count": <n>,
"time_range": { "start": "...", "end": "..." },
"collector_version": "...", "kernel_version": "...",
"host_id": "...", "container_ids": [ ... ] } }
previous_chunk_id is what makes the sequence tamper-evident — each chunk commits to its predecessor. The full predicate field set is defined in Signing/RuntimeEvidencePredicate.cs; the statement/DSSE assembly and signing flow are in Signing/AttestorEvidenceChunkSigner.cs.
Validation
Validate evidence against docs/schemas/runtime-evidence-v1.json with any JSON Schema (draft 2020-12) validator. The schema is the validation authority; the C# records are kept in sync with it.
For evidence handling at the chunk/attestation level the CLI exposes stella evidence export and stella evidence verify (plus card, reindex, verify-continuity, migrate); see src/Cli/StellaOps.Cli/Commands/EvidenceCommandGroup.cs.
Migration from v0 schemas
Earlier per-language schemas migrate to the unified v1 record by: renaming fields to snake_case, wrapping type-specific fields inside the event object with a type discriminator, adding the src probe identifier, and converting timestamps to ts_ns (nanoseconds since boot). The v1 field names and discriminator values are those in the JSON Schema.
Related
- Probe Reference — which probe emits each event type
- Operator Runbook — collecting, verifying, and archiving evidence
- Security Model — evidence integrity and tamper-evidence
- eBPF Reachability overview
