Initialize repository snapshot
This commit is contained in:
217
spec/ATTACK_RESISTANCE_LEDGER.md
Normal file
217
spec/ATTACK_RESISTANCE_LEDGER.md
Normal file
@@ -0,0 +1,217 @@
|
||||
# Attack Resistance & Control Ledger
|
||||
|
||||
Status: Canonical
|
||||
Scope: State-Level Threat Model
|
||||
Operating Mode: Single-Sovereign, Local-First
|
||||
Federation: Optional Witness Augmentation
|
||||
|
||||
## Non-goal
|
||||
|
||||
VaultMesh does not guarantee liveness, availability, or global consensus under adversarial conditions. It guarantees detectability, attribution, and recoverable truth.
|
||||
|
||||
## Pinned Definitions
|
||||
|
||||
- **ShadowReceipt**: An append-only proof emitted when an action is considered but not executed, recording intent, denial reason, and (if applicable) scope narrowing without side effects.
|
||||
- **Receipt scroll**: An append-only JSONL event log per domain (e.g., `receipts/treasury/treasury_events.jsonl`).
|
||||
- **Merkle root**: A deterministic commitment over a scroll’s hashed leaves using the VaultMesh `VmHash` + `merkle_root` algorithm.
|
||||
- **Root file**: A file that stores the current Merkle root for a scroll (typically `ROOT.<scroll>.txt`).
|
||||
- **Seal bundle (Ouroboros)**: A deterministic digest over a selected evidence set in the local SQLite ledger, stored as a `proof_artifacts.kind=ouroboros_seal_bundle` artifact.
|
||||
- **Anchor (external, optional)**: A timestamp/immutability witness over a seal digest (RFC-3161 / blockchain / etc.), recorded as an additional proof artifact referencing the seal bundle.
|
||||
- **Trace id**: A correlation id linking the evidence chain across `tool_invocations`, `mcp_calls`, `proof_artifacts`, and (where emitted) `shadow_receipts`.
|
||||
- **Capability / scope**: A revocable, least-privilege right that can be narrowed without rewriting history (Mesh receipts).
|
||||
|
||||
## Operating Assumption
|
||||
|
||||
VaultMesh is designed to remain truthful, auditable, and survivable as a single sovereign system under isolation. Federation is an optional augmentation that increases resilience and reach, but is never required for correctness.
|
||||
|
||||
Primary adversary context: *“You are alone. No peers. No network. No court protection.”*
|
||||
|
||||
## Adversary Classes (State-Level)
|
||||
|
||||
- **Isolation**: network partition, long-term offline operation, selective connectivity denial.
|
||||
- **Seizure**: physical confiscation, disk imaging, forced shutdown, forced relocation.
|
||||
- **Coercion**: compelled operation, compelled credential disclosure, compelled signing.
|
||||
- **Supply chain**: compromised dependencies, poisoned updates, build/release interdiction.
|
||||
- **Insider drift**: sequences of individually policy-valid actions that violate long-horizon invariants.
|
||||
- **Narrative warfare**: re-framing outages as “lies”, attacking legitimacy rather than mechanics.
|
||||
|
||||
---
|
||||
|
||||
## 🜔 Proof (Immutable Wealth)
|
||||
|
||||
### Invariants
|
||||
|
||||
- **Append-only evidence**: evidence is never rewritten in place; corrections are new events referencing prior ids/hashes.
|
||||
- **Deterministic verification**: the same inputs yield the same roots and seal digests.
|
||||
- **Detectable tamper**: any change to past events must surface as a root/seal mismatch.
|
||||
|
||||
### Likely Moves
|
||||
|
||||
- Edit/delete old receipts; roll back state to a “clean” snapshot; truncate scrolls.
|
||||
- Rewrite root files to match a forged history.
|
||||
- Partition the node so anchoring cannot occur.
|
||||
|
||||
### Controls
|
||||
|
||||
- Scrolls are append-only JSONL + deterministic Merkle roots (`ROOT.*.txt`).
|
||||
- Seals bind SQLite evidence to a deterministic digest (local witness) that can be copied out-of-band.
|
||||
- Optional anchoring adds a time witness when connectivity exists (never required for local correctness).
|
||||
|
||||
### Evidence Artifacts
|
||||
|
||||
- Scrolls: `receipts/**`
|
||||
- Roots: `ROOT.*.txt` and `receipts/console/ROOT.console.txt`
|
||||
- Local ledger: `.state/ledger.sqlite` (`tool_invocations`, `mcp_calls`, `proof_artifacts`, `shadow_receipts`)
|
||||
- Seal bundles: `.state/seals/ouroboros_seal_*.json` + `proof_artifacts.kind=ouroboros_seal_bundle`
|
||||
- Anchor receipts: `receipts/guardian/anchor_events.jsonl` (and planned `proof_artifacts.kind=external_anchor`)
|
||||
|
||||
### Drills
|
||||
|
||||
- Recompute and compare roots (no writes): `python3 cli/vm_cli.py guardian compute-roots`
|
||||
- Check whether on-disk roots match computed roots: `python3 cli/vm_cli.py guardian status`
|
||||
- Emit an anchor cycle (writes roots + anchor receipt): `python3 cli/vm_cli.py guardian anchor --backend local`
|
||||
- Seal recent evidence (deterministic digest over ledger tables): `python3 cli/ledger.py seal --since "7 days"`
|
||||
|
||||
---
|
||||
|
||||
## 🜃 Energy (Scarce Wealth)
|
||||
|
||||
### Invariants
|
||||
|
||||
- **No action without cost**: actions require a debit/charge.
|
||||
- **No cost without record**: debits/credits are receipted; state is reconstructable from receipts.
|
||||
- **No silent denial**: denied/aborted high-impact actions produce a ShadowReceipt (proof of restraint), not silence.
|
||||
|
||||
### Likely Moves
|
||||
|
||||
- Spam/flood to force writes, bury signals in volume, or extract unbounded work.
|
||||
- Coercive drain of budgets to force depletion or induce “just this once” shortcuts.
|
||||
|
||||
### Controls
|
||||
|
||||
- Debit-before-write for mutating operations; budgets enforce ceilings.
|
||||
- Compartment budgets by purpose; require stronger capabilities for high-impact budgets.
|
||||
- “Freeze” and “contain” responses narrow authority; they never grant new authority.
|
||||
|
||||
### Evidence Artifacts
|
||||
|
||||
- Treasury scroll + root: `receipts/treasury/treasury_events.jsonl`, `ROOT.treasury.txt`
|
||||
- Ledger witness of debits/denials: `.state/ledger.sqlite` (`tool_invocations`, `shadow_receipts`)
|
||||
- Seal bundles over the above: `.state/seals/ouroboros_seal_*.json`
|
||||
|
||||
### Drills
|
||||
|
||||
- Create a seal over a high-volume window and confirm it is stable on replay: `python3 cli/ledger.py seal --since "1 day"`
|
||||
- Confirm denials are queryable (ShadowReceipts are sealed even if not rooted):
|
||||
- `sqlite3 .state/ledger.sqlite "select ts,horizon_id,reason_unrealized,trace_id from shadow_receipts order by datetime(ts) desc limit 20;"`
|
||||
|
||||
---
|
||||
|
||||
## 🜍 Intelligence (Auditable Consciousness)
|
||||
|
||||
### Invariants
|
||||
|
||||
- **Bounded automation**: analysis may run, but execution requires capability + receipt trail.
|
||||
- **Legible decisions**: reasoning/uncertainty is recorded as evidence, not “trust the model”.
|
||||
- **Temporal defensibility**: “locally allowed” is insufficient if a long-horizon invariant is violated.
|
||||
|
||||
### Likely Moves
|
||||
|
||||
- Drift sequences: individually allowed steps that collectively break invariants.
|
||||
- Poisoned telemetry: adversarial signals to induce unsafe policies or overblocking.
|
||||
- “Optimize away restraint”: remove proof-of-denial records to reduce friction.
|
||||
|
||||
### Controls
|
||||
|
||||
- DriftGuard pattern: detect long-horizon invariant violations and deny execution while emitting a ShadowReceipt.
|
||||
- Quarantine: treat suspicious signals as inputs to proposals (artifacts), not direct law rewrites.
|
||||
- Replay + seal: decisions are reviewable through deterministic seals over evidence sets.
|
||||
|
||||
### Evidence Artifacts
|
||||
|
||||
- ShadowReceipts: `.state/ledger.sqlite` table `shadow_receipts`
|
||||
- Correlated evidence chain: `.state/ledger.sqlite` tables `tool_invocations`, `mcp_calls`, `proof_artifacts`
|
||||
- Automation scroll (if/when used): `receipts/automation/automation_events.jsonl`, `ROOT.automation.txt`
|
||||
|
||||
### Drills
|
||||
|
||||
- Create a ShadowReceipt for a denied path (proof of restraint), then seal the window:
|
||||
- `python3 cli/ledger.py seal --since "1 day"`
|
||||
- Confirm trace correlation is preserved (and treat gaps as audit failures):
|
||||
- `python3 cli/ledger.py last --n 50`
|
||||
|
||||
---
|
||||
|
||||
## ☿ Trust (Circulating Authority)
|
||||
|
||||
### Invariants
|
||||
|
||||
- **No ambient trust**: rights are explicit capabilities with scopes.
|
||||
- **Revocation is additive**: power can shrink without erasing history.
|
||||
- **Containment > blame**: automatic responses narrow scopes; they do not expand authority.
|
||||
|
||||
### Likely Moves
|
||||
|
||||
- Key theft / replay; attempt to broaden scope “just for recovery”.
|
||||
- Coercion to compel signing or privileged action.
|
||||
|
||||
### Controls
|
||||
|
||||
- Least-privilege, short-lived capabilities; explicit scopes; revocation receipts.
|
||||
- For irreversible actions: time-locks and/or multi-party approval (policy-dependent).
|
||||
- Record refusals as ShadowReceipts; never “black-hole” denied operations.
|
||||
|
||||
### Evidence Artifacts
|
||||
|
||||
- Mesh capability receipts + root: `receipts/mesh/mesh_events.jsonl`, `ROOT.mesh.txt`
|
||||
- Identity receipts + root: `receipts/identity/identity_events.jsonl`, `ROOT.identity.txt`
|
||||
- ShadowReceipts for denied/coerced paths: `.state/ledger.sqlite` `shadow_receipts`
|
||||
|
||||
### Drills
|
||||
|
||||
- Revoke and verify containment:
|
||||
- (emit revoke) verify it appears in `receipts/mesh/mesh_events.jsonl`
|
||||
- recompute roots: `python3 cli/vm_cli.py guardian compute-roots`
|
||||
|
||||
---
|
||||
|
||||
## 🜞 Time (Continuity Across Decades)
|
||||
|
||||
### Invariants
|
||||
|
||||
- **Portability**: proofs can be verified from artifacts alone.
|
||||
- **Legibility**: tools and formats remain understandable without a priesthood.
|
||||
- **Recoverability**: state can be reconstructed from receipts + seals.
|
||||
|
||||
### Likely Moves
|
||||
|
||||
- Long-term offline storage; partial artifact survival; missing dependencies; bit rot.
|
||||
- Availability attacks misframed as correctness failures (narrative warfare).
|
||||
|
||||
### Controls
|
||||
|
||||
- Boring formats: JSONL + SQLite + text roots.
|
||||
- Archaeology drill: restore from a cold copy and re-derive roots and seals.
|
||||
- Explicitly separate **truth** from **availability** (see Non-goal).
|
||||
|
||||
### Evidence Artifacts
|
||||
|
||||
- Local ledger: `.state/ledger.sqlite`
|
||||
- Scrolls + roots: `receipts/**`, `ROOT.*.txt`, `receipts/console/ROOT.console.txt`
|
||||
- Constitutional mapping: `spec/BLUEPRINT_SPEC.md`, `spec/MAPPING.md`
|
||||
|
||||
### Drills
|
||||
|
||||
- Cold-restore verification: copy artifacts to a new directory and run:
|
||||
- `python3 cli/vm_cli.py guardian status`
|
||||
- `python3 cli/ledger.py seal --since "365 days"`
|
||||
|
||||
---
|
||||
|
||||
## Federation (Optional Witness Augmentation)
|
||||
|
||||
Federation is not correctness. It is redundancy and cross-witnessing.
|
||||
|
||||
- Peers may mirror roots/seals to increase survivability and detect targeted rollback.
|
||||
- Disagreement is an incident artifact, not a correctness failure of the local node.
|
||||
|
||||
203
spec/BLUEPRINT_SPEC.md
Normal file
203
spec/BLUEPRINT_SPEC.md
Normal file
@@ -0,0 +1,203 @@
|
||||
# VaultMesh Blueprint Spec (v0)
|
||||
|
||||
This document defines the concrete, auditable objects and invariants implied by the VaultMesh Blueprint. It is written to be implementable and reviewable by engineers and auditors.
|
||||
|
||||
## Scope
|
||||
|
||||
This spec covers:
|
||||
- Local-first evidence storage (SQLite ledger)
|
||||
- File-based receipt scrolls and Merkle roots
|
||||
- Sealing (deterministic digests over a set of events) and external anchoring
|
||||
- ShadowReceipts (“proof of restraint”) as a first-class, queryable record
|
||||
- Evolution control (epochs) and bounded automation (Autogene: read-only)
|
||||
|
||||
## Core Objects
|
||||
|
||||
### 1) ProofRune
|
||||
|
||||
A generic “proof container” for any payload that must be replayable, hashable, and auditable.
|
||||
|
||||
Minimal shape:
|
||||
```json
|
||||
{
|
||||
"payload": { "any": "json" },
|
||||
"capability_hash": "hex",
|
||||
"merkle_root": "hex|0",
|
||||
"epoch": "nigredo|albedo|rubedo",
|
||||
"ts": "ISO-8601 Z"
|
||||
}
|
||||
```
|
||||
|
||||
Storage:
|
||||
- As an on-disk file referenced by a row in `proof_artifacts` (preferred), or
|
||||
- As a JSON object in `proof_artifacts.meta_json` for small payloads.
|
||||
|
||||
### 2) OuroborosReceipt (Seal Bundle + External Anchor)
|
||||
|
||||
An OuroborosReceipt is a *sealed* summary proof for a selected set of events, anchored externally.
|
||||
|
||||
It has two layers:
|
||||
1) **Local seal bundle** (SQLite witness): a deterministic digest over a chosen set.
|
||||
2) **External anchor** (pipeline witness): an immutable timestamp/anchor referencing the seal digest.
|
||||
|
||||
Minimal fields (local seal bundle file):
|
||||
```json
|
||||
{
|
||||
"format": "vm-ouroboros-seal-v0",
|
||||
"schema_version": 3,
|
||||
"schema_last_migration": "0003_shadow_receipts.sql",
|
||||
"seal_id": "uuid",
|
||||
"sealed_at": "ISO-8601 Z",
|
||||
"digest_algo": "sha256",
|
||||
"selection": {
|
||||
"scope": "time_window|trace_set",
|
||||
"since": "ISO-8601 Z|null",
|
||||
"until": "ISO-8601 Z|null",
|
||||
"trace_ids": ["uuid", "..."],
|
||||
"kinds": ["tool_invocations", "mcp_calls", "proof_artifacts"]
|
||||
},
|
||||
"digest": {
|
||||
"algorithm": "sha256",
|
||||
"hex": "..."
|
||||
},
|
||||
"bounds": {
|
||||
"min_ts": "ISO-8601 Z|null",
|
||||
"max_ts": "ISO-8601 Z|null"
|
||||
},
|
||||
"inputs": {
|
||||
"sqlite_db_path": "path",
|
||||
"receipt_roots": ["receipts/**/ROOT.*.txt"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
External anchor evidence is recorded as an additional `proof_artifacts` row that either:
|
||||
- embeds the anchor payload (e.g., RFC-3161 token, txid), or
|
||||
- references an artifact path containing it.
|
||||
|
||||
### 3) ShadowReceipt (Proof of Restraint)
|
||||
|
||||
A ShadowReceipt records a counterfactual/near-miss/aborted path without rewriting canonical history.
|
||||
|
||||
Minimal row fields (table `shadow_receipts`):
|
||||
- `id`: uuid
|
||||
- `ts`: ISO-8601 Z
|
||||
- `horizon_id`: stable identifier for a decision horizon
|
||||
- `counterfactual_hash`: hash of a canonicalized counterfactual description
|
||||
- `entropy_delta`: numeric drift/uncertainty signal (policy-defined meaning)
|
||||
- `reason`: short reason the path was not executed
|
||||
- `observer_signature`: signature/attestation of the observer (human or system identity)
|
||||
- `trace_id`: correlation id linking to tool/MCP/receipt chain
|
||||
- `meta_json`: optional redacted metadata
|
||||
|
||||
ShadowReceipts are **not** part of the per-engine Merkle roots by default; they remain queryable and auditable via SQLite + seals.
|
||||
|
||||
### 4) Guardians
|
||||
|
||||
Guardians are bounded subsystems that:
|
||||
- ingest signals (telemetry, anomalies, drift indicators)
|
||||
- produce evidence (receipts/artifacts)
|
||||
- produce proposals (never unilateral law rewrites)
|
||||
|
||||
In implementation terms, a Guardian is a module that consumes ledger/scroll state and emits:
|
||||
- `proof_artifacts` (reports, policies, recommended changes)
|
||||
- (optionally) receipt scroll entries in its engine domain
|
||||
- (optionally) ShadowReceipts
|
||||
|
||||
### 5) Directed Evolution Engine (DEE)
|
||||
|
||||
DEE is a controller that converts signals into *proposed* system changes.
|
||||
|
||||
Outputs are always proposals, not direct execution. Executing a proposal requires:
|
||||
- capability authorization, and
|
||||
- an auditable receipt trail (scroll + seal).
|
||||
|
||||
DEE outputs are stored as `proof_artifacts` with stable formats (e.g., `vm-dee-proposal-v0`).
|
||||
|
||||
### 6) Epoch
|
||||
|
||||
`epoch` is an explicit system mode included in ProofRunes and proposals:
|
||||
- `nigredo`: maximum learning; conservative execution
|
||||
- `albedo`: normalization and stabilization
|
||||
- `rubedo`: directed transformation (strict gating)
|
||||
|
||||
Epoch changes are themselves auditable events (receipt + seal).
|
||||
|
||||
### 7) Autogene (Read-only)
|
||||
|
||||
Autogene is a bounded anticipatory system:
|
||||
- It can analyze and forecast.
|
||||
- It cannot execute changes directly.
|
||||
|
||||
Autogene outputs are stored as `proof_artifacts` (e.g., `autogene_forecast`, `autogene_recommendation`) and require the same approval/execution gates as any other proposal.
|
||||
|
||||
## Invariants (Must Hold)
|
||||
|
||||
1) **Local-first evidence**: every externally anchored claim must correspond to a locally stored seal bundle (SQLite witness).
|
||||
2) **Deterministic sealing**: the seal digest is deterministic for a given selection + canonicalization rules.
|
||||
3) **Append-only evidence**: evidence is never rewritten in place; corrections are new receipts/artifacts referencing prior ids/hashes.
|
||||
4) **Action gating**: proposals never execute themselves; execution requires capability + receipt trail.
|
||||
5) **Autogene read-only**: Autogene cannot mutate state; it only emits artifacts.
|
||||
6) **Shadow separation**: ShadowReceipts do not retroactively alter canonical history; they are additive evidence.
|
||||
7) **Trace continuity**: a `trace_id` links the full chain across:
|
||||
- `tool_invocations.trace_id`
|
||||
- `mcp_calls.trace_id`
|
||||
- `proof_artifacts.trace_id`
|
||||
- `shadow_receipts.trace_id` (planned)
|
||||
8) **Redaction for storage**: stored payloads must be redacted/hashed where appropriate (secrets never stored in plaintext).
|
||||
|
||||
## Evidence Artifacts (What Proves What)
|
||||
|
||||
### SQLite ledger (queryable witness)
|
||||
|
||||
Current tables:
|
||||
- `tool_invocations`: “what local tools did” with redacted inputs/outputs.
|
||||
- `mcp_calls`: “what boundary calls happened” with redacted request/response.
|
||||
- `proof_artifacts`: “what proof objects exist” (files and/or meta) with content hashes.
|
||||
- `shadow_receipts`: “what paths were considered and not executed” (proof of restraint).
|
||||
|
||||
### Receipt scrolls + roots (tamper-evident chronology)
|
||||
|
||||
Per-engine JSONL scrolls and their Merkle roots (e.g., console engine):
|
||||
- `receipts/**/ENGINE_EVENTS.jsonl`
|
||||
- `receipts/**/ROOT.*.txt`
|
||||
|
||||
These are inputs into sealing and external anchoring, but they remain independently verifiable.
|
||||
|
||||
### Seals and anchors (bridge to external immutability)
|
||||
|
||||
- Seal bundle file: stored as `proof_artifacts` with a strong digest.
|
||||
- External anchor evidence: stored as a second `proof_artifacts` row referencing or embedding:
|
||||
- RFC-3161 timestamp token
|
||||
- release-time Merkle root(s)
|
||||
- blockchain txid(s) or other anchoring proof
|
||||
|
||||
## Failure Modes (Detection + Response)
|
||||
|
||||
1) **Ledger tampering / local rollback**
|
||||
- Detect: mismatch between `proof_artifacts.sha256_hex` and file contents; seal digest mismatch; missing expected rows.
|
||||
- Respond: emit a new artifact documenting divergence; re-seal; escalate to external anchor verification.
|
||||
|
||||
2) **External anchor missing or unverifiable**
|
||||
- Detect: seal exists but no anchor artifact; anchor proof fails verification.
|
||||
- Respond: block promotion of high-impact changes; emit incident artifact; re-run anchoring pipeline.
|
||||
|
||||
3) **Poisoning of learning signals / adversarial telemetry**
|
||||
- Detect: replay reports show FP increase or catastrophic boundary regression; outlier actors dominate support.
|
||||
- Respond: require quorum + replay + human approval; quarantine candidates; record a ShadowReceipt for the rejected promotion.
|
||||
|
||||
4) **Overblocking / drift into refusal**
|
||||
- Detect: trend in false positives; rising “blocked” outcomes on benign workloads.
|
||||
- Respond: rollback via new policy receipt; require replay validation before relaxation is promoted.
|
||||
|
||||
5) **Clock skew / timestamp ambiguity**
|
||||
- Detect: non-monotonic timestamps, ordering anomalies in seals.
|
||||
- Respond: anchor by content ordering (stable sort keys); treat timestamps as metadata; include row ids/hashes in sealing.
|
||||
|
||||
6) **Trace discontinuity**
|
||||
- Detect: tool/MCP/proof artifacts lacking `trace_id` where expected.
|
||||
- Respond: enforce trace propagation at call sites; treat missing trace links as audit gaps.
|
||||
|
||||
## Versioning
|
||||
|
||||
All seal bundle formats MUST include a `format` string (e.g., `vm-ouroboros-seal-v0`). Any breaking change requires a new version and must be documented as an auditable artifact.
|
||||
36
spec/MAPPING.md
Normal file
36
spec/MAPPING.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# Blueprint → Code Mapping (v0)
|
||||
|
||||
This document maps Blueprint objects to concrete modules/files and to the local SQLite ledger evidence they must produce.
|
||||
|
||||
## Mapping Table
|
||||
|
||||
| Blueprint object | Implementation location | Ledger tables touched | Proof artifacts emitted | Trace propagation rules |
|
||||
|---|---|---|---|---|
|
||||
| ProofRune | `ledger/db.py` (artifact hashing), `ledger/redact.py` (safe storage), engine scroll emitters | `proof_artifacts` | `proof_artifacts.kind=*` (file/hash recorded) | `proof_artifacts.trace_id` should match the initiating tool/MCP trace |
|
||||
| OuroborosReceipt (local seal bundle) | `cli/ledger.py` subcommand `seal` | `proof_artifacts` (and read-only queries over `tool_invocations`, `mcp_calls`) | `kind=ouroboros_seal_bundle` | Seal bundle should include selection (since/until/trace_ids) and record the sealing `trace_id` |
|
||||
| External anchor evidence | **Pipeline/ops**, recorded back into SQLite via CLI/tooling | `proof_artifacts` | `kind=external_anchor` (planned) | Anchor artifact must reference seal digest + seal artifact id/path |
|
||||
| ShadowReceipt | `ledger/schema/0003_shadow_receipts.sql` + `ledger/db.py` helper | `shadow_receipts` | Optional: `kind=shadow_receipt_attachment` for large payloads | `shadow_receipts.trace_id` must correlate to the considered action chain |
|
||||
| Guardian (generic) | `vaultmesh-guardian/` (Rust), `vaultmesh-offsec/`, `vaultmesh-observability/` (future), plus Python engines as needed | `tool_invocations`, `mcp_calls`, `proof_artifacts` | `kind=guardian_report`, `kind=guardian_policy_proposal` (planned) | Guardian-generated events must either reuse the upstream `trace_id` or emit a new trace id and link it in meta |
|
||||
| DEE proposal output | `engines/` (planned controller module) | `proof_artifacts` | `kind=dee_proposal` (planned) | Proposal artifacts must link to the evidence set used to produce them (seal ids, trace ids) |
|
||||
| Epoch (mode) | Stored as a field inside proposal/seal payloads; epoch changes logged as receipts (future) | `proof_artifacts` (and engine scrolls) | `kind=epoch_change` (planned) | Epoch changes must be sealed and externally anchored for high-impact transitions |
|
||||
| Autogene (read-only) | `engines/` (planned analytics job) | `proof_artifacts` | `kind=autogene_forecast`, `kind=autogene_recommendation` (planned) | Outputs must never trigger execution; they must be consumable as inputs to an approval gate |
|
||||
| Console receipt scroll + Merkle root | `engines/console/receipts.py` | (not SQLite by default) | Root file(s) under `receipts/**/ROOT.*.txt` | Seal bundles should include the root files as inputs; optional `proof_artifacts` rows can reference root files |
|
||||
| Approvals | `engines/console/approvals.py` (receipted), `cli/vm_cli.py` (entrypoint) | (scroll-based today; SQLite optional later) | Receipt types `console_approval_request` and `console_approval` | Approval decisions should carry the same `trace_id` as the action being approved (planned wiring) |
|
||||
| Local ledger introspection | `cli/ledger.py` | Read-only queries over `tool_invocations`, `mcp_calls`, `proof_artifacts` | None (unless exporting reports) | Reporting commands should preserve trace correlation when exporting artifacts |
|
||||
|
||||
## SQLite Ledger Schema (Current)
|
||||
|
||||
Defined in:
|
||||
- `ledger/schema/0001_init.sql` (tables)
|
||||
- `ledger/schema/0002_indexes.sql` (indexes)
|
||||
|
||||
Tables:
|
||||
- `tool_invocations`
|
||||
- `mcp_calls`
|
||||
- `proof_artifacts`
|
||||
|
||||
## Planned Additions (Not Yet Implemented)
|
||||
|
||||
1) External anchoring capture:
|
||||
- Insert `proof_artifacts.kind=external_anchor` referencing a prior `ouroboros_seal_bundle`
|
||||
- Store RFC-3161 tokens and/or chain txids either embedded in `meta_json` or as file paths
|
||||
331
spec/MERIDIAN_V1_FAQ_HOSTILE_REGULATOR_EDITION.md
Normal file
331
spec/MERIDIAN_V1_FAQ_HOSTILE_REGULATOR_EDITION.md
Normal file
@@ -0,0 +1,331 @@
|
||||
# MERIDIAN v1 FAQ — Hostile Regulator Edition (Evidence‑First)
|
||||
|
||||
Status: Draft (regulator-facing; non-marketing; copy/paste runnable)
|
||||
Scope: MERIDIAN v1 conformance evidence + Sentinel v1 offline verifier
|
||||
|
||||
This FAQ is written for the “hostile room”: every answer routes to **offline, deterministic evidence**.
|
||||
|
||||
Baseline: generate the evidence once, then answer every question by pointing to `out/`.
|
||||
|
||||
```bash
|
||||
bash vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/run.sh
|
||||
```
|
||||
|
||||
Artifacts:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/report.json`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/*.record.json`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/sentinel_reports/*.verification_report.json`
|
||||
|
||||
Definitions (used throughout):
|
||||
- `exit`: verifier exit code (`0` PASS, `1` FAIL)
|
||||
- `failure_code`: Sentinel failure code (e.g. `E_EVENT_HASH_MISMATCH`)
|
||||
- `violated_contract_ids`: stable contract IDs (e.g. `E-2`)
|
||||
- “fail‑closed”: verifier returns non‑zero and emits explicit codes/contract IDs
|
||||
|
||||
Normative references:
|
||||
- Verifier: `vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py`
|
||||
- Failure codes: `vaultmesh-orgine-mobile/tools/sentinel_failure_codes.py`
|
||||
- Failure semantics: `vaultmesh-orgine-mobile/spec/SENTINEL_FAILURE_CODE_SEMANTICS.md`
|
||||
- Contract matrix: `vaultmesh-orgine-mobile/spec/SENTINEL_V1_CONTRACT_MATRIX.md`
|
||||
- Evidence standard: `vaultmesh-orgine-mobile/spec/SENTINEL_EVIDENCE_STANDARD.md`
|
||||
|
||||
---
|
||||
|
||||
## 1) “How do you prevent evidence fabrication by the operator?”
|
||||
|
||||
Answer (direct):
|
||||
- The offline verifier proves **internal integrity** of a bundle (hash chain + Merkle roots + integrity manifest).
|
||||
- It does **not** prove “this history was the only possible history” without an **external anchor** (procedural control).
|
||||
|
||||
Verifier‑enforced controls (objective; evidence‑backed):
|
||||
- Any post‑hoc modification inside a bundle is detected and fails closed (`E_EVENT_HASH_MISMATCH`, `E_MANIFEST_HASH_MISMATCH`, `E_ROOT_MISMATCH`).
|
||||
|
||||
Audit‑procedural controls (required if you want “anti‑fabrication” rather than “tamper detection”):
|
||||
- Independent anchoring of Merkle roots to an immutable witness (WORM storage / external ledger / third‑party timestamping).
|
||||
- Chain‑of‑custody of bundles (who held them, when).
|
||||
|
||||
Run (tamper detection demonstrations; both are expected FAIL fixtures):
|
||||
```bash
|
||||
python3 vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py \
|
||||
--bundle vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/fixtures/fail/event_hash_mismatch \
|
||||
--strict
|
||||
|
||||
python3 vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py \
|
||||
--bundle vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/fixtures/fail/manifest_hash_mismatch \
|
||||
--strict
|
||||
```
|
||||
|
||||
Expected:
|
||||
- Exit: `1`
|
||||
- Failure codes: `E_EVENT_HASH_MISMATCH` and `E_MANIFEST_HASH_MISMATCH`
|
||||
- Contract IDs: `E-2` and `I-3`
|
||||
|
||||
Inspect:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-EVENT-001.record.json`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-SEAL-002.record.json`
|
||||
|
||||
Fail‑closed statement:
|
||||
- If any evidence inside a bundle is altered after sealing, verification refuses (`exit=1`) and emits stable codes + contract IDs.
|
||||
|
||||
---
|
||||
|
||||
## 2) “What happens if clocks drift, reboot loops occur, or power cycles happen?”
|
||||
|
||||
Answer (direct):
|
||||
- MERIDIAN/Sentinel ordering is secured by `seq` and the hash chain (`prev_event_hash`), not by wallclock.
|
||||
- Wallclock timestamps (`ts`) are recorded for audit correlation but are not the trust anchor for ordering.
|
||||
|
||||
Verifier‑enforced controls:
|
||||
- `seq` must be consistent and non‑ambiguous; replay/duplicate ordering fails closed.
|
||||
- Hash chain continuity fails closed if `prev_event_hash` does not link.
|
||||
|
||||
Audit‑procedural controls:
|
||||
- Correlate `ts` with independent time sources (NTP logs, hardware event logs, external anchors).
|
||||
- Treat time anomalies as incident signals; verification remains possible offline.
|
||||
|
||||
Run (ordering / continuity are expected FAIL fixtures):
|
||||
```bash
|
||||
python3 vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py \
|
||||
--bundle vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/fixtures/fail/seq_non_monotonic_duplicate \
|
||||
--strict
|
||||
|
||||
python3 vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py \
|
||||
--bundle vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/fixtures/fail/prev_event_hash_mismatch \
|
||||
--strict
|
||||
```
|
||||
|
||||
Expected:
|
||||
- Exit: `1`
|
||||
- Failure codes: `E_SEQ_NON_MONOTONIC`, `E_CHAIN_DISCONTINUITY`
|
||||
- Contract IDs: `E-4`, `E-3`
|
||||
|
||||
Inspect:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-EVENT-005.record.json`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-EVENT-003.record.json`
|
||||
|
||||
Fail‑closed statement:
|
||||
- If ordering/continuity is ambiguous or broken, verification refuses and emits explicit codes (`E_SEQ_NON_MONOTONIC` / `E_CHAIN_DISCONTINUITY`).
|
||||
|
||||
---
|
||||
|
||||
## 3) “How do you handle lawful access vs refusal?”
|
||||
|
||||
Answer (direct):
|
||||
- Lawful access produces an attributable `action_executed` trail.
|
||||
- Refusal produces an attributable `shadow_receipt` trail.
|
||||
- “No silent denial” is enforced: intent must have an outcome (executed or denied) in strict mode.
|
||||
|
||||
Verifier‑enforced controls:
|
||||
- Strict trace linkage requires `action_intent` → (`action_executed` **or** `shadow_receipt`), otherwise verification fails closed.
|
||||
|
||||
Audit‑procedural controls:
|
||||
- Define lawful basis and policy outside the verifier; the verifier enforces the resulting evidence integrity.
|
||||
|
||||
Run (refusal proof PASS + “silent denial” FAIL):
|
||||
```bash
|
||||
python3 vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py \
|
||||
--bundle vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/fixtures/pass/refusal_proof_pass \
|
||||
--strict
|
||||
|
||||
python3 vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py \
|
||||
--bundle vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/fixtures/fail/silent_denial_intent_without_outcome \
|
||||
--strict
|
||||
```
|
||||
|
||||
Expected:
|
||||
- PASS bundle exit: `0`
|
||||
- FAIL bundle exit: `1`
|
||||
- FAIL bundle `failure_code`: `E_CHAIN_DISCONTINUITY`
|
||||
- FAIL bundle contract IDs: `E-3`
|
||||
|
||||
Inspect:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-PASS-REFUSAL-001.record.json`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-REFUSAL-001.record.json`
|
||||
|
||||
Fail‑closed statement:
|
||||
- If a denial would be “silent” (intent without outcome), verification refuses with `E_CHAIN_DISCONTINUITY` and contract `E-3`.
|
||||
|
||||
---
|
||||
|
||||
## 4) “Can an operator delete or rewrite history?”
|
||||
|
||||
Answer (direct):
|
||||
- Delete: they can destroy local copies, but then there is no evidence; retention is procedural.
|
||||
- Rewrite: any rewrite inside a bundle is detected and fails closed.
|
||||
|
||||
Verifier‑enforced controls:
|
||||
- Missing required artifacts fail loudly (`E_MISSING_REQUIRED_FILE`).
|
||||
- Rewrites are detected via integrity digests (`E_MANIFEST_HASH_MISMATCH`), event hashes (`E_EVENT_HASH_MISMATCH`), roots/ranges (`E_ROOT_MISMATCH`, `E_RANGE_MISMATCH`).
|
||||
|
||||
Audit‑procedural controls:
|
||||
- WORM retention, redundancy, and off‑site escrow of evidence bundles.
|
||||
|
||||
Run (expected FAIL fixtures):
|
||||
```bash
|
||||
python3 vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py \
|
||||
--bundle vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/fixtures/fail/missing_required_file_roots \
|
||||
--strict
|
||||
```
|
||||
|
||||
Expected:
|
||||
- Exit: `1`
|
||||
- Failure code: `E_MISSING_REQUIRED_FILE`
|
||||
- Contract IDs: `B-1`
|
||||
|
||||
Inspect:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-SEAL-001.record.json`
|
||||
|
||||
Fail‑closed statement:
|
||||
- If required artifacts are missing, verification refuses and emits `E_MISSING_REQUIRED_FILE` + `B-1`.
|
||||
|
||||
---
|
||||
|
||||
## 5) “What if Sentinel itself is compromised?”
|
||||
|
||||
Answer (direct):
|
||||
- The verifier can prove integrity of what was recorded; it cannot prove the recorder was honest.
|
||||
- If Sentinel is compromised enough to generate a fully consistent but fraudulent history, detecting that requires external controls (anchoring, independent telemetry, attestation).
|
||||
|
||||
Verifier‑enforced controls:
|
||||
- The verifier can still detect internal inconsistencies (tampering, missing links, revoked capability used).
|
||||
- A “tamper signal” can be recorded and verified as present (evidence of a condition being asserted).
|
||||
|
||||
Audit‑procedural controls:
|
||||
- Independent tamper sensors, hardware attestation, and root anchoring external to the compromised device.
|
||||
|
||||
Run (tamper signal PASS + revoked cap FAIL):
|
||||
```bash
|
||||
python3 vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py \
|
||||
--bundle vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/fixtures/pass/tamper_signal_pass \
|
||||
--strict
|
||||
|
||||
python3 vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py \
|
||||
--bundle vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/fixtures/fail/revoked_capability_used \
|
||||
--strict
|
||||
```
|
||||
|
||||
Expected:
|
||||
- Tamper PASS exit: `0`
|
||||
- Revoked-cap FAIL exit: `1`
|
||||
- Revoked-cap `failure_code`: `E_REVOKED_CAPABILITY_USED`
|
||||
- Revoked-cap contract IDs: `E-7`
|
||||
|
||||
Inspect:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-PASS-TAMPER-001.record.json`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-CAP-001.record.json`
|
||||
|
||||
Fail‑closed statement:
|
||||
- If execution uses a revoked capability, verification refuses with `E_REVOKED_CAPABILITY_USED` + `E-7`.
|
||||
|
||||
---
|
||||
|
||||
## 6) “Is this surveillance by default?”
|
||||
|
||||
Answer (direct):
|
||||
- MERIDIAN v1 is an evidence system: it records **security‑relevant operations and refusals**, not continuous surveillance, unless you choose to log more.
|
||||
- The verifier enforces integrity of what you record; minimization is a governance and engineering choice.
|
||||
|
||||
Verifier‑enforced controls:
|
||||
- Integrity only: the verifier validates structure/hashes; it does not evaluate whether a payload is “too invasive.”
|
||||
|
||||
Audit‑procedural controls (privacy posture):
|
||||
- Minimize payloads; store sensitive values as digests/handles where possible.
|
||||
- Redact before storage/export where appropriate:
|
||||
- `vaultmesh-orgine-mobile/ledger/redact.py`
|
||||
|
||||
Run (evidence surface is discrete; PASS fixture demonstrates minimal event set):
|
||||
```bash
|
||||
python3 vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py \
|
||||
--bundle vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/fixtures/pass/refusal_proof_pass \
|
||||
--strict
|
||||
```
|
||||
|
||||
Expected:
|
||||
- Exit: `0`
|
||||
- Contract IDs: none (PASS)
|
||||
|
||||
Inspect:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/fixtures/pass/refusal_proof_pass/receipts.jsonl`
|
||||
|
||||
Fail‑closed statement:
|
||||
- If the evidence bundle is malformed or tampered, verification refuses; privacy minimization is enforced by policy and export/redaction controls, not by the verifier.
|
||||
|
||||
---
|
||||
|
||||
## 7) “What fails open vs fails closed?”
|
||||
|
||||
Answer (direct):
|
||||
- For compliance use, **always run strict**: `--strict` + the conformance suite gate.
|
||||
- In strict mode, warnings and partial verifications become failures (fail‑closed posture).
|
||||
|
||||
Verifier‑enforced controls:
|
||||
- Strict-mode failures for: missing links, replay/ordering ambiguity, tampering, unsupported canonicalization versions, oversize inputs.
|
||||
|
||||
Audit‑procedural controls:
|
||||
- Require strict verification for any compliance claim.
|
||||
- Treat any non‑zero verifier exit as “invalid evidence.”
|
||||
|
||||
Run (strict-mode is the compliance actuator):
|
||||
```bash
|
||||
bash vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/run.sh
|
||||
```
|
||||
|
||||
Expected:
|
||||
- Exit: `0` for a compliant build (any drift ⇒ non-zero)
|
||||
- Contract IDs: N/A at suite level (per-test records carry contract IDs)
|
||||
|
||||
Inspect:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/report.json`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/*.record.json`
|
||||
|
||||
Fail‑closed statement:
|
||||
- If any expected code/contract outcome drifts, the suite exits non-zero and CI fails.
|
||||
|
||||
---
|
||||
|
||||
## 8) “How do you stop the verifier from silently changing meanings?”
|
||||
|
||||
Answer (direct):
|
||||
- Failure codes are contractual, documented, and parity-gated.
|
||||
- The build fails if codes drift between docs and implementation.
|
||||
|
||||
Verifier‑enforced controls:
|
||||
- The verifier emits only enumerated codes (see `sentinel_failure_codes.py`); reports include contract IDs.
|
||||
|
||||
Audit‑procedural controls:
|
||||
- Pin verifier versions; record hashes of verifier artifacts in release processes.
|
||||
|
||||
Run (parity gate):
|
||||
```bash
|
||||
python3 vaultmesh-orgine-mobile/tools/check_sentinel_contract_parity.py
|
||||
```
|
||||
|
||||
Expected:
|
||||
- Exit: `0` and prints `[OK] …`
|
||||
- Contract IDs: N/A (tooling gate), but it protects all Sentinel contract IDs from silent drift.
|
||||
|
||||
Inspect:
|
||||
- `vaultmesh-orgine-mobile/spec/SENTINEL_FAILURE_CODE_SEMANTICS.md`
|
||||
- `vaultmesh-orgine-mobile/spec/SENTINEL_V1_CONTRACT_MATRIX.md`
|
||||
|
||||
Fail‑closed statement:
|
||||
- If the implementation and contractual docs drift, the parity gate fails and the build blocks.
|
||||
|
||||
---
|
||||
|
||||
## Annex — “If you only have 60 seconds”
|
||||
|
||||
1) Run:
|
||||
```bash
|
||||
bash vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/run.sh
|
||||
```
|
||||
|
||||
2) Open:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/report.json`
|
||||
|
||||
3) Confirm:
|
||||
- `counts.failed == 0`
|
||||
|
||||
4) For any hostile question:
|
||||
- Find the referenced `out/tests/<TEST_ID>.record.json` and compare `expected` vs `observed`.
|
||||
|
||||
309
spec/MERIDIAN_V1_INSURER_DUE_DILIGENCE_QUESTIONS.md
Normal file
309
spec/MERIDIAN_V1_INSURER_DUE_DILIGENCE_QUESTIONS.md
Normal file
@@ -0,0 +1,309 @@
|
||||
# MERIDIAN v1 — Insurer Due Diligence Questions (Evidence‑First)
|
||||
|
||||
Status: Draft (underwriter-facing; copy/paste runnable)
|
||||
Scope: MERIDIAN v1 conformance evidence, backed by Sentinel v1 offline verifier
|
||||
|
||||
This document is designed so an underwriter (or auditor) can ask the questions **verbatim** and receive answers as:
|
||||
- **paths** (authoritative artifacts)
|
||||
- **commands** (offline, deterministic verification)
|
||||
- **pass/fail conditions** (exit codes + contract IDs + failure codes)
|
||||
|
||||
## 0) Generate the evidence (offline)
|
||||
|
||||
From repo root:
|
||||
|
||||
```bash
|
||||
bash vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/run.sh
|
||||
```
|
||||
|
||||
Expected outcome:
|
||||
- Suite summary prints `Passed: N` and `Failed: 0`
|
||||
- Non-zero exit on any unexpected drift (exit code, failure_code, contract_ids)
|
||||
|
||||
Artifacts produced (the evidence surface):
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/report.json`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/report.txt`
|
||||
- Per-test records (expected vs observed):
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/*.record.json`
|
||||
- Raw verifier outputs (regenerable; convenience copies):
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/sentinel_reports/*.verification_report.json`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/sentinel_stdio/*.stdout.txt`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/sentinel_stdio/*.stderr.txt`
|
||||
|
||||
Fast index:
|
||||
|
||||
```bash
|
||||
python3 vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/run.py --list
|
||||
```
|
||||
|
||||
## A) “Can you prove what happened, offline, years later?”
|
||||
|
||||
### A1. Offline verification
|
||||
Question: Can an auditor validate a bundle **without network access or secrets**?
|
||||
|
||||
Evidence:
|
||||
- Verifier: `vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py`
|
||||
- Bundle(s): `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/fixtures/…`
|
||||
- Suite output: `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/report.json`
|
||||
|
||||
How to answer (example PASS bundle):
|
||||
```bash
|
||||
python3 vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py \
|
||||
--bundle vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/fixtures/pass/refusal_proof_pass \
|
||||
--strict
|
||||
```
|
||||
|
||||
Pass condition:
|
||||
- Exit `0` and prints `PASS`
|
||||
- Generated `verification_report.json` is deterministic for identical inputs
|
||||
|
||||
Test coverage:
|
||||
- `MV1-PASS-REFUSAL-001` (PASS refusal proof bundle)
|
||||
- `MV1-PASS-OFFLINE-001` (PASS after clean-room copy)
|
||||
|
||||
### A2. Deterministic roots (reproducible from artifacts alone)
|
||||
Question: Are Merkle roots reproducible from artifacts alone?
|
||||
|
||||
Evidence:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/report.json`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/sentinel_reports/*.verification_report.json`
|
||||
|
||||
How to answer (rerun determinism spot-check):
|
||||
```bash
|
||||
bash vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/run.sh
|
||||
cp vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/report.json /tmp/meridian_report_run1.json
|
||||
|
||||
bash vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/run.sh
|
||||
diff -u /tmp/meridian_report_run1.json vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/report.json
|
||||
```
|
||||
|
||||
Pass condition:
|
||||
- Same inputs ⇒ same `computed_end_root`, same `failure_code`, same `violated_contract_ids`
|
||||
|
||||
Test coverage:
|
||||
- `MV1-PASS-REFUSAL-001` (roots recompute to PASS)
|
||||
- `MV1-FAIL-SEAL-004` (root mismatch fails loudly)
|
||||
|
||||
### A3. No silent denial
|
||||
Question: Do denied operations produce verifiable evidence (not gaps)?
|
||||
|
||||
Evidence:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-REFUSAL-001.record.json`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-PASS-REFUSAL-001.record.json`
|
||||
|
||||
Pass condition:
|
||||
- “Intent without outcome” is detected as a failure with explicit contract IDs (no silent gaps).
|
||||
|
||||
Test coverage:
|
||||
- `MV1-FAIL-REFUSAL-001` (intent without outcome ⇒ `E_CHAIN_DISCONTINUITY`, contract `E-3`)
|
||||
- `MV1-FAIL-REFUSAL-002` (execution without intent ⇒ `E_CHAIN_DISCONTINUITY`, contract `E-3`)
|
||||
- `MV1-FAIL-REFUSAL-003` (double outcome ⇒ `E_CHAIN_DISCONTINUITY`, contract `E-3`)
|
||||
- `MV1-PASS-REFUSAL-001` (well-formed refusal proof passes)
|
||||
|
||||
## B) “Can you detect tampering and incomplete evidence?”
|
||||
|
||||
### B4. Missing required files fail loudly
|
||||
Question: If required artifacts are missing, does verification fail loudly with contract IDs?
|
||||
|
||||
Evidence:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-SEAL-001.record.json`
|
||||
|
||||
Pass condition:
|
||||
- Non-zero exit; `failure_code=E_MISSING_REQUIRED_FILE`; `violated_contract_ids` includes `B-1`.
|
||||
|
||||
Test coverage:
|
||||
- `MV1-FAIL-SEAL-001`
|
||||
|
||||
### B5. Manifest mismatch is detected
|
||||
Question: If the integrity manifest hash is altered, do you catch it?
|
||||
|
||||
Evidence:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-SEAL-002.record.json`
|
||||
|
||||
Pass condition:
|
||||
- Fail with `E_MANIFEST_HASH_MISMATCH`; `violated_contract_ids` includes `I-3`.
|
||||
|
||||
Test coverage:
|
||||
- `MV1-FAIL-SEAL-002`
|
||||
|
||||
### B6. Root mismatch / range mismatch are detected
|
||||
Question: If the bundle claims the wrong root or ranges, do you catch it?
|
||||
|
||||
Evidence:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-SEAL-004.record.json`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-SEAL-005.record.json`
|
||||
|
||||
Pass condition:
|
||||
- Root mismatch ⇒ `E_ROOT_MISMATCH` with contract `E-5`
|
||||
- Range mismatch ⇒ `E_RANGE_MISMATCH` with contract `E-6`
|
||||
|
||||
Test coverage:
|
||||
- `MV1-FAIL-SEAL-004`
|
||||
- `MV1-FAIL-SEAL-005`
|
||||
|
||||
### B7. Bounded verification (oversize input rejected)
|
||||
Question: Is verification bounded so oversized inputs fail deterministically?
|
||||
|
||||
Evidence:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-SEAL-007.record.json`
|
||||
|
||||
Pass condition:
|
||||
- Fail with `E_OVERSIZE_INPUT`; contract `B-3`.
|
||||
|
||||
Test coverage:
|
||||
- `MV1-FAIL-SEAL-007`
|
||||
|
||||
## C) “Can you attribute actions and prevent unauthorized control?”
|
||||
|
||||
### C8. Revoked capability used is rejected
|
||||
Question: If a revoked capability is used, does verification fail with explicit attribution?
|
||||
|
||||
Evidence:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-CAP-001.record.json`
|
||||
|
||||
Pass condition:
|
||||
- Fail with `E_REVOKED_CAPABILITY_USED`; contract `E-7`.
|
||||
|
||||
Test coverage:
|
||||
- `MV1-FAIL-CAP-001`
|
||||
|
||||
### C9. Replay / ordering attacks are rejected
|
||||
Question: Do you prevent replay or ordering attacks (non-monotonic sequences)?
|
||||
|
||||
Evidence:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-EVENT-005.record.json`
|
||||
|
||||
Pass condition:
|
||||
- Fail with `E_SEQ_NON_MONOTONIC`; contract `E-4`.
|
||||
|
||||
Test coverage:
|
||||
- `MV1-FAIL-EVENT-005`
|
||||
|
||||
## D) “Can you prove integrity of each event?”
|
||||
|
||||
### D10. Event hash integrity is enforced
|
||||
Question: Is `event_hash` enforced as `H(canonical(event_without_event_hash))`?
|
||||
|
||||
Evidence:
|
||||
- Fixture alias (explicit path): `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/fixtures/fail/E_EVENT_HASH_MISMATCH/`
|
||||
- Suite record: `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-EVENT-001.record.json`
|
||||
|
||||
How to answer (explicit run):
|
||||
```bash
|
||||
python3 vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py \
|
||||
--bundle vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/fixtures/fail/E_EVENT_HASH_MISMATCH \
|
||||
--strict
|
||||
```
|
||||
|
||||
Pass condition:
|
||||
- Fail with `E_EVENT_HASH_MISMATCH`
|
||||
- `violated_contract_ids` contains `E-2`
|
||||
|
||||
Test coverage:
|
||||
- `MV1-FAIL-EVENT-001`
|
||||
|
||||
### D11. op_digest and prev_event_hash chain are enforced
|
||||
Question: Are `op_digest` and the `prev_event_hash` chain integrity enforced?
|
||||
|
||||
Evidence:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-EVENT-002.record.json`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-EVENT-003.record.json`
|
||||
|
||||
Pass condition:
|
||||
- op_digest mismatch ⇒ `E_EVENT_HASH_MISMATCH` with contract `E-2`
|
||||
- prev_event_hash mismatch ⇒ `E_CHAIN_DISCONTINUITY` with contract `E-3`
|
||||
|
||||
Test coverage:
|
||||
- `MV1-FAIL-EVENT-002`
|
||||
- `MV1-FAIL-EVENT-003`
|
||||
|
||||
### D12. Schema and canonicalization versioning are enforced
|
||||
Question: Do you hard-fail invalid schema inputs and unsupported canonicalization versions?
|
||||
|
||||
Evidence:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-EVENT-004.record.json`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/MV1-FAIL-SEAL-006.record.json`
|
||||
|
||||
Pass condition:
|
||||
- Invalid JSONL/schema ⇒ `E_SCHEMA_INVALID` with contract `E-1`
|
||||
- Unsupported canonicalization ⇒ `E_CANON_VERSION_UNSUPPORTED` with contract `S-6`
|
||||
|
||||
Test coverage:
|
||||
- `MV1-FAIL-EVENT-004`
|
||||
- `MV1-FAIL-SEAL-006`
|
||||
|
||||
## E) “Is this enforceable continuously, not just in a PDF?”
|
||||
|
||||
### E13. Build-blocking conformance
|
||||
Question: Does CI fail if expected contract IDs drift or exit codes change?
|
||||
|
||||
Evidence:
|
||||
- CI job: `vaultmesh-orgine-mobile/.gitlab-ci.yml` (`meridian-v1-conformance`)
|
||||
- Suite actuator: `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/run.sh`
|
||||
- Suite report: `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/report.json`
|
||||
|
||||
Pass condition:
|
||||
- Any drift ⇒ non-zero suite exit ⇒ CI job fails
|
||||
|
||||
### E14. Failure codes are stable and documented (no proprietary drift)
|
||||
Question: Are failure codes stable, documented, and parity-gated?
|
||||
|
||||
Evidence:
|
||||
- Source of truth: `vaultmesh-orgine-mobile/tools/sentinel_failure_codes.py`
|
||||
- Semantics: `vaultmesh-orgine-mobile/spec/SENTINEL_FAILURE_CODE_SEMANTICS.md`
|
||||
- Parity gate: `vaultmesh-orgine-mobile/tools/check_sentinel_contract_parity.py`
|
||||
|
||||
Pass condition:
|
||||
- `python3 vaultmesh-orgine-mobile/tools/check_sentinel_contract_parity.py` prints `[OK] …`
|
||||
|
||||
## Annex A — Test coverage map (authoritative)
|
||||
|
||||
The authoritative mapping lives in:
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/manifest.yaml`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/report.json`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/*.record.json`
|
||||
|
||||
Quick mapping (question → tests):
|
||||
- A1: `MV1-PASS-REFUSAL-001`, `MV1-PASS-OFFLINE-001`
|
||||
- A2: `MV1-PASS-REFUSAL-001`, `MV1-FAIL-SEAL-004`
|
||||
- A3: `MV1-FAIL-REFUSAL-001`, `MV1-FAIL-REFUSAL-002`, `MV1-FAIL-REFUSAL-003`, `MV1-PASS-REFUSAL-001`
|
||||
- B4: `MV1-FAIL-SEAL-001`
|
||||
- B5: `MV1-FAIL-SEAL-002`
|
||||
- B6: `MV1-FAIL-SEAL-004`, `MV1-FAIL-SEAL-005`
|
||||
- B7: `MV1-FAIL-SEAL-007`
|
||||
- C8: `MV1-FAIL-CAP-001`
|
||||
- C9: `MV1-FAIL-EVENT-005`
|
||||
- D10: `MV1-FAIL-EVENT-001`
|
||||
- D11: `MV1-FAIL-EVENT-002`, `MV1-FAIL-EVENT-003`
|
||||
- D12: `MV1-FAIL-EVENT-004`, `MV1-FAIL-SEAL-006`
|
||||
- E13: `meridian-v1-conformance` CI job + suite exit behavior
|
||||
- E14: parity gate + semantics doc
|
||||
|
||||
## Annex B — Evidence packet (what to request; what to run)
|
||||
|
||||
Minimum “evidence packet” contents (offline runnable):
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/report.json`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/report.txt`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/out/tests/`
|
||||
- `vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/fixtures/`
|
||||
- `vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py`
|
||||
- `vaultmesh-orgine-mobile/tools/sentinel_failure_codes.py`
|
||||
|
||||
Optional (human-readable contract references):
|
||||
- `vaultmesh-orgine-mobile/spec/SENTINEL_V1_CONTRACT_MATRIX.md`
|
||||
- `vaultmesh-orgine-mobile/spec/SENTINEL_FAILURE_CODE_SEMANTICS.md`
|
||||
|
||||
Verifier run (auditor entrypoint):
|
||||
```bash
|
||||
python3 vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py --bundle <bundle_dir> --strict
|
||||
```
|
||||
|
||||
Suite run (answer all questions at once):
|
||||
```bash
|
||||
bash vaultmesh-orgine-mobile/MERIDIAN_V1_CONFORMANCE_TEST_SUITE/run.sh
|
||||
```
|
||||
|
||||
60-second interpretation:
|
||||
- Open `out/report.json` and confirm `counts.failed == 0`.
|
||||
- For any question, open the referenced `out/tests/<TEST_ID>.record.json` and compare `expected` vs `observed`.
|
||||
|
||||
41
spec/SENTINEL_EVIDENCE_STANDARD.md
Normal file
41
spec/SENTINEL_EVIDENCE_STANDARD.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Sentinel Evidence Standard v1
|
||||
|
||||
Status: Draft (implementation-oriented)
|
||||
Scope: VaultMesh Sentinel v1 offline-verifiable evidence artifacts
|
||||
|
||||
## 1) What “evidence” means here
|
||||
|
||||
Evidence is a **portable, offline-verifiable artifact set** that allows an auditor to deterministically verify:
|
||||
- what happened (`action_executed`)
|
||||
- what was attempted (`action_intent`)
|
||||
- what was denied (`shadow_receipt`)
|
||||
- and whether the history was tampered with (`prev_event_hash` + roots + integrity digests)
|
||||
|
||||
## 2) Required artifact set (seal bundle)
|
||||
|
||||
A seal bundle is the canonical evidence package. At minimum it contains:
|
||||
- `seal.json`
|
||||
- `integrity.json`
|
||||
- `verifier_manifest.json`
|
||||
- `receipts.jsonl` (or declared ledger export)
|
||||
- `roots.txt`
|
||||
|
||||
## 3) Cryptographic defaults (v1)
|
||||
|
||||
- Signing: Ed25519 (where signatures are used; v1 verifier does not require a seal signature)
|
||||
- Hashing: `blake3` **or** `sha256` (declared in artifacts; verifier MUST respect the declared `hash_algo`)
|
||||
- Canonicalization: pinned by `canonicalization_version` and enforced by the verifier
|
||||
|
||||
## 4) Verification entrypoints (offline)
|
||||
|
||||
Single bundle:
|
||||
- `python3 vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py --bundle vaultmesh-orgine-mobile/testvectors/sentinel/black-box-that-refused --strict`
|
||||
|
||||
All testvectors (includes determinism check):
|
||||
- `bash vaultmesh-orgine-mobile/tools/run_sentinel_testvectors.sh`
|
||||
|
||||
## 5) Failure codes are contractual
|
||||
|
||||
Failure codes are stable and must not be reused across meanings:
|
||||
- Source of truth: `vaultmesh-orgine-mobile/tools/sentinel_failure_codes.py`
|
||||
|
||||
43
spec/SENTINEL_FAILURE_CODE_SEMANTICS.md
Normal file
43
spec/SENTINEL_FAILURE_CODE_SEMANTICS.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Sentinel Failure & Warning Code Semantics (v1)
|
||||
|
||||
Status: Canonical (protocol surface)
|
||||
|
||||
Source of truth: `vaultmesh-orgine-mobile/tools/sentinel_failure_codes.py`
|
||||
|
||||
This document freezes the meaning of `failure_code` / `warning` codes emitted by the Sentinel v1 offline verifier(s). Codes are intended to be stable identifiers for automation, audits, and long-term tooling.
|
||||
|
||||
## Stability Rules
|
||||
|
||||
- Codes MUST NOT be reused. If meaning must change, add a new code and deprecate the old one.
|
||||
- Codes MUST have stable semantics across verifier implementations.
|
||||
- Verifiers MUST emit only codes defined in `vaultmesh-orgine-mobile/tools/sentinel_failure_codes.py`.
|
||||
- Reports SHOULD include `contract_ids` / `violated_contract_ids` to bind findings to the Contract Matrix.
|
||||
|
||||
## Severity Model
|
||||
|
||||
- `E_*` = verification FAIL (non-zero exit; bundle is not accepted as correct evidence).
|
||||
- `W_*` = verification WARNING (bundle may PASS). In `--strict` mode, verifiers MAY elevate some `W_*` conditions into `E_*` failures (documented per-code below).
|
||||
|
||||
## Failure Codes (`E_*`)
|
||||
|
||||
| Code | Meaning (stable) | Typical Triggers | Remediation / Next Actions |
|
||||
| --- | --- | --- | --- |
|
||||
| `E_SCHEMA_INVALID` | Any required schema/format/cross-field validation fails, or required JSON cannot be parsed. | Invalid JSONL line; missing required field; unknown `format`; inconsistent manifest fields. | Re-export the bundle from a known-good producer; verify older seals; treat as corruption/tamper evidence if produced artifacts are expected to be immutable. |
|
||||
| `E_MISSING_REQUIRED_FILE` | A required file is missing from the bundle (or referenced but absent). | `seal.json` missing; `seal.json.files.*` points to absent paths; integrity lists missing file. | Restore the missing artifact from redundancy/WORM copy; re-export the seal; verify an older seal bundle that includes the missing file(s). |
|
||||
| `E_MANIFEST_HASH_MISMATCH` | A file’s computed digest does not match `integrity.json`. | One-bit flip / truncation; tampering; wrong `hash_algo` used for verification. | Treat as high-confidence tamper/corruption evidence; restore from a known-good copy; compare against earlier seals / out-of-band copies. |
|
||||
| `E_OVERSIZE_INPUT` | A bundle input exceeds configured maximum bytes (defense against decompression bombs / giant files). | Abnormally large receipts; attacker-supplied oversized file; misconfigured exporter. | Re-export with bounded payload/chunking; raise size limits only with explicit operational override and strong justification. |
|
||||
| `E_EVENT_HASH_MISMATCH` | `event_hash` does not match recomputation from canonical bytes (with `event_hash` omitted). | Event field mutation; canonicalization drift; wrong `hash_algo`; corruption. | Confirm `canonicalization_version` + `hash_algo`; re-export from canonical source; treat persistent mismatch as tamper evidence. |
|
||||
| `E_CHAIN_DISCONTINUITY` | `prev_event_hash` chain breaks (tamper/reorder/rollback evidence) or strict linkage invariants fail. | Missing `prev_event_hash`; chain fork; execution without intent; intent without outcome (strict). | Verify earlier bundles; compare to independent copies; treat as rollback/reorder evidence; restore from last-known-good continuity point. |
|
||||
| `E_SEQ_NON_MONOTONIC` | Duplicate, missing, or non-monotonic `seq` values in the covered range. | Truncation; rollback; forked history; corrupted append order. | Treat as rollback/corruption evidence; restore from earlier seal; reconstruct from raw receipts if available. |
|
||||
| `E_RANGE_MISMATCH` | Seal declares a range that does not match included events/roots. | `seal.json.range` inconsistent with receipts; `roots.txt` last seq mismatch. | Re-export the seal with correct range; ensure exporter includes complete receipts for the declared range. |
|
||||
| `E_CANON_VERSION_UNSUPPORTED` | Declared `canonicalization_version` is unknown/unsupported by this verifier. | Newer producer; older verifier; incompatible artifact set. | Use an updated verifier that supports the declared version; keep N-2 verifier compatibility policy enforced. |
|
||||
| `E_ROOT_MISMATCH` | Recomputed Merkle end root does not match declared/observed root. | Tampering; missing continuation state (strict); wrong hash algorithm; inconsistent leaf definition. | Confirm `hash_algo` and leaf definition; restore missing continuation state (eg. frontier snapshot) or verify a genesis-range seal; treat persistent mismatch as tamper evidence. |
|
||||
| `E_REVOKED_CAPABILITY_USED` | A revoked capability is used after revoke (violates “revocation is authoritative”). | `action_executed` references `cap_hash` after `cap_revoke`. | Treat as compromise/violation of authority semantics; investigate actor systems; rotate keys/caps; ensure future actions are denied + recorded via `shadow_receipt`. |
|
||||
|
||||
## Warning Codes (`W_*`)
|
||||
|
||||
| Code | Meaning (stable) | Typical Triggers | Strict Mode Behavior | Remediation / Next Actions |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `W_FILE_NOT_IN_MANIFEST` | A file exists in the bundle but is not listed in `integrity.json` (or recommended files like `seal.json` are not covered). | Extra stray files; incomplete integrity manifest; accidental artifacts (eg. `.DS_Store`). | MAY be elevated to `E_SCHEMA_INVALID` (fail-closed) depending on verifier policy. | Either add the file to `integrity.json` (preferred) or remove it from the bundle; ensure exporters generate complete integrity manifests. |
|
||||
| `W_RANGE_ROOT_PARTIAL` | Verifier cannot fully verify roots/chain due to missing prior context (non-genesis range). | `since_seq > 0`; first event is not `seq=0`. | MAY be elevated to `E_CHAIN_DISCONTINUITY` or `E_ROOT_MISMATCH` depending on verifier policy. | Provide verifiable continuation state (frontier snapshot) or export a seal that starts at `seq=0`; accept reduced assurance only intentionally (non-strict). |
|
||||
|
||||
225
spec/SENTINEL_OFFLINE_VERIFIER_REQUIREMENTS.md
Normal file
225
spec/SENTINEL_OFFLINE_VERIFIER_REQUIREMENTS.md
Normal file
@@ -0,0 +1,225 @@
|
||||
# Sentinel v1 Offline Verifier Requirements
|
||||
|
||||
Artifact: `vaultmesh-orgine-mobile/spec/SENTINEL_OFFLINE_VERIFIER_REQUIREMENTS.md`
|
||||
Purpose: Verify Sentinel evidence without network, without secrets, without the original runtime, using only exported artifacts.
|
||||
|
||||
---
|
||||
|
||||
## 0) Inputs
|
||||
|
||||
Verifier accepts either:
|
||||
- a Seal Bundle directory (recommended), or
|
||||
- a raw artifact directory (receipts + roots + integrity + manifest)
|
||||
|
||||
Required files (seal bundle mode):
|
||||
- `seal.json`
|
||||
- `integrity.json`
|
||||
- `verifier_manifest.json`
|
||||
- one or more receipt/event files (JSONL or sqlite export, as declared by seal)
|
||||
- root history file(s) as declared by seal
|
||||
|
||||
---
|
||||
|
||||
## 1) Outputs
|
||||
|
||||
Verifier MUST produce:
|
||||
- PASS or FAIL
|
||||
- deterministic error codes + human-readable explanations
|
||||
- a machine-readable `verification_report.json` containing:
|
||||
- verified ranges
|
||||
- computed roots
|
||||
- observed roots (from artifacts)
|
||||
- mismatches
|
||||
- corruption findings
|
||||
- toolchain / schema versions used
|
||||
- `failure_code` (or null)
|
||||
|
||||
---
|
||||
|
||||
## 2) Trust Model
|
||||
|
||||
- No trust in the producer.
|
||||
- No trust in timestamps.
|
||||
- No trust in filesystem ordering.
|
||||
- Only trust:
|
||||
- schemas & canonicalization rules
|
||||
- cryptographic hashes
|
||||
- deterministic computation
|
||||
|
||||
---
|
||||
|
||||
## 3) Verification Phases (MUST implement all)
|
||||
|
||||
### Phase A — Manifest & Schema Validation
|
||||
|
||||
**A1. Schema validate**
|
||||
- Validate `seal.json`, `integrity.json`, `verifier_manifest.json`, and each event against their schemas.
|
||||
|
||||
Fail if:
|
||||
- missing required fields
|
||||
- unknown schema version without explicit compatibility support
|
||||
- canonicalization version missing or unsupported
|
||||
|
||||
**A2. Canonicalization version pin**
|
||||
- Verifier MUST enforce `canonicalization_version` from `seal.json` / manifest.
|
||||
- If multiple are present, they MUST match.
|
||||
|
||||
---
|
||||
|
||||
### Phase B — Integrity Manifest Verification
|
||||
|
||||
**B1. File hash verification**
|
||||
- For every file listed in `integrity.json`, compute its hash and compare.
|
||||
|
||||
Fail if:
|
||||
- any hash mismatch (hard fail)
|
||||
- any required file missing (hard fail)
|
||||
- any file present but not listed (soft fail or warning; policy configurable)
|
||||
|
||||
**B2. Size & bounds checks**
|
||||
- Enforce max file sizes (configurable) to prevent decompression bombs / giant inputs.
|
||||
|
||||
Fail if:
|
||||
- size exceeds limits without explicit override
|
||||
|
||||
---
|
||||
|
||||
### Phase C — Event Canonicalization & Hashing
|
||||
|
||||
**C1. Canonicalize every event**
|
||||
- Convert each event into canonical bytes per `canonicalization.md`.
|
||||
|
||||
**C2. Compute `event_hash`**
|
||||
- Compute `event_hash = H(canonical_event_bytes)`.
|
||||
|
||||
Fail if:
|
||||
- event has `event_hash` and it does not match recomputed hash
|
||||
- event has no `event_hash` AND v1 policy requires it (recommended hardening)
|
||||
|
||||
**C3. Compute `op_digest`**
|
||||
- Verify `op_digest` matches canonicalized operation descriptor/params.
|
||||
|
||||
Fail if:
|
||||
- `op_digest` mismatch
|
||||
|
||||
---
|
||||
|
||||
### Phase D — Chain Verification (Tamper / Rollback Detection)
|
||||
|
||||
**D1. `prev_event_hash` chain**
|
||||
- For each event in strict `seq` order:
|
||||
- verify `event.prev_event_hash == previous.event_hash`
|
||||
|
||||
Fail if:
|
||||
- missing `seq` values
|
||||
- duplicate `seq` values
|
||||
- non-monotonic `seq`
|
||||
- chain discontinuity
|
||||
- chain fork (two events with same `seq`)
|
||||
|
||||
**D2. Trace linkage integrity (optional but recommended)**
|
||||
- Where `trace_id` exists, verify that:
|
||||
- `action_intent` exists before `action_executed`
|
||||
- If no `action_executed`, then `shadow_receipt` exists (policy may require)
|
||||
|
||||
Fail if (strict mode):
|
||||
- execution without intent
|
||||
- denial without shadow receipt (unless explicitly allowed as “impossible-to-write”)
|
||||
|
||||
---
|
||||
|
||||
### Phase E — Merkle Root Verification
|
||||
|
||||
**E1. Leaf definition**
|
||||
- Leaf = hash(`event_hash` OR canonical_event_bytes) as specified. Must be consistent with spec.
|
||||
|
||||
**E2. Root recomputation**
|
||||
- Recompute roots for the receipt range in the seal.
|
||||
|
||||
Fail if:
|
||||
- computed end root != `seal.json.end_root`
|
||||
- root history continuity breaks (start root mismatch where applicable)
|
||||
|
||||
**E3. Root timestamp is non-authoritative**
|
||||
- `ts` can be displayed but never treated as security-critical.
|
||||
|
||||
---
|
||||
|
||||
### Phase F — Seal Verification
|
||||
|
||||
**F1. Seal self-consistency**
|
||||
- seal range aligns with included receipts
|
||||
- seal declares expected roots correctly
|
||||
- integrity manifest covers all seal files
|
||||
|
||||
Fail if:
|
||||
- declared range doesn’t match included data
|
||||
- missing roots or receipts required for the range
|
||||
|
||||
**F2. Optional seal signature (future)**
|
||||
- v1 may omit cryptographic signature; if present, verify it.
|
||||
|
||||
---
|
||||
|
||||
## 4) Failure Classes & Codes (Required)
|
||||
|
||||
Verifier must map failures to stable codes:
|
||||
- `E_SCHEMA_INVALID`
|
||||
- `E_MANIFEST_HASH_MISMATCH`
|
||||
- `E_MISSING_REQUIRED_FILE`
|
||||
- `E_EVENT_HASH_MISMATCH`
|
||||
- `E_CHAIN_DISCONTINUITY`
|
||||
- `E_SEQ_NON_MONOTONIC`
|
||||
- `E_ROOT_MISMATCH`
|
||||
- `E_RANGE_MISMATCH`
|
||||
- `E_CANON_VERSION_UNSUPPORTED`
|
||||
- `E_OVERSIZE_INPUT`
|
||||
- `E_REVOKED_CAPABILITY_USED`
|
||||
|
||||
This is what makes audits repeatable.
|
||||
|
||||
---
|
||||
|
||||
## 5) Corruption Handling Requirements
|
||||
|
||||
If verifier detects:
|
||||
- malformed JSONL segments
|
||||
- partial file reads
|
||||
- decode errors
|
||||
|
||||
It MUST:
|
||||
- produce FAIL (unless “best-effort mode” is explicitly requested)
|
||||
- report:
|
||||
- last good `seq`
|
||||
- affected byte ranges (if possible)
|
||||
- last valid root
|
||||
- recommend recovery path:
|
||||
- verify older seal bundle
|
||||
- restore from WORM copy
|
||||
- compare to out-of-band seal digest
|
||||
|
||||
---
|
||||
|
||||
## 6) Determinism Requirements
|
||||
|
||||
Given identical inputs, verifier output must be byte-identical (except wallclock runtime fields).
|
||||
- deterministic ordering rules (sort by `seq`, not file order)
|
||||
- deterministic JSON serialization for reports (stable key order)
|
||||
|
||||
---
|
||||
|
||||
## 7) CLI Interface (Minimum)
|
||||
|
||||
- `sentinel verify --bundle <path> [--strict] [--report <out.json>]`
|
||||
- `sentinel verify --artifacts <dir> --range <since..until>`
|
||||
- `sentinel compute-roots --events <events.jsonl>`
|
||||
|
||||
---
|
||||
|
||||
## 8) Definition of Done
|
||||
|
||||
Verifier is “v1 complete” when it passes these drills:
|
||||
1. Cold archaeology restore
|
||||
2. Denial proof drill
|
||||
3. Corruption drill
|
||||
4. Rollback attempt detection drill
|
||||
137
spec/SENTINEL_V1_CONTRACT_MATRIX.md
Normal file
137
spec/SENTINEL_V1_CONTRACT_MATRIX.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# Sentinel v1 Contract Matrix
|
||||
|
||||
Purpose: Define what must be recorded, by whom, when, and what the verifier must enforce.
|
||||
|
||||
Legend:
|
||||
- Emitter: system responsible for writing the event
|
||||
- Trigger: when the event must be emitted
|
||||
- Hard rule: verifier MUST fail if violated
|
||||
- Soft rule: verifier MAY warn/fail in strict mode
|
||||
|
||||
---
|
||||
|
||||
## 0) Bundle & Schema Contracts (Seal Bundle)
|
||||
|
||||
| Contract ID | Invariant | Evidence Artifact(s) | Verifier Enforcement | Failure Codes |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `B-1` | Bundle MUST contain `seal.json`, `integrity.json`, `verifier_manifest.json`, plus the paths referenced by `seal.json.files.*`. | `seal.json` | File presence checks in `vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py:557`. | `E_MISSING_REQUIRED_FILE`, `E_SCHEMA_INVALID` |
|
||||
| `B-2` | Bundle MUST be offline-verifiable (no network assumptions). | Entire bundle | Verifier MUST rely only on bundle bytes; no network calls are permitted by design. | `E_MISSING_REQUIRED_FILE`, `E_SCHEMA_INVALID` (derived from missing/incomplete artifacts) |
|
||||
|
||||
### `seal.json` (vm-sentinel-seal-v1)
|
||||
|
||||
| Contract ID | Invariant | Evidence Artifact(s) | Verifier Enforcement | Failure Codes |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `S-1` | `seal.json.format` MUST equal `vm-sentinel-seal-v1`. | `seal.json` | Format allowlist check in `vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py:594`. | `E_SCHEMA_INVALID` |
|
||||
| `S-2` | `seal.json.hash_algo` MUST be `blake3` or `sha256`. | `seal.json` | `hash_algo` validation in `vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py:604`. | `E_SCHEMA_INVALID` |
|
||||
| `S-3` | Seal MUST declare a sequence range (`since_seq`, `until_seq`). | `seal.json.range` | Schema validation in `vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py:582`. | `E_SCHEMA_INVALID` |
|
||||
| `S-4` | Seal MUST declare `root.start` and `root.end`. | `seal.json.root` | Schema validation in `vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py:582`. | `E_SCHEMA_INVALID` |
|
||||
| `S-5` | Seal MUST point to receipts/roots/integrity/verifier_manifest files (and they must exist in the bundle). | `seal.json.files.*` | Path resolution + existence checks in `vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py:640`. | `E_MISSING_REQUIRED_FILE`, `E_SCHEMA_INVALID` |
|
||||
|
||||
### `integrity.json` (vm-sentinel-integrity-v1)
|
||||
|
||||
| Contract ID | Invariant | Evidence Artifact(s) | Verifier Enforcement | Failure Codes |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `I-1` | `integrity.json.format` MUST equal `vm-sentinel-integrity-v1`. | `integrity.json` | Format allowlist check in `vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py:689`. | `E_SCHEMA_INVALID` |
|
||||
| `I-2` | `integrity.json.hash_algo` MUST match `seal.json.hash_algo`. | `integrity.json`, `seal.json` | Cross-check in `vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py:697`. | `E_SCHEMA_INVALID` |
|
||||
| `I-3` | Each listed file MUST have `path` + `digest`, and the digest MUST match. | `integrity.json.files[]` | Digest recomputation + compare in `vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py:766`. | `E_MANIFEST_HASH_MISMATCH`, `E_SCHEMA_INVALID`, `E_MISSING_REQUIRED_FILE` |
|
||||
| `I-4` | If `size_bytes` is present, it MUST match file size. | `integrity.json.files[].size_bytes` | Size check in `vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py:822`. | `E_SCHEMA_INVALID` |
|
||||
|
||||
### `verifier_manifest.json` (vm-sentinel-verifier-manifest-v1)
|
||||
|
||||
| Contract ID | Invariant | Evidence Artifact(s) | Verifier Enforcement | Failure Codes |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `V-1` | `verifier_manifest.json.format` MUST equal `vm-sentinel-verifier-manifest-v1`. | `verifier_manifest.json` | Format allowlist check in `vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py:874`. | `E_SCHEMA_INVALID` |
|
||||
| `V-2` | MUST declare `sentinel_version`, `schema_version`, `canonicalization_version`. | `verifier_manifest.json` | Schema validation in `vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py:866`. | `E_SCHEMA_INVALID` |
|
||||
| `V-3` | If `hash_algo` is present, it MUST match `seal.json.hash_algo`. | `verifier_manifest.json`, `seal.json` | Cross-check in `vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py:898`. | `E_SCHEMA_INVALID` |
|
||||
| `V-4` | `verifier` object MAY include `name/version/sha256`; if present, include it in reports. | `verifier_manifest.json` | Report inclusion in `vaultmesh-orgine-mobile/tools/vm_verify_sentinel_bundle.py:912`. | N/A |
|
||||
|
||||
## A) Action Lifecycle Events (Intent → Decision → Outcome)
|
||||
|
||||
| Event Type | Emitter | Trigger | Required Fields (minimum) | Hard Verification Rules |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `action_intent` | Actor system (Cloudflare ops / guardian / CLI / RTOS host) | Before any attempt to execute an operation | `seq`, `ts`, `event_type`, `actor`, `op`, `op_digest`, `trace_id`, `cap_hash`, `prev_event_hash`, `event_hash` | No execution without prior intent: Every `action_executed` must reference a prior `action_intent` with same `trace_id`. |
|
||||
| `policy_decision` (recommended v1; can be embedded in intent `payload` to keep schema lean) | Policy engine (Layer0/classifier) | After intent, before allow/deny | `seq`, `ts`, `actor`, `trace_id`, `op_digest`, `result` (`allow`/`deny`), `payload.reason_code`, `payload.classification`, `prev_event_hash` | Policy recording: if system claims policy enforcement, then every allow/deny must have a recorded decision (either as this event or as a signed payload embedded in intent). |
|
||||
| `action_executed` | Actor system | Immediately after side-effect completes | `seq`, `ts`, `actor`, `trace_id`, `op_digest`, `result` (`ok`/`error`), `root_before`, `root_after`, `prev_event_hash`, `event_hash` | Must have matching prior `action_intent`. Must not exist if corresponding denial exists for same `trace_id` (no split reality). |
|
||||
| `shadow_receipt` | Sentinel core (or Actor if core is embedded) | On any denial (capability fail, policy deny, budget deny, degraded mode) | `seq`, `ts`, `actor`, `trace_id`, `op_digest`, `result` (`deny`), `payload.reason_code`, `payload.side_effects="none"`, `prev_event_hash`, `event_hash` | No silent denial: if an intent does not lead to `action_executed`, there must be a `shadow_receipt` unless explicitly marked “write-impossible” (rare). Shadow receipts must assert `side_effects="none"`. |
|
||||
|
||||
Notes:
|
||||
- If you want to avoid a separate `policy_decision` event, put the decision in `action_intent.payload.policy` and require it to be present when `result != "unknown"`.
|
||||
|
||||
---
|
||||
|
||||
## B) Trust / Authority Events (Capabilities)
|
||||
|
||||
| Event Type | Emitter | Trigger | Required Fields | Hard Verification Rules |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `cap_grant` | Authority issuer (operator tool / provisioning process) | When a capability is created/issued | `seq`, `ts`, `actor` (issuer), `payload.capability_json`, `cap_hash`, `prev_event_hash` | Capability used later must hash to a previously granted token OR be in a pinned trust root (bootstrap). |
|
||||
| `cap_revoke` | Authority issuer | When revoking capability | `seq`, `ts`, `actor`, `payload.revoked_cap_hash`, `payload.reason_code`, `prev_event_hash` | Revocation is authoritative: any subsequent event with `cap_hash` matching a revoked one MUST be denied (`shadow_receipt` with reason revoked). |
|
||||
| `cap_use` (optional; can be derived) | Sentinel core | Whenever a capability is presented | `seq`, `ts`, `actor`, `cap_hash`, `trace_id`, `prev_event_hash` | If enabled, must correlate to `action_intent/trace_id`. Not required if you already store `cap_hash` on intent/outcome. |
|
||||
|
||||
---
|
||||
|
||||
## C) Root & Sealing Events (Time Compression / Witness Bundles)
|
||||
|
||||
| Event Type | Emitter | Trigger | Required Fields | Hard Verification Rules |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `root_published` | Sentinel core | After appending N events or T time window | `seq`, `ts`, `payload.root_hex`, `payload.coverage_seq`, `prev_event_hash` | Root must match recomputation over all events up to `coverage_seq`. Root determinism required. |
|
||||
| `seal_created` | Sentinel core | On schedule OR on tamper/corruption OR on manual request | `seq`, `ts`, `payload.seal_id`, `payload.range_since`, `payload.range_until`, `payload.end_root`, `payload.canonicalization_version`, `prev_event_hash` | Seal must be verifiable offline: receipts + roots + integrity manifest present. Seal completeness is a hard requirement. |
|
||||
|
||||
---
|
||||
|
||||
## D) Integrity / Tamper / Degradation Events (Hostile Reality)
|
||||
|
||||
| Event Type | Emitter | Trigger | Required Fields | Hard Verification Rules |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `tamper_signal` | Hardware/host sensor adapter → recorded by Sentinel | Unexpected power cycle, clock jump, enclosure open, seizure sensor | `seq`, `ts`, `payload.kind`, `payload.sensor_digest`, `payload.severity`, `prev_event_hash` | Presence of tamper signals must tighten policy: subsequent high-risk ops should be denied or require stronger caps (enforced in policy rules; verifier can check if policy recorded). |
|
||||
| `corruption_detected` | Storage layer / Sentinel core | On detection of checksum/page/parse failure | `seq`, `ts`, `payload.affected_ranges`, `payload.last_good_seq`, `payload.last_good_root`, `prev_event_hash` | No silent data loss: corruption must be recorded. Recommended: must trigger immediate `seal_created` if possible (strict mode can enforce). |
|
||||
| `boot_event` | Sentinel core | On startup | `seq`, `ts`, `payload.version`, `payload.schema_version`, `payload.hash_algo`, `prev_event_hash` | Boot events should be monotonic across sessions; verifier can warn if missing across long ranges. |
|
||||
|
||||
---
|
||||
|
||||
## E) Minimal Verifier Rules (Derived from Matrix)
|
||||
|
||||
Hard fails (always):
|
||||
1. Schema invalid for any required file/event → `E_SCHEMA_INVALID`
|
||||
2. `seq` non-monotonic / duplicate / missing in covered range → `E_SEQ_NON_MONOTONIC`
|
||||
3. `prev_event_hash` chain discontinuity → `E_CHAIN_DISCONTINUITY`
|
||||
4. Root mismatch for declared coverage → `E_ROOT_MISMATCH`
|
||||
5. Seal missing required artifacts (receipts + roots + integrity + verifier manifest) → `E_MISSING_REQUIRED_FILE`, `E_SCHEMA_INVALID`
|
||||
6. Revoked capability used without denial → `E_REVOKED_CAPABILITY_USED`
|
||||
|
||||
Strict-mode fails (recommended):
|
||||
7. Missing `shadow_receipt` where intent didn’t execute
|
||||
8. Corruption without subsequent seal (when seal could be created)
|
||||
9. Policy enforcement claim without recorded policy decision
|
||||
|
||||
---
|
||||
|
||||
## F) Boundary Rules (encoded)
|
||||
|
||||
- Actor Replaceability: actor systems can change; evidence format cannot.
|
||||
- Policy Recording: decisions go into receipts.
|
||||
- Tamper Evidence: tamper events must exist for power/clock anomalies.
|
||||
- Export Redundancy: portable artifacts exist independent of runtime.
|
||||
- Verifier Independence: no network/secrets required.
|
||||
- Version Compatibility: verifier supports N-2.
|
||||
|
||||
---
|
||||
|
||||
## G) Failure Code Map (v1)
|
||||
|
||||
Source of truth: `vaultmesh-orgine-mobile/tools/sentinel_failure_codes.py`
|
||||
|
||||
- `E_SCHEMA_INVALID`: Any required schema/format/cross-field validation fails.
|
||||
- `E_MISSING_REQUIRED_FILE`: A required file is missing from the bundle (or referenced but absent).
|
||||
- `E_MANIFEST_HASH_MISMATCH`: A file’s computed digest does not match `integrity.json`.
|
||||
- `E_OVERSIZE_INPUT`: Input exceeds configured maximum bytes.
|
||||
- `E_EVENT_HASH_MISMATCH`: `event_hash` does not match recomputation from canonical bytes.
|
||||
- `E_CHAIN_DISCONTINUITY`: `prev_event_hash` chain breaks (tamper/reorder/rollback evidence).
|
||||
- `E_SEQ_NON_MONOTONIC`: Duplicate, missing, or non-monotonic `seq` values.
|
||||
- `E_RANGE_MISMATCH`: Seal declares a range that does not match included events.
|
||||
- `E_CANON_VERSION_UNSUPPORTED`: Declared `canonicalization_version` is unknown/unsupported.
|
||||
- `E_ROOT_MISMATCH`: Recomputed Merkle end root does not match declared/observed root.
|
||||
- `E_REVOKED_CAPABILITY_USED`: A revoked capability is used after revoke without denial semantics.
|
||||
|
||||
Warnings (non-fatal unless strict-mode elevates):
|
||||
- `W_FILE_NOT_IN_MANIFEST`: A file exists in the bundle but is not listed in `integrity.json` (or recommended `seal.json` coverage is missing).
|
||||
- `W_RANGE_ROOT_PARTIAL`: Verifier cannot fully verify roots/chain due to missing prior context (eg. `since_seq > 0` without continuation state).
|
||||
340
spec/SENTINEL_V1_SPEC.md
Normal file
340
spec/SENTINEL_V1_SPEC.md
Normal file
@@ -0,0 +1,340 @@
|
||||
# VaultMesh Sentinel v1 Specification
|
||||
|
||||
Status: Draft v1 (implementation-oriented)
|
||||
Goal: A space/IoT-grade “forensic continuity core” that remains truthful under isolation, capture, corruption, and time.
|
||||
Non-goals: availability guarantees, global consensus, remote control plane, “SIEM replacement,” full workflow UI.
|
||||
|
||||
Non-goal clarification: Sentinel does not guarantee liveness or uptime under adversarial conditions. It guarantees detectability, attribution, and recoverable truth.
|
||||
|
||||
---
|
||||
|
||||
## 1) Sentinel v1 Operating Assumptions
|
||||
|
||||
- Correctness under isolation: Sentinel must remain verifiable with zero network for months/years.
|
||||
- Federation optional: peers are witness augmenters, never required for correctness.
|
||||
- Adversary present: assume capture, coercion, supply-chain drift, narrative pressure.
|
||||
- Truth > uptime: Sentinel may degrade functionality, but must not silently lie.
|
||||
|
||||
---
|
||||
|
||||
## 2) System Invariants
|
||||
|
||||
Sentinel is “correct” iff all invariants hold.
|
||||
|
||||
### I-1 Append-only evidence
|
||||
|
||||
- Evidence events are append-only and monotonic by sequence number.
|
||||
- Any truncation/rollback is detectable via root mismatch.
|
||||
|
||||
### I-2 Deterministic verification
|
||||
|
||||
- Given the same artifacts, verification must be deterministic across platforms.
|
||||
|
||||
### I-3 No silent denial
|
||||
|
||||
- If an operation is denied, a ShadowReceipt MUST be emitted (unless physically impossible).
|
||||
|
||||
### I-4 No authority amplification
|
||||
|
||||
- Automation and recovery actions may only narrow authority, never expand it.
|
||||
|
||||
### I-5 Corruption becomes evidence
|
||||
|
||||
- Storage corruption must emit CorruptionReceipt with scope of damage (pages/segments) and last known good root.
|
||||
|
||||
### I-6 Archaeology-first survivability
|
||||
|
||||
- A clean-room restore + verification must succeed using only exported artifacts + verifier.
|
||||
|
||||
---
|
||||
|
||||
## 3) Sentinel v1 Scope
|
||||
|
||||
### Included
|
||||
|
||||
- Evidence ledger (append-only receipts)
|
||||
- Roots (deterministic Merkle)
|
||||
- Seal bundles (portable witness packages)
|
||||
- ShadowReceipts (proof of restraint)
|
||||
- Minimal capability verification (scoped authority)
|
||||
- Corruption detection + reporting
|
||||
- Export + verification CLI
|
||||
|
||||
### Excluded (v1)
|
||||
|
||||
- Full federation sync
|
||||
- Cloud dashboards
|
||||
- Remote orchestration beyond export bundles
|
||||
- Complex policy engines (keep minimal)
|
||||
- On-chain anchoring required for correctness (optional)
|
||||
|
||||
---
|
||||
|
||||
## 4) Core Components
|
||||
|
||||
### 4.1 Receipt Ledger
|
||||
|
||||
Storage: single-file SQLite (preferred) OR append-only JSONL (fallback), but exported artifacts MUST be open and redundant.
|
||||
|
||||
Event types (minimum):
|
||||
- `action_intent` (attempt to perform operation)
|
||||
- `policy_decision` (recommended; record allow/deny reasoning, or embed in `action_intent.payload`)
|
||||
- `action_executed` (operation performed)
|
||||
- `shadow_receipt` (operation denied / restrained)
|
||||
- `cap_grant` / `cap_revoke`
|
||||
- `seal_created`
|
||||
- `root_published`
|
||||
- `corruption_detected`
|
||||
- `boot_event` (startup, version, schema hash)
|
||||
- `health_event` (periodic status, storage checks)
|
||||
|
||||
Fields (required per event):
|
||||
- `event_id` (uuid)
|
||||
- `seq` (u64 monotonic)
|
||||
- `ts` (monotonic + wallclock if available)
|
||||
- `event_type`
|
||||
- `actor` (capability subject / device identity)
|
||||
- `cap_hash` (hash of capability JSON or `"none"`)
|
||||
- `op` (operation name / canonical descriptor)
|
||||
- `op_digest` (hash of normalized op params)
|
||||
- `result` (`ok`/`deny`/`error`)
|
||||
- `root_before` / `root_after` (where applicable)
|
||||
- `trace_id` (correlates intent → outcome)
|
||||
- `prev_event_hash` (hash chain for quick tamper evidence)
|
||||
- `event_hash` (hash of canonical event bytes; verifiable)
|
||||
- `payload` (bounded JSON with strict schema)
|
||||
|
||||
Bounded payload rule: payload size must be capped (configurable), with overflow handled by chunking or external blob with hash reference.
|
||||
|
||||
### 4.2 Merkle Root Engine
|
||||
|
||||
- Maintain rolling Merkle root of receipt leaves (each leaf = hash(event_canonical_bytes)).
|
||||
- Support incremental updates O(log n).
|
||||
- Persist:
|
||||
- `ROOT.current.txt` (root + seq + timestamp)
|
||||
- `frontier.bin` (or equivalent) for fast restart
|
||||
- Deterministic canonicalization rules for event hashing.
|
||||
|
||||
Hash function: BLAKE3 (recommended) or SHA-256 (if platform constraints). Must be constant across builds.
|
||||
|
||||
### 4.3 Seal Bundles (Ouroboros Seals)
|
||||
|
||||
A seal is a portable, offline-verifiable “witness packet”.
|
||||
|
||||
Seal contents:
|
||||
- `seal.json` (metadata + root + ranges)
|
||||
- `receipts_range.jsonl` (or sqlite page range export)
|
||||
- `roots.txt` (root history for covered range)
|
||||
- `integrity.json` (hashes of included files)
|
||||
- `verifier_manifest.json` (expected tool versions & checksums)
|
||||
|
||||
Seal creation policy (v1 default):
|
||||
- Time-based (e.g., every 24h), OR
|
||||
- Event-based (N high-risk operations), OR
|
||||
- Tamper-signal triggered (see §6)
|
||||
|
||||
Seal cadence guidance (normative defaults; implementations MAY be stricter):
|
||||
- Max time window: 24h between seals while in NORMAL mode.
|
||||
- Max event window: 10,000 events between seals (configurable).
|
||||
- Mandatory seal triggers: any `tamper_signal` or `corruption_detected` event SHOULD attempt an immediate seal creation (unless physically impossible).
|
||||
|
||||
Seal verification must not require network.
|
||||
|
||||
### 4.4 Capabilities (Trust, killable)
|
||||
|
||||
Format: signed JSON capability tokens.
|
||||
|
||||
Fields:
|
||||
- `sub` (subject identity)
|
||||
- `scopes[]` (fine-grained)
|
||||
- `exp` (expiry)
|
||||
- `nbf` (not-before)
|
||||
- `aud` (sentinel instance id)
|
||||
- `jti` (token id)
|
||||
|
||||
Rules:
|
||||
- Deny if expired/invalid signature/wrong audience/revoked.
|
||||
- Revocation is additive evidence: emits `cap_revoke` receipt.
|
||||
- Emergency mode may narrow scopes only.
|
||||
|
||||
### 4.5 ShadowReceipts (Proof of Restraint)
|
||||
|
||||
Emitted when:
|
||||
- capability check fails
|
||||
- policy denies
|
||||
- budget insufficient (if using energy model)
|
||||
- unsafe context (tamper signals, degraded mode)
|
||||
|
||||
Minimum fields:
|
||||
- `reason_code` (enum)
|
||||
- `reason_text` (short)
|
||||
- `would_have_done` (op descriptor + digest)
|
||||
- `constraints_applied` (scopes narrowed, mode escalated)
|
||||
- `context_snapshot_hash` (hash of relevant context)
|
||||
|
||||
Canonical convention (recommended for audit clarity):
|
||||
- `payload.side_effects` SHOULD be `"none"` for `shadow_receipt` events.
|
||||
- `payload.reason_code` SHOULD be from a stable enum (e.g., `policy_violation`, `insufficient_capability`, `insufficient_budget`, `unsafe_context`, `backpressure`, `integrity_degraded`).
|
||||
|
||||
---
|
||||
|
||||
## 5) Execution Model (Action Gating)
|
||||
|
||||
Sentinel sits between “intent” and “effect”.
|
||||
|
||||
State machine:
|
||||
1. `action_intent` emitted
|
||||
2. Validate capability + context
|
||||
3. If allowed → execute → emit `action_executed`
|
||||
4. If denied → emit `shadow_receipt`
|
||||
5. Always advance receipt root
|
||||
|
||||
No operation may execute without producing a receipt trail.
|
||||
|
||||
---
|
||||
|
||||
## 6) Tamper & Degradation Signals (v1 minimal)
|
||||
|
||||
Sentinel accepts a `tamper_signal` input stream (from hardware or host OS). v1 supports:
|
||||
- acceleration spike / motion pattern
|
||||
- unexpected power cycle
|
||||
- secure clock jump / rollback
|
||||
- enclosure open (if available)
|
||||
- storage integrity failures
|
||||
|
||||
Response: never self-destruct. Instead:
|
||||
- elevate mode to `DEGRADED`
|
||||
- narrow allowable scopes
|
||||
- increase sealing frequency
|
||||
- emit `corruption_detected` or `tamper_signal` receipt
|
||||
|
||||
---
|
||||
|
||||
## 7) Storage Integrity & Corruption Handling
|
||||
|
||||
Requirements:
|
||||
- periodic background scan (configurable duty cycle)
|
||||
- per-page checksums (if sqlite: use `PRAGMA integrity_check` + custom page hashing if needed)
|
||||
- on detection:
|
||||
- emit `corruption_detected`
|
||||
- record impacted ranges/pages
|
||||
- freeze mutating ops (or narrow to safe subset)
|
||||
- create an immediate seal bundle if possible
|
||||
|
||||
---
|
||||
|
||||
## 8) Interfaces
|
||||
|
||||
### 8.1 Local API (host integration)
|
||||
|
||||
Provide minimal host-callable interface (C FFI or HTTP on localhost, depending on platform).
|
||||
|
||||
Calls (v1):
|
||||
- `submit_intent(op, params, cap_token) -> trace_id`
|
||||
- `get_trace(trace_id) -> outcome + receipt references`
|
||||
- `export_seal(since, until) -> path`
|
||||
- `verify_bundle(path) -> ok + details`
|
||||
- `get_root() -> current root + seq`
|
||||
- `signal_tamper(kind, payload) -> emits receipt + mode shift`
|
||||
|
||||
### 8.2 CLI (must ship with artifacts)
|
||||
|
||||
Offline verifier requirements: `spec/SENTINEL_OFFLINE_VERIFIER_REQUIREMENTS.md`.
|
||||
|
||||
- `sentinel verify --bundle <path>`
|
||||
- `sentinel compute-roots --from <artifact_dir>`
|
||||
- `sentinel seal --since "24h"`
|
||||
- `sentinel export --since "90d" --for auditor`
|
||||
|
||||
---
|
||||
|
||||
## 9) Artifact Layout (v1 canonical)
|
||||
|
||||
```
|
||||
.state/
|
||||
ledger.sqlite
|
||||
frontier.bin
|
||||
seals/
|
||||
ouroboros_seal_YYYYMMDD_HHMMSS/
|
||||
seal.json
|
||||
receipts.jsonl
|
||||
roots.txt
|
||||
integrity.json
|
||||
verifier_manifest.json
|
||||
ROOT.current.txt
|
||||
receipts/
|
||||
receipts.jsonl (optional mirror)
|
||||
identity.jsonl
|
||||
mesh.jsonl
|
||||
treasury.jsonl (optional)
|
||||
```
|
||||
|
||||
Mirror strategy: keep SQLite as primary, JSONL mirror for portability (configurable).
|
||||
|
||||
---
|
||||
|
||||
## 10) Security & Key Management (v1 minimum)
|
||||
|
||||
- Device identity keypair (Ed25519 recommended)
|
||||
- Capability verification public keys pinned locally
|
||||
- Revocation list stored append-only with receipts
|
||||
- Keys must be exportable for succession but not casually readable
|
||||
- Support “Operator Phone” as witness/verifier only (no full node requirement)
|
||||
|
||||
---
|
||||
|
||||
## 11) Performance & Footprint Targets
|
||||
|
||||
- Memory: < 64MB steady state (configurable)
|
||||
- Storage: < 256MB baseline for 90 days (depends on event volume)
|
||||
- Receipt append latency: target < 10ms typical
|
||||
- Sealing: incremental, bounded CPU
|
||||
- Deterministic behavior under load (backpressure emits ShadowReceipts)
|
||||
|
||||
---
|
||||
|
||||
## 12) Test & Drill Requirements (Definition of Done)
|
||||
|
||||
Required drills (must pass):
|
||||
|
||||
1. Cold archaeology restore
|
||||
- restore artifacts to empty dir
|
||||
- recompute roots
|
||||
- verify seals match
|
||||
2. Denial proof drill
|
||||
- attempt forbidden op
|
||||
- confirm ShadowReceipt exists
|
||||
- confirm no `action_executed` receipt exists
|
||||
3. Corruption drill
|
||||
- corrupt storage segment/pages
|
||||
- confirm corruption detected
|
||||
- confirm mode degrade + narrowed scopes
|
||||
- confirm immediate seal if possible
|
||||
4. Coercion drill
|
||||
- simulate “must sign” request
|
||||
- confirm refusal recorded (ShadowReceipt)
|
||||
- confirm no authority expansion occurred
|
||||
|
||||
---
|
||||
|
||||
## 13) Versioning & Compatibility
|
||||
|
||||
- Sentinel v1 schemas are append-only. Any breaking change requires a v2 schema and a new `canonicalization_version`.
|
||||
- Every artifact includes:
|
||||
- `sentinel_version`
|
||||
- `schema_version`
|
||||
- `hash_algo`
|
||||
- `canonicalization_version`
|
||||
- Verifier must support at least:
|
||||
- N-2 schema versions (configurable)
|
||||
|
||||
---
|
||||
|
||||
## 14) v1 Deliverables
|
||||
|
||||
- `sentinel-core` library (Rust recommended)
|
||||
- Sentinel CLI + verifier
|
||||
- Seal bundle generator + verifier
|
||||
- Minimal host API
|
||||
- Reference integration example (IoT gateway simulator)
|
||||
- Test suite for drills above
|
||||
22
spec/sentinel/README.md
Normal file
22
spec/sentinel/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Sentinel v1 Schemas (v1)
|
||||
|
||||
This directory contains implementer-facing, machine-checkable schemas and deterministic verification rules for Sentinel v1.
|
||||
|
||||
- `canonicalization.md`: normative hashing + Merkle + root publication rules.
|
||||
- `event.schema.json`: minimal event schema for `receipts*.jsonl` export.
|
||||
- `seal.schema.json`: minimal schema for `seal.json` inside an Ouroboros seal bundle.
|
||||
- `integrity.schema.json`: optional schema for `integrity.json` (hashes of bundle files).
|
||||
- `verifier_manifest.schema.json`: optional schema for `verifier_manifest.json` (tool/version expectations).
|
||||
|
||||
Related v1 documents:
|
||||
- `spec/SENTINEL_OFFLINE_VERIFIER_REQUIREMENTS.md`
|
||||
- `spec/SENTINEL_V1_CONTRACT_MATRIX.md`
|
||||
|
||||
Reference verifier + testvector:
|
||||
- Verifier: `tools/vm_verify_sentinel_bundle.py`
|
||||
- Testvector bundle: `testvectors/sentinel/black-box-that-refused/`
|
||||
|
||||
Quick run:
|
||||
```bash
|
||||
python3 tools/vm_verify_sentinel_bundle.py --bundle testvectors/sentinel/black-box-that-refused --strict
|
||||
```
|
||||
123
spec/sentinel/canonicalization.md
Normal file
123
spec/sentinel/canonicalization.md
Normal file
@@ -0,0 +1,123 @@
|
||||
# Sentinel v1 Canonicalization & Hashing Rules
|
||||
|
||||
This document defines deterministic event hashing and Merkle root computation for Sentinel v1. Verification MUST be deterministic across platforms given the same artifacts.
|
||||
|
||||
## 1) Hash function (`hash_algo`)
|
||||
|
||||
`hash_algo` MUST be one of:
|
||||
- `blake3` (recommended)
|
||||
- `sha256` (fallback for constrained platforms)
|
||||
|
||||
The chosen `hash_algo` MUST be constant for a given Sentinel instance/build. Verifiers MUST reject mixed algorithms within a single bundle unless explicitly versioned.
|
||||
|
||||
### 1.1 `vmhash`
|
||||
|
||||
`vmhash(data: bytes) -> string` returns:
|
||||
- `"blake3:" + hex(blake3(data))` when `hash_algo=blake3`
|
||||
- `"sha256:" + hex(sha256(data))` when `hash_algo=sha256`
|
||||
|
||||
`hex(...)` is lowercase hex with no separators.
|
||||
|
||||
## 2) JSON canonicalization (`canonicalization_version`)
|
||||
|
||||
`canonicalization_version` for Sentinel v1 events is:
|
||||
|
||||
- `sentinel-event-jcs-v1`
|
||||
|
||||
Canonical JSON MUST use RFC 8785 (JSON Canonicalization Scheme, “JCS”):
|
||||
- UTF-8 encoding
|
||||
- Object keys sorted lexicographically
|
||||
- No insignificant whitespace
|
||||
- Numbers encoded per JCS rules
|
||||
|
||||
If a platform cannot implement full JCS, it MUST NOT claim `sentinel-event-jcs-v1`.
|
||||
|
||||
## 3) Event canonical bytes
|
||||
|
||||
Each exported event is a JSON object that conforms to `event.schema.json`.
|
||||
|
||||
`event_canonical_bytes` is the UTF-8 bytes of the JCS-canonicalized event object.
|
||||
|
||||
## 4) Event hash + hash chain
|
||||
|
||||
### 4.1 `event_hash`
|
||||
|
||||
`event_hash` MUST be computed over the canonical bytes of the event object *excluding* the `event_hash` field itself.
|
||||
|
||||
Define:
|
||||
- `event_without_event_hash = event` with the `event_hash` property removed (if present)
|
||||
- `event_canonical_bytes = jcs_bytes(event_without_event_hash)`
|
||||
|
||||
Then:
|
||||
|
||||
`event_hash = vmhash(event_canonical_bytes)`
|
||||
|
||||
For exported artifacts, `event_hash` MUST be present in the event record and verifiers MUST recompute and compare it.
|
||||
|
||||
### 4.2 `prev_event_hash`
|
||||
|
||||
- For `seq = 0` (or the first event in a new ledger): `prev_event_hash = "0"`
|
||||
- For `seq = n > 0`: `prev_event_hash` MUST equal the computed `event_hash` of the immediately preceding event (`seq = n-1`) in the same ledger.
|
||||
|
||||
This provides fast tamper evidence even without Merkle recomputation.
|
||||
|
||||
## 5) Operation digest (`op_digest`)
|
||||
|
||||
`op_digest` commits to the *normalized* operation descriptor.
|
||||
|
||||
Define the normalized object:
|
||||
```json
|
||||
{
|
||||
"op": "<op>",
|
||||
"params": { "canonical": "params" }
|
||||
}
|
||||
```
|
||||
|
||||
Normalization rules:
|
||||
- `op` MUST be a stable, versioned identifier (e.g., `sentinel.export_seal.v1`).
|
||||
- `params` MUST be JSON (no NaN/Infinity); omit unset fields rather than using null where possible.
|
||||
- Canonicalize the object using `sentinel-event-jcs-v1`, then hash:
|
||||
|
||||
`op_digest = vmhash(jcs_bytes({"op": op, "params": params}))`
|
||||
|
||||
## 6) Merkle root (`ROOT.current.txt`)
|
||||
|
||||
### 6.1 Leaves
|
||||
|
||||
The Merkle tree commits to the ordered list of event hashes:
|
||||
|
||||
`leaves = [event_hash(seq=0), event_hash(seq=1), ...]`
|
||||
|
||||
Each leaf is a `vmhash` string (`algo:hex`).
|
||||
|
||||
Note on ranged bundles: A verifier can only recompute the global Merkle roots for an arbitrary `since_seq > 0` bundle if it is also given a verifiable Merkle continuation state (e.g., a frontier snapshot) at `since_seq-1`. Otherwise, verification MUST fall back to hash-chain + file-integrity checks for that range, or the bundle MUST start at `since_seq = 0`.
|
||||
|
||||
### 6.2 Parent computation (VaultMesh-style)
|
||||
|
||||
To compute a parent from two children:
|
||||
- Let `left_hex = left.split(":", 1)[-1]`
|
||||
- Let `right_hex = right.split(":", 1)[-1]`
|
||||
- `parent = vmhash( (left_hex + right_hex).encode("utf-8") )`
|
||||
|
||||
If the level has an odd count, duplicate the last element (i.e., `right = left`).
|
||||
|
||||
### 6.3 Empty tree root
|
||||
|
||||
If there are no leaves, the root MUST be:
|
||||
|
||||
`vmhash(b"empty")`
|
||||
|
||||
### 6.4 Root publication file format
|
||||
|
||||
`ROOT.current.txt` MUST be human-readable and parseable as key/value lines:
|
||||
|
||||
```
|
||||
format=vm-sentinel-root-v1
|
||||
root=<algo:hex>
|
||||
seq=<u64>
|
||||
updated_at=<ISO-8601 Z>
|
||||
hash_algo=<blake3|sha256>
|
||||
canonicalization_version=sentinel-event-jcs-v1
|
||||
```
|
||||
|
||||
Additional keys MAY be included, but verifiers MUST ignore unknown keys.
|
||||
68
spec/sentinel/event.schema.json
Normal file
68
spec/sentinel/event.schema.json
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "VaultMesh Sentinel v1 Event",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"event_id",
|
||||
"seq",
|
||||
"ts",
|
||||
"event_type",
|
||||
"actor",
|
||||
"cap_hash",
|
||||
"op",
|
||||
"op_digest",
|
||||
"result",
|
||||
"trace_id",
|
||||
"prev_event_hash",
|
||||
"event_hash",
|
||||
"payload"
|
||||
],
|
||||
"properties": {
|
||||
"event_id": { "type": "string", "format": "uuid" },
|
||||
"seq": { "type": "integer", "minimum": 0 },
|
||||
"ts": {
|
||||
"description": "Monotonic + wallclock if available. Accepts ISO-8601 Z or a structured object.",
|
||||
"anyOf": [
|
||||
{ "type": "string" },
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["wall"],
|
||||
"properties": {
|
||||
"wall": { "type": "string", "format": "date-time" },
|
||||
"mono_ns": { "type": "integer", "minimum": 0 }
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"event_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"action_intent",
|
||||
"policy_decision",
|
||||
"action_executed",
|
||||
"shadow_receipt",
|
||||
"cap_grant",
|
||||
"cap_revoke",
|
||||
"seal_created",
|
||||
"root_published",
|
||||
"corruption_detected",
|
||||
"tamper_signal",
|
||||
"boot_event",
|
||||
"health_event"
|
||||
]
|
||||
},
|
||||
"actor": { "type": "string", "minLength": 1 },
|
||||
"cap_hash": { "type": "string", "minLength": 1 },
|
||||
"op": { "type": "string", "minLength": 1 },
|
||||
"op_digest": { "type": "string", "minLength": 1 },
|
||||
"result": { "type": "string", "enum": ["ok", "deny", "error"] },
|
||||
"root_before": { "type": "string" },
|
||||
"root_after": { "type": "string" },
|
||||
"trace_id": { "type": "string", "format": "uuid" },
|
||||
"prev_event_hash": { "type": "string", "minLength": 1 },
|
||||
"event_hash": { "type": "string" },
|
||||
"payload": { "type": "object" }
|
||||
}
|
||||
}
|
||||
24
spec/sentinel/integrity.schema.json
Normal file
24
spec/sentinel/integrity.schema.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "VaultMesh Sentinel v1 Integrity Manifest (integrity.json)",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["format", "hash_algo", "files"],
|
||||
"properties": {
|
||||
"format": { "type": "string", "const": "vm-sentinel-integrity-v1" },
|
||||
"hash_algo": { "type": "string", "enum": ["blake3", "sha256"] },
|
||||
"files": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["path", "digest"],
|
||||
"properties": {
|
||||
"path": { "type": "string" },
|
||||
"digest": { "type": "string" },
|
||||
"size_bytes": { "type": "integer", "minimum": 0 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
62
spec/sentinel/seal.schema.json
Normal file
62
spec/sentinel/seal.schema.json
Normal file
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "VaultMesh Sentinel v1 Seal Bundle (seal.json)",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"format",
|
||||
"sentinel_version",
|
||||
"schema_version",
|
||||
"hash_algo",
|
||||
"canonicalization_version",
|
||||
"seal_id",
|
||||
"created_at",
|
||||
"range",
|
||||
"root",
|
||||
"files"
|
||||
],
|
||||
"properties": {
|
||||
"format": { "type": "string", "const": "vm-sentinel-seal-v1" },
|
||||
"sentinel_version": { "type": "string" },
|
||||
"schema_version": { "type": "string" },
|
||||
"hash_algo": { "type": "string", "enum": ["blake3", "sha256"] },
|
||||
"canonicalization_version": { "type": "string" },
|
||||
"seal_id": { "type": "string" },
|
||||
"created_at": { "type": "string", "format": "date-time" },
|
||||
"instance_id": { "type": "string" },
|
||||
"ledger_type": { "type": "string", "enum": ["sqlite", "jsonl"] },
|
||||
"range": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["since_seq", "until_seq"],
|
||||
"properties": {
|
||||
"since_seq": { "type": "integer", "minimum": 0 },
|
||||
"until_seq": { "type": "integer", "minimum": 0 },
|
||||
"since_ts": { "type": "string" },
|
||||
"until_ts": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["start", "end"],
|
||||
"properties": {
|
||||
"start": { "type": "string" },
|
||||
"end": { "type": "string" },
|
||||
"seq": { "type": "integer", "minimum": 0 }
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["receipts", "roots", "integrity", "verifier_manifest"],
|
||||
"properties": {
|
||||
"receipts": { "type": "string" },
|
||||
"roots": { "type": "string" },
|
||||
"integrity": { "type": "string" },
|
||||
"verifier_manifest": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"notes": { "type": "string" }
|
||||
}
|
||||
}
|
||||
23
spec/sentinel/verifier_manifest.schema.json
Normal file
23
spec/sentinel/verifier_manifest.schema.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "VaultMesh Sentinel v1 Verifier Manifest (verifier_manifest.json)",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["format", "sentinel_version", "schema_version", "canonicalization_version"],
|
||||
"properties": {
|
||||
"format": { "type": "string", "const": "vm-sentinel-verifier-manifest-v1" },
|
||||
"sentinel_version": { "type": "string" },
|
||||
"schema_version": { "type": "string" },
|
||||
"hash_algo": { "type": "string", "enum": ["blake3", "sha256"] },
|
||||
"canonicalization_version": { "type": "string" },
|
||||
"verifier": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"version": { "type": "string" },
|
||||
"sha256": { "type": "string" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user