vta_keyspaces/lib.rs
1//! Central registry of the VTA's keyspace names.
2//!
3//! Every `store.keyspace(..)` call in the VTA (`vta-service` server, offline
4//! CLIs, backup, tests) names its keyspace through a `const` here rather than a
5//! bare string literal. This is the single source of truth that killed the
6//! `"imported"` / `"imported_secrets"` test-vs-production divergence (a test
7//! opened a *different*, empty keyspace than the one production writes). The
8//! `no_bare_keyspace_literals` guard in `vta-service` keeps it that way by
9//! scanning that crate's source for bare `.keyspace("…")` literals.
10//!
11//! Keyspace *names* live here; per-keyspace *key formats* (the `key:`, `seed:`,
12//! `path_counter:` … record families inside a keyspace) are a separate concern
13//! and are not yet centralised.
14//!
15//! This is a dependency-free leaf crate: it holds only the shared vocabulary so
16//! that every VTA subsystem crate can name keyspaces without depending on
17//! `vta-service`.
18
19/// Master seed + key records (`key:`, `seed:`, `path_counter:`,
20/// `active_seed_id`, `imported_kek_salt`, …) and the backup import sentinel.
21pub const KEYS: &str = "keys";
22/// Auth sessions + challenges.
23pub const SESSIONS: &str = "sessions";
24/// ACL entries + the seal record + the integrity-anchor root.
25pub const ACL: &str = "acl";
26/// Trust contexts (the BIP-32 key hierarchy roots).
27pub const CONTEXTS: &str = "contexts";
28/// Stored DID templates (global + context-scoped).
29pub const DID_TEMPLATES: &str = "did_templates";
30/// Audit log.
31pub const AUDIT: &str = "audit";
32/// Imported secret material (KEK-wrapped). Named `imported_secrets`, **not**
33/// `imported` — the latter was a long-standing test-only typo that operated on
34/// an empty keyspace disjoint from production. Always reference this const.
35pub const IMPORTED_SECRETS: &str = "imported_secrets";
36/// Ephemeral cache (resolver/auth caches).
37pub const CACHE: &str = "cache";
38/// Holder credential vault (third-party secrets stored on this VTA).
39pub const VAULT: &str = "vault";
40/// Persistent runtime service-enable state (`operations::protocol::runtime_state`).
41pub const SERVICE_STATE: &str = "service_state";
42/// Sealed-bootstrap anti-replay nonce log.
43pub const SEALED_NONCES: &str = "sealed_nonces";
44/// In-flight backup-bundle control-plane records.
45pub const BACKUP_BUNDLES: &str = "backup_bundles";
46/// WebVH DID records + `did.jsonl` state.
47pub const WEBVH: &str = "webvh";
48/// In-flight passkey-as-verificationMethod enrolment state.
49pub const PASSKEY_VMS: &str = "passkey_vms";
50/// Persisted protocol-management drain set.
51pub const DRAINS: &str = "drains";
52/// Per-kind previous-config snapshots for fail-forward rollback.
53/// (Historically `operations::protocol::snapshot::KEYSPACE_NAME`.)
54pub const SNAPSHOT: &str = "service_prev_config";
55/// KMS-protected, unencrypted boot keyspace (TEE integrity manifest, etc.).
56pub const BOOTSTRAP: &str = "bootstrap";
57/// Inbound-messaging consent: durable grants + TTL'd pending requests
58/// (`vti_common::consent`). The VTA is the first gate for bridged conversations.
59pub const CONSENT: &str = "consent";
60/// Per-(platform, context) approver bindings — who decides consent and how the
61/// prompt routes (`vti_common::consent::ApproverBinding`).
62pub const CONSENT_APPROVERS: &str = "consent_approvers";
63/// VTA-issued credentials (minted by `vta/credentials/issue/0.1`, revoked by
64/// `vta/credentials/revoke/0.1`). One record per credential keyed `cred:<id>`;
65/// revocation is a tombstone (`revokedAt` set in place), not a delete. Distinct
66/// from [`VAULT`] (which stores credentials the holder *holds*).
67pub const ISSUED_CREDENTIALS: &str = "issued_credentials";
68
69/// Per-context key/value store for AI-agent memory (`vta/memory/{put,list,
70/// delete}/0.1`). One record per `(contextId, key)` pair, keyed
71/// `mem:<contextId>:<key>`; `list` is a `mem:<contextId>:` prefix scan. Durable
72/// user data → in [`BACKED_UP`].
73pub const MEMORY: &str = "memory";
74
75/// Rego policy modules for the Policy Decision Point (`policy/{upsert,list,
76/// delete,evaluate}`). One `policy::PolicyModule` per id, keyed `policy:<id>`;
77/// the active set is every enabled row, priority-ordered. Durable operator
78/// security config → in [`BACKED_UP`] (a lost policy set would silently drop
79/// enforcement on restore).
80pub const POLICY: &str = "policy";
81
82/// Task-execution consent for the PDP's `requireConsent` disposition: pending
83/// approvals keyed by payload digest, and granted consents a re-submitted task
84/// consumes. Distinct from [`CONSENT`] (messaging-bridge conversation consent).
85/// One `policy::consent::PendingTaskConsent` per `pending:<digest>` and
86/// `policy::consent::TaskConsentGrant` per `grant:<digest>:<requester>`.
87/// Durable operator-facing security state → [`BACKED_UP`].
88pub const TASK_CONSENT: &str = "task_consent";
89
90/// Durable reliable-messaging outbox backing `vti_common::outbox_store::`
91/// `VtiOutboxStore` for the delivery-layer `MessagingService` (D2 P2a
92/// cut-over). Holds `Guaranteed`-delivery outbox entries; dormant in P2a (all
93/// current sends are `BestEffort`) but wired so the drain/confirmation loops
94/// persist across restarts once P2b adds guaranteed VTA pushes. Runtime state,
95/// not backed up.
96pub const OUTBOX: &str = "outbox";
97
98/// Every production keyspace. Partitioned by [`BACKED_UP`] +
99/// [`EXCLUDED_FROM_BACKUP`]; the [`tests::backup_partition_is_total`] guard
100/// asserts the partition stays exhaustive so a newly-added keyspace can't be
101/// silently omitted from the backup decision.
102pub const ALL: &[&str] = &[
103 KEYS,
104 SESSIONS,
105 ACL,
106 CONTEXTS,
107 DID_TEMPLATES,
108 AUDIT,
109 IMPORTED_SECRETS,
110 CACHE,
111 VAULT,
112 SERVICE_STATE,
113 SEALED_NONCES,
114 BACKUP_BUNDLES,
115 WEBVH,
116 PASSKEY_VMS,
117 DRAINS,
118 SNAPSHOT,
119 BOOTSTRAP,
120 CONSENT,
121 CONSENT_APPROVERS,
122 ISSUED_CREDENTIALS,
123 MEMORY,
124 POLICY,
125 TASK_CONSENT,
126 OUTBOX,
127];
128
129/// Keyspaces whose contents a full `export_backup` captures (as typed
130/// collections — see `operations::backup`).
131pub const BACKED_UP: &[&str] = &[
132 KEYS,
133 ACL,
134 CONTEXTS,
135 AUDIT,
136 IMPORTED_SECRETS,
137 WEBVH,
138 CONSENT,
139 CONSENT_APPROVERS,
140 // Durable agent memory is user data and must survive a restore.
141 MEMORY,
142 // Operator security policy — must survive a restore, else enforcement
143 // silently reverts to whatever defaults boot-install provides.
144 POLICY,
145 // Task-consent grants are durable authorizations a re-submitted task
146 // consumes; losing them on restore would strand in-flight approvals.
147 TASK_CONSENT,
148];
149
150/// Keyspaces deliberately **not** in a backup.
151///
152/// Most are ephemeral / runtime / re-derivable: [`SESSIONS`], [`CACHE`],
153/// [`SEALED_NONCES`], [`SERVICE_STATE`], [`BACKUP_BUNDLES`], [`PASSKEY_VMS`],
154/// [`DRAINS`], [`SNAPSHOT`], [`BOOTSTRAP`]. [`DID_TEMPLATES`] and [`VAULT`]
155/// hold durable operator/holder state and are **known backup gaps** — a
156/// backup-fidelity follow-up should move them into [`BACKED_UP`], not leave
157/// them silently dropped.
158pub const EXCLUDED_FROM_BACKUP: &[&str] = &[
159 SESSIONS,
160 DID_TEMPLATES,
161 CACHE,
162 VAULT,
163 SERVICE_STATE,
164 SEALED_NONCES,
165 BACKUP_BUNDLES,
166 PASSKEY_VMS,
167 DRAINS,
168 SNAPSHOT,
169 BOOTSTRAP,
170 // Durable VTA-issued holder credentials. Like [`VAULT`], a known backup
171 // gap — a backup-fidelity follow-up should move it into [`BACKED_UP`].
172 ISSUED_CREDENTIALS,
173 // Reliable-messaging outbox: runtime delivery state, re-driven from live
174 // sends, not part of a state backup.
175 OUTBOX,
176];
177
178#[cfg(test)]
179mod tests {
180 use super::*;
181 use std::collections::BTreeSet;
182
183 /// The backup partition must be total and disjoint: every production
184 /// keyspace is either backed up or explicitly excluded. Adding a keyspace
185 /// to [`ALL`] without classifying it fails here — that's the point.
186 #[test]
187 fn backup_partition_is_total() {
188 let all: BTreeSet<&str> = ALL.iter().copied().collect();
189 let backed: BTreeSet<&str> = BACKED_UP.iter().copied().collect();
190 let excluded: BTreeSet<&str> = EXCLUDED_FROM_BACKUP.iter().copied().collect();
191
192 assert_eq!(all.len(), ALL.len(), "ALL has a duplicate");
193 assert!(
194 backed.is_disjoint(&excluded),
195 "a keyspace is both backed up and excluded: {:?}",
196 backed.intersection(&excluded).collect::<Vec<_>>()
197 );
198 let union: BTreeSet<&str> = backed.union(&excluded).copied().collect();
199 assert_eq!(
200 union, all,
201 "backup partition is not exhaustive — every keyspace in ALL must be in \
202 exactly one of BACKED_UP / EXCLUDED_FROM_BACKUP"
203 );
204 }
205}