173 lines
6.8 KiB
Markdown
173 lines
6.8 KiB
Markdown
# Execution Evidence Predicate Contract
|
|
|
|
**Predicate Type:** `stella.ops/executionEvidence@v1`
|
|
**Status:** Active
|
|
**Sprint:** SPRINT_20260219_013
|
|
|
|
Provides a cryptographically verifiable, deterministic attestation that a specific artifact was observed executing in a real environment. Converts "it executed" from an implicit signal into a signed DSSE predicate suitable for policy gates and audit packs.
|
|
|
|
## Overview
|
|
|
|
- **Auditability:** Offline-verifiable proof that an artifact ran in a given environment.
|
|
- **Determinism:** Same trace input blob produces byte-identical predicates (address-canonicalized, sorted).
|
|
- **Privacy-safe:** Coarse trace summary (syscall families, hot symbols, counts) — no raw syscall logs.
|
|
- **Offline-first:** No external service dependencies; uses local signing keys.
|
|
|
|
## Schema
|
|
|
|
```json
|
|
{
|
|
"predicateType": "stella.ops/executionEvidence@v1",
|
|
"subject": [{"name": "artifact", "digest": {"sha256": "<canonical_id>"}}],
|
|
"predicate": {
|
|
"artifact_id": "sha256:<image_or_binary_digest>",
|
|
"environment_id": "<env_identifier>",
|
|
"trace_source": "ebpf|etw|dyld",
|
|
"observation_window": {
|
|
"start": "2026-02-19T12:00:00Z",
|
|
"end": "2026-02-19T12:00:10Z",
|
|
"duration_ms": 10000
|
|
},
|
|
"trace_summary": {
|
|
"syscall_families_observed": ["network", "filesystem", "process"],
|
|
"hot_symbols": ["main", "handleRequest", "db.Query"],
|
|
"hot_symbol_count": 42,
|
|
"unique_call_paths": 17,
|
|
"address_canonicalized": true
|
|
},
|
|
"trace_digest": "sha256:<hash_of_canonical_trace_blob>",
|
|
"determinism": {
|
|
"replay_seed": "<if applicable>",
|
|
"inputs_digest": "sha256:<hash_of_frozen_inputs>",
|
|
"expected_output_digest": "sha256:<if deterministic replay enabled>"
|
|
},
|
|
"timestamp": "2026-02-19T12:00:10Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
## Field Definitions
|
|
|
|
### Root Fields
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `predicateType` | string | yes | Always `stella.ops/executionEvidence@v1` |
|
|
| `subject` | array | yes | Single-element array with artifact canonical ID |
|
|
|
|
### Predicate Fields
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `artifact_id` | string | yes | `sha256:<digest>` of the container image or binary |
|
|
| `environment_id` | string | yes | Identifier of the environment where execution was observed |
|
|
| `trace_source` | string | yes | Instrumentation source: `ebpf`, `etw`, or `dyld` |
|
|
| `observation_window` | object | yes | Time window of the trace capture |
|
|
| `trace_summary` | object | yes | Coarse summary of observed behavior |
|
|
| `trace_digest` | string | yes | `sha256:<hex>` digest of the canonical trace blob |
|
|
| `determinism` | object | yes | Replay and determinism metadata |
|
|
| `timestamp` | ISO 8601 | yes | When the predicate was generated |
|
|
|
|
### Observation Window
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `start` | ISO 8601 | yes | Trace capture start time |
|
|
| `end` | ISO 8601 | yes | Trace capture end time |
|
|
| `duration_ms` | long | yes | Window duration in milliseconds |
|
|
|
|
### Trace Summary
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `syscall_families_observed` | string[] | yes | Coarse syscall families: `network`, `filesystem`, `process` |
|
|
| `hot_symbols` | string[] | yes | Top-K symbols by hit count (capped by `MaxHotSymbols`) |
|
|
| `hot_symbol_count` | int | yes | Total number of distinct hot symbols before top-K |
|
|
| `unique_call_paths` | int | yes | Number of unique call paths observed |
|
|
| `address_canonicalized` | bool | yes | Whether ASLR noise was stripped |
|
|
|
|
### Determinism Metadata
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| `replay_seed` | string | no | Seed for deterministic replay (if applicable) |
|
|
| `inputs_digest` | string | yes | `sha256:<hex>` of frozen input set |
|
|
| `expected_output_digest` | string | no | Expected output digest (if deterministic replay enabled) |
|
|
|
|
## Privacy Canonicalization Rules
|
|
|
|
The following transformations are applied to raw trace data before predicate generation:
|
|
|
|
| Data | Canonicalization | Rationale |
|
|
|------|-----------------|-----------|
|
|
| Memory addresses (loader base) | Stripped to zero-based offset | Removes ASLR noise |
|
|
| Socket addresses | Port stripped, IP retained as family indicator | Privacy — port numbers leak service topology |
|
|
| Process names | Retained (coarse family classification only) | Needed for `process` syscall family |
|
|
| Raw syscall sequences | Collapsed to family set (`network`, `filesystem`, `process`) | Privacy-safe, deterministic |
|
|
| Symbol names | Retained (hot symbols are public API surface) | Required for trace utility |
|
|
| File paths | Not included in predicate | Privacy — paths leak deployment layout |
|
|
|
|
## Digest Computation
|
|
|
|
### Trace Digest
|
|
|
|
1. Sort canonical trace events by `(SymbolId, HitCount)` ascending.
|
|
2. Serialize to deterministic JSON (sorted keys, no whitespace).
|
|
3. Compute `SHA256` over the UTF-8 bytes.
|
|
4. Encode as lowercase hex with `sha256:` prefix.
|
|
|
|
### Predicate Digest
|
|
|
|
1. Serialize the complete predicate to deterministic JSON.
|
|
2. Compute `SHA256` over the UTF-8 bytes.
|
|
3. Encode as lowercase hex (no prefix).
|
|
|
|
## DSSE Signing
|
|
|
|
Predicates are wrapped in a DSSE envelope and signed using the environment's configured crypto profile. Supported profiles: EdDSA, ECDSA, RSA, GOST R 34.10, SM2, eIDAS QSealC, PQC (ML-DSA).
|
|
|
|
```json
|
|
{
|
|
"payloadType": "application/vnd.in-toto+json",
|
|
"payload": "<base64(predicate_json)>",
|
|
"signatures": [
|
|
{
|
|
"keyid": "<key_identifier>",
|
|
"sig": "<base64(signature)>"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Rate Limiting
|
|
|
|
One predicate per `(artifact_id, environment_id)` per configurable window (default: 60 minutes). Duplicate submissions within the window return a rate-limited result without generating a new predicate.
|
|
|
|
## Configuration
|
|
|
|
Section: `Signals:ExecutionEvidence`
|
|
|
|
| Option | Type | Default | Description |
|
|
|--------|------|---------|-------------|
|
|
| `Enabled` | bool | `true` | Whether the pipeline is active |
|
|
| `RateLimitWindowMinutes` | int | `60` | Rate limit window per artifact/environment pair |
|
|
| `MaxHotSymbols` | int | `50` | Maximum hot symbols in trace summary |
|
|
| `MinEventsThreshold` | int | `5` | Minimum events required to produce a predicate |
|
|
|
|
## API Endpoints
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| `POST` | `/signals/execution-evidence` | Submit runtime trace for evidence generation |
|
|
| `GET` | `/signals/execution-evidence/{artifactId}/{environmentId}` | Query latest evidence for an artifact/environment pair |
|
|
|
|
## Related Documents
|
|
|
|
- `docs/contracts/witness-v1.md` — Runtime witness predicate (complementary)
|
|
- `docs/contracts/beacon-attestation-v1.md` — Beacon attestation predicate (lightweight complement)
|
|
- `docs/modules/policy/gates/execution-evidence-gate.md` — Policy gate consuming this predicate
|
|
|
|
---
|
|
|
|
*Last updated: 2026-02-19.*
|