1use std::collections::{BTreeMap, BTreeSet, VecDeque};
2use std::fmt;
3use std::sync::Arc;
4
5mod evaluator;
6mod execute;
7mod json;
8mod path;
9mod proof;
10mod secret_material;
11mod wrapped_secret;
12
13use evaluator::{evaluate_expression, extract_expression_refs};
14pub use execute::{
15 normalize_executable_path, parse_executable_target, ExecuteError, ExecuteValue, MeTargetAst,
16};
17pub use json::{
18 execute_value_to_json, kernel_event_to_json, kernel_value_from_json, kernel_value_to_json,
19 memory_to_json, parse_kernel_value, proof_result_to_json, snapshot_from_json, snapshot_to_json,
20 JsonCodecError,
21};
22pub use path::{IntoPath, ParsedPath, Path, PathParseError, PathPart, Selector};
23pub use proof::{
24 derive_branch_proof_seed, derive_compound_seed, derive_identity_hash, normalize_proof_payload,
25 normalize_root_namespace, prove_with_timestamp, verify_ed25519_signature, ProofError,
26 ProofInput, ProofResult,
27};
28use secret_material::{
29 decrypt_blob_v3_cleartext, derive_blob_v3_keys, derive_secret_material_v3,
30 encrypt_blob_v3_cleartext, lineage_segment, random_blob_v3_nonce,
31};
32pub use secret_material::{BlobV3DerivedKeys, SecretMaterialPurpose};
33pub use wrapped_secret::{
34 export_p256_public_key_from_private, generate_p256_key_pair, unwrap_secret_v1, wrap_secret_v1,
35 P256KeyPair, P256PrivateKey, P256PublicKeyCoordinates, WrappedSecretCleartext,
36 WrappedSecretError, WrappedSecretOutput,
37};
38
39const V3_DOMAIN: &str = "this.me/blob/v3";
40const V3_NO_NOISE_SENTINEL: &str = "this.me/blob/v3/no-noise";
41
42#[derive(Debug, Clone, PartialEq)]
43pub enum Value {
44 Null,
45 Bool(bool),
46 Number(f64),
47 String(String),
48 Array(Vec<Value>),
49 Object(BTreeMap<String, Value>),
50 Pointer(Path),
51 Identity(String),
52}
53
54impl From<&str> for Value {
55 fn from(value: &str) -> Self {
56 Self::String(value.to_string())
57 }
58}
59
60impl From<String> for Value {
61 fn from(value: String) -> Self {
62 Self::String(value)
63 }
64}
65
66impl From<bool> for Value {
67 fn from(value: bool) -> Self {
68 Self::Bool(value)
69 }
70}
71
72impl From<i64> for Value {
73 fn from(value: i64) -> Self {
74 Self::Number(value as f64)
75 }
76}
77
78impl From<u64> for Value {
79 fn from(value: u64) -> Self {
80 Self::Number(value as f64)
81 }
82}
83
84impl From<f64> for Value {
85 fn from(value: f64) -> Self {
86 Self::Number(value)
87 }
88}
89
90#[derive(Debug, Clone, PartialEq)]
91pub struct Memory {
92 pub path: Path,
93 pub operator: Option<String>,
94 pub expression: Option<Value>,
95 pub value: Value,
96 pub prev_hash: Option<String>,
97 pub hash: String,
98}
99
100#[derive(Debug, Clone, PartialEq, Eq)]
101pub struct OperatorDefinition {
102 pub kind: String,
103}
104
105#[derive(Debug, Clone, PartialEq, Default)]
106pub struct Snapshot {
107 pub memories: Vec<Memory>,
108 pub local_secrets: BTreeMap<Path, String>,
109 pub local_noises: BTreeMap<Path, String>,
110 pub key_spaces: BTreeMap<String, StoredWrappedKey>,
111 pub operators: BTreeMap<String, OperatorDefinition>,
112}
113
114#[derive(Debug, Clone, PartialEq)]
115pub struct StoredWrappedKey {
116 pub envelope: Value,
117 pub recipient_key_id: Option<String>,
118}
119
120#[derive(Debug, Clone, PartialEq)]
121pub struct KernelEvent {
122 pub path: Path,
123 pub operator: Option<String>,
124 pub value: Option<Value>,
125 pub memory_hash: String,
126}
127
128#[derive(Debug, Clone, PartialEq)]
129pub struct InspectResult {
130 pub memories: Vec<InspectMemory>,
131 pub index: BTreeMap<Path, Value>,
132 pub secret_scopes: Vec<Path>,
133 pub noise_scopes: Vec<Path>,
134 pub derivations: Vec<Path>,
135}
136
137#[derive(Debug, Clone, PartialEq)]
138pub struct InspectMemory {
139 pub path: Path,
140 pub operator: Option<String>,
141 pub expression: Option<Value>,
142 pub value: Value,
143 pub prev_hash: Option<String>,
144 pub hash: String,
145}
146
147#[derive(Debug, Clone, PartialEq)]
148pub struct ExplainResult {
149 pub path: Path,
150 pub value: Option<Value>,
151 pub expr: Option<String>,
152 pub derivation: Option<ExplainDerivation>,
153 pub meta: ExplainMeta,
154}
155
156#[derive(Debug, Clone, PartialEq)]
157pub struct ExplainDerivation {
158 pub expression: String,
159 pub inputs: Vec<ExplainInput>,
160}
161
162#[derive(Debug, Clone, PartialEq)]
163pub struct ExplainInput {
164 pub label: String,
165 pub path: Path,
166 pub value: Option<Value>,
167 pub origin: ExplainOrigin,
168 pub masked: bool,
169}
170
171#[derive(Debug, Clone, Copy, PartialEq, Eq)]
172pub enum ExplainOrigin {
173 Public,
174 Secret,
175}
176
177#[derive(Debug, Clone, Copy, PartialEq, Eq)]
178pub enum SecretMaterialMode {
179 Branch,
180 Value,
181}
182
183#[derive(Debug, Clone, Copy, PartialEq, Eq)]
184pub enum RecomputeMode {
185 Eager,
186 Lazy,
187}
188
189#[derive(Debug, Clone, PartialEq, Eq)]
190pub struct ExplainMeta {
191 pub depends_on: Vec<Path>,
192 pub resolved_path: Path,
193 pub pointer_chain: Vec<Path>,
194 pub secret: bool,
195 pub k: usize,
196 pub recomputed: Vec<Path>,
197 pub source_path: Option<Path>,
198}
199
200#[derive(Debug, Clone, PartialEq, Eq)]
201pub enum KernelError {
202 EmptyPath,
203 EmptyExpression,
204 EmptyNoise,
205 EmptyOperator,
206 EmptyOperatorKind,
207 EmptyQuery,
208 EmptySecret,
209 InvalidPath(PathParseError),
210 InvalidIdentity(String),
211 NonFiniteNumber,
212 NoSecretContext(Path),
213 RandomUnavailable,
214 ReservedOperator(String),
215 SecretBlobDecryptFailed(Path),
216 RootSecretBranchUnsupported,
217 HydrationHashMismatch {
218 path: Path,
219 expected: String,
220 actual: String,
221 },
222 HydrationChainMismatch {
223 index: usize,
224 expected_prev_hash: Option<String>,
225 actual_prev_hash: Option<String>,
226 },
227}
228
229impl fmt::Display for KernelError {
230 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231 match self {
232 Self::EmptyPath => write!(f, "path cannot be empty"),
233 Self::EmptyExpression => write!(f, "expression cannot be empty"),
234 Self::EmptyNoise => write!(f, "noise cannot be empty"),
235 Self::EmptyOperator => write!(f, "operator cannot be empty"),
236 Self::EmptyOperatorKind => write!(f, "operator kind cannot be empty"),
237 Self::EmptyQuery => write!(f, "query must contain at least one path"),
238 Self::EmptySecret => write!(f, "secret cannot be empty"),
239 Self::InvalidPath(error) => write!(f, "invalid path: {error}"),
240 Self::InvalidIdentity(value) => write!(f, "invalid identity: {value}"),
241 Self::NonFiniteNumber => write!(f, "numbers must be finite"),
242 Self::NoSecretContext(path) => write!(
243 f,
244 "no secret context active for {}",
245 if path.is_empty() {
246 "<root>".to_string()
247 } else {
248 path.join(".")
249 }
250 ),
251 Self::RandomUnavailable => write!(f, "secure random bytes are unavailable"),
252 Self::ReservedOperator(operator) => {
253 write!(f, "operator {operator} is reserved")
254 }
255 Self::SecretBlobDecryptFailed(path) => write!(
256 f,
257 "secret blob decrypt failed for {}",
258 if path.is_empty() {
259 "<root>".to_string()
260 } else {
261 path.join(".")
262 }
263 ),
264 Self::RootSecretBranchUnsupported => {
265 write!(f, "branch v3 derivation does not support root secret scope")
266 }
267 Self::HydrationHashMismatch {
268 path,
269 expected,
270 actual,
271 } => write!(
272 f,
273 "memory hash mismatch at {}: expected {}, got {}",
274 path.join("."),
275 expected,
276 actual
277 ),
278 Self::HydrationChainMismatch {
279 index,
280 expected_prev_hash,
281 actual_prev_hash,
282 } => write!(
283 f,
284 "memory chain mismatch at index {}: expected prev_hash {:?}, got {:?}",
285 index, expected_prev_hash, actual_prev_hash
286 ),
287 }
288 }
289}
290
291impl std::error::Error for KernelError {}
292
293#[derive(Debug, Clone)]
294pub struct Kernel {
295 memories: Vec<Memory>,
296 index: BTreeMap<Path, Value>,
297 private_index: BTreeMap<Path, Value>,
298 secret_scopes: BTreeSet<Path>,
299 noise_scopes: BTreeSet<Path>,
300 local_secrets: BTreeMap<Path, String>,
301 local_noises: BTreeMap<Path, String>,
302 key_spaces: BTreeMap<String, StoredWrappedKey>,
303 recipient_keyring: BTreeMap<String, P256PrivateKey>,
304 derivations: BTreeMap<Path, DerivationRecord>,
305 ref_subscribers: BTreeMap<Path, BTreeSet<Path>>,
306 events: Vec<KernelEvent>,
307 active_identity: Option<String>,
308 seed: Option<String>,
309 identity_hash: Option<String>,
310 active_expression: Option<String>,
311 operators: BTreeMap<String, OperatorDefinition>,
312 last_recompute_wave_by_target: BTreeMap<Path, Arc<RecomputeWave>>,
313 active_recompute_wave: Option<RecomputeWave>,
314 recompute_mode: RecomputeMode,
315 path_version_clock: u64,
316 path_versions: BTreeMap<Path, u64>,
317}
318
319#[derive(Debug, Clone, PartialEq, Eq)]
320struct DerivationRecord {
321 eval_scope: Path,
322 expression: String,
323 refs: Vec<DerivationRef>,
324 ref_versions: BTreeMap<Path, u64>,
325}
326
327#[derive(Debug, Clone, PartialEq, Eq)]
328struct DerivationRef {
329 label: String,
330 path: Path,
331}
332
333#[derive(Debug, Clone, PartialEq, Eq)]
334struct RecomputeWave {
335 source_path: Path,
336 recomputed: BTreeSet<Path>,
337}
338
339#[derive(Debug, Clone, PartialEq, Eq)]
340struct PointerResolution {
341 resolved_path: Path,
342 pointer_chain: Vec<Path>,
343}
344
345impl Default for Kernel {
346 fn default() -> Self {
347 Self {
348 memories: Vec::new(),
349 index: BTreeMap::new(),
350 private_index: BTreeMap::new(),
351 secret_scopes: BTreeSet::new(),
352 noise_scopes: BTreeSet::new(),
353 local_secrets: BTreeMap::new(),
354 local_noises: BTreeMap::new(),
355 key_spaces: BTreeMap::new(),
356 recipient_keyring: BTreeMap::new(),
357 derivations: BTreeMap::new(),
358 ref_subscribers: BTreeMap::new(),
359 events: Vec::new(),
360 active_identity: None,
361 seed: None,
362 identity_hash: None,
363 active_expression: None,
364 operators: default_operators(),
365 last_recompute_wave_by_target: BTreeMap::new(),
366 active_recompute_wave: None,
367 recompute_mode: RecomputeMode::Eager,
368 path_version_clock: 0,
369 path_versions: BTreeMap::new(),
370 }
371 }
372}
373
374impl Kernel {
375 pub fn new() -> Self {
376 Self::default()
377 }
378
379 pub fn with_seed(seed: impl Into<String>) -> Self {
380 let mut kernel = Self::new();
381 kernel.set_seed(seed);
382 kernel
383 }
384
385 pub fn with_compound_seed(who: &str, secret: &str) -> Self {
386 let mut kernel = Self::new();
387 kernel.reseed_identity(who, secret);
388 kernel
389 }
390
391 pub fn memories(&self) -> &[Memory] {
392 &self.memories
393 }
394
395 pub fn set_seed(&mut self, seed: impl Into<String>) -> &mut Self {
396 let seed = seed.into();
397 self.identity_hash = Some(derive_identity_hash(&seed));
398 self.seed = Some(seed);
399 self
400 }
401
402 pub fn reseed_identity(&mut self, who: &str, secret: &str) -> &mut Self {
403 let seed = derive_compound_seed(who, secret);
404 self.identity_hash = Some(derive_identity_hash(&seed));
405 self.seed = Some(seed);
406 self.active_expression = Some(who.to_string());
407 self
408 }
409
410 pub fn identity_hash(&self) -> Option<&str> {
411 self.identity_hash.as_deref()
412 }
413
414 pub fn active_expression(&self) -> Option<&str> {
415 self.active_expression.as_deref()
416 }
417
418 pub fn set_active_expression(&mut self, expression: impl Into<Option<String>>) -> &mut Self {
419 self.active_expression = expression.into();
420 self
421 }
422
423 pub fn prove_with_timestamp(
424 &self,
425 input: ProofInput,
426 timestamp: u64,
427 ) -> Result<ProofResult, ProofError> {
428 let seed = self.seed.as_deref().ok_or(ProofError::EmptySeed)?;
429 let expression = self
430 .active_expression
431 .as_deref()
432 .ok_or(ProofError::ActiveExpressionRequired)?;
433 prove_with_timestamp(
434 seed,
435 expression,
436 &input.root_namespace,
437 input.challenge.as_deref(),
438 timestamp,
439 )
440 }
441
442 pub fn inspect(&self) -> InspectResult {
443 self.inspect_memories(self.memories.iter())
444 }
445
446 pub fn inspect_last(&self, last: usize) -> InspectResult {
447 if last == 0 || last >= self.memories.len() {
448 return self.inspect();
449 }
450 self.inspect_memories(self.memories[self.memories.len() - last..].iter())
451 }
452
453 pub fn active_identity(&self) -> Option<&str> {
454 self.active_identity.as_deref()
455 }
456
457 pub fn operators(&self) -> &BTreeMap<String, OperatorDefinition> {
458 &self.operators
459 }
460
461 pub fn events(&self) -> &[KernelEvent] {
462 &self.events
463 }
464
465 pub fn event_cursor(&self) -> usize {
466 self.events.len()
467 }
468
469 pub fn events_since(&self, cursor: usize) -> &[KernelEvent] {
470 let cursor = cursor.min(self.events.len());
471 &self.events[cursor..]
472 }
473
474 pub fn drain_events_since(&mut self, cursor: usize) -> Vec<KernelEvent> {
475 if cursor >= self.events.len() {
476 return Vec::new();
477 }
478 self.events.split_off(cursor)
479 }
480
481 pub fn drain_events(&mut self) -> Vec<KernelEvent> {
482 std::mem::take(&mut self.events)
483 }
484
485 pub fn events_matching(&self, path: impl IntoPath) -> Result<Vec<KernelEvent>, KernelError> {
486 let path = path.into_path().map_err(KernelError::InvalidPath)?;
487 Ok(self
488 .events
489 .iter()
490 .filter(|event| event_matches_subscription_path(&path, &event.path))
491 .cloned()
492 .collect())
493 }
494
495 pub fn drain_events_matching(
496 &mut self,
497 path: impl IntoPath,
498 ) -> Result<Vec<KernelEvent>, KernelError> {
499 let path = path.into_path().map_err(KernelError::InvalidPath)?;
500 let mut drained = Vec::new();
501 let mut retained = Vec::new();
502
503 for event in self.events.drain(..) {
504 if event_matches_subscription_path(&path, &event.path) {
505 drained.push(event);
506 } else {
507 retained.push(event);
508 }
509 }
510
511 self.events = retained;
512 Ok(drained)
513 }
514
515 pub fn clear_events(&mut self) -> &mut Self {
516 self.events.clear();
517 self
518 }
519
520 pub fn operator_kind(&self, operator: &str) -> Option<&str> {
521 self.operators
522 .get(operator)
523 .map(|definition| definition.kind.as_str())
524 }
525
526 pub fn recompute_mode(&self) -> RecomputeMode {
527 self.recompute_mode
528 }
529
530 pub fn set_recompute_mode(&mut self, mode: RecomputeMode) -> &mut Self {
531 self.recompute_mode = mode;
532 self
533 }
534
535 pub fn define_operator(&mut self, operator: &str, kind: &str) -> Result<(), KernelError> {
536 let operator = operator.trim();
537 let kind = kind.trim();
538
539 if operator.is_empty() {
540 return Err(KernelError::EmptyOperator);
541 }
542 if operator == "+" {
543 return Err(KernelError::ReservedOperator(operator.to_string()));
544 }
545 if kind.is_empty() {
546 return Err(KernelError::EmptyOperatorKind);
547 }
548
549 self.operators.insert(
550 operator.to_string(),
551 OperatorDefinition {
552 kind: kind.to_string(),
553 },
554 );
555 Ok(())
556 }
557
558 pub fn is_secret_scope(&self, path: impl IntoPath) -> bool {
559 let Ok(path) = path.into_path() else {
560 return false;
561 };
562 self.secret_scopes.contains(&path)
563 }
564
565 pub fn is_noise_scope(&self, path: impl IntoPath) -> bool {
566 let Ok(path) = path.into_path() else {
567 return false;
568 };
569 self.noise_scopes.contains(&path)
570 }
571
572 pub fn effective_secret(&self, path: impl IntoPath) -> Result<String, KernelError> {
573 let path = path.into_path().map_err(KernelError::InvalidPath)?;
574 Ok(self.compute_effective_secret(&path))
575 }
576
577 pub fn secret_material_v3(
578 &self,
579 path: impl IntoPath,
580 mode: SecretMaterialMode,
581 purpose: SecretMaterialPurpose,
582 ) -> Result<[u8; 32], KernelError> {
583 let path = path.into_path().map_err(KernelError::InvalidPath)?;
584 let chain = self.collect_secret_chain_v3(&path, mode)?;
585 derive_secret_material_v3(&chain, purpose).ok_or(KernelError::NoSecretContext(path))
586 }
587
588 pub fn secret_blob_keys_v3(
589 &self,
590 path: impl IntoPath,
591 mode: SecretMaterialMode,
592 ) -> Result<BlobV3DerivedKeys, KernelError> {
593 let path = path.into_path().map_err(KernelError::InvalidPath)?;
594 let chain = self.collect_secret_chain_v3(&path, mode)?;
595 let purpose = match mode {
596 SecretMaterialMode::Branch => SecretMaterialPurpose::Branch,
597 SecretMaterialMode::Value => SecretMaterialPurpose::Value,
598 };
599 derive_blob_v3_keys(&chain, purpose, &path).ok_or(KernelError::NoSecretContext(path))
600 }
601
602 pub fn encrypt_secret_value_v3(
603 &self,
604 path: impl IntoPath,
605 value: impl Into<Value>,
606 nonce: [u8; 16],
607 ) -> Result<String, KernelError> {
608 let path = path.into_path().map_err(KernelError::InvalidPath)?;
609 let keys = self.secret_blob_keys_v3(path.clone(), SecretMaterialMode::Value)?;
610 let value = value.into();
611 ensure_value_is_supported(&value)?;
612 let mut json = String::new();
613 push_json_value(&mut json, &value);
614 Ok(encrypt_blob_v3_cleartext(json.as_bytes(), &keys, nonce))
615 }
616
617 pub fn decrypt_secret_value_v3(
618 &self,
619 path: impl IntoPath,
620 blob: &str,
621 ) -> Result<Option<Value>, KernelError> {
622 let path = path.into_path().map_err(KernelError::InvalidPath)?;
623 let keys = self.secret_blob_keys_v3(path, SecretMaterialMode::Value)?;
624 let Some(cleartext) = decrypt_blob_v3_cleartext(blob, &keys) else {
625 return Ok(None);
626 };
627 let Ok(json) = String::from_utf8(cleartext) else {
628 return Ok(None);
629 };
630 Ok(json_to_value(&json))
631 }
632
633 pub fn postulate(
634 &mut self,
635 path: impl IntoPath,
636 value: impl Into<Value>,
637 ) -> Result<&Memory, KernelError> {
638 self.postulate_with_operator(path, None, value)
639 }
640
641 pub fn postulate_with_operator(
642 &mut self,
643 path: impl IntoPath,
644 operator: Option<String>,
645 value: impl Into<Value>,
646 ) -> Result<&Memory, KernelError> {
647 let path = path.into_path().map_err(KernelError::InvalidPath)?;
648 if path.is_empty() {
649 return Err(KernelError::EmptyPath);
650 }
651
652 self.commit_memory(path, operator, value.into())
653 }
654
655 pub fn remove(&mut self, path: impl IntoPath) -> Result<&Memory, KernelError> {
656 self.postulate_with_operator(path, Some("-".to_string()), Value::String("-".to_string()))
657 }
658
659 pub fn derive(
660 &mut self,
661 scope: impl IntoPath,
662 name: impl IntoPath,
663 expression: &str,
664 ) -> Result<&Memory, KernelError> {
665 let eval_scope = scope.into_path().map_err(KernelError::InvalidPath)?;
666 let name = name.into_path().map_err(KernelError::InvalidPath)?;
667 let expression = expression.trim();
668
669 if name.is_empty() {
670 return Err(KernelError::EmptyPath);
671 }
672 if expression.is_empty() {
673 return Err(KernelError::EmptyExpression);
674 }
675
676 let target_path = eval_scope.iter().cloned().chain(name).collect::<Vec<_>>();
677
678 self.register_derivation(
679 target_path.clone(),
680 eval_scope.clone(),
681 expression.to_string(),
682 );
683
684 let value = self
685 .evaluate_expression(&eval_scope, expression)
686 .unwrap_or_else(|| Value::String(expression.to_string()));
687
688 self.commit_memory_with_expression(
689 target_path,
690 Some("=".to_string()),
691 value,
692 Some(Value::String(expression.to_string())),
693 true,
694 )
695 }
696
697 pub fn collect<I, P>(&self, paths: I) -> Result<Value, KernelError>
698 where
699 I: IntoIterator<Item = P>,
700 P: IntoPath,
701 {
702 self.collect_from_scope(&[], paths)
703 }
704
705 pub fn query<I, P>(
706 &mut self,
707 target_path: impl IntoPath,
708 paths: I,
709 ) -> Result<&Memory, KernelError>
710 where
711 I: IntoIterator<Item = P>,
712 P: IntoPath,
713 {
714 let target_path = target_path.into_path().map_err(KernelError::InvalidPath)?;
715 if target_path.is_empty() {
716 return Err(KernelError::EmptyPath);
717 }
718
719 let value = self.collect_from_scope(&target_path, paths)?;
720 self.commit_memory(target_path, Some("?".to_string()), value)
721 }
722
723 pub fn noise(&mut self, path: impl IntoPath, noise: &str) -> Result<&Memory, KernelError> {
724 if noise.trim().is_empty() {
725 return Err(KernelError::EmptyNoise);
726 }
727
728 let path = path.into_path().map_err(KernelError::InvalidPath)?;
729 if path.is_empty() {
730 return Err(KernelError::EmptyPath);
731 }
732
733 let path_for_noise = path.clone();
734 let memory_index = self.memories.len();
735 self.local_noises
736 .insert(path_for_noise.clone(), noise.trim().to_string());
737 self.commit_memory(
738 path,
739 Some("~".to_string()),
740 Value::String("***".to_string()),
741 )?;
742 Ok(&self.memories[memory_index])
743 }
744
745 pub fn secret(&mut self, path: impl IntoPath, secret: &str) -> Result<&Memory, KernelError> {
746 if secret.trim().is_empty() {
747 return Err(KernelError::EmptySecret);
748 }
749
750 let path = path.into_path().map_err(KernelError::InvalidPath)?;
751 if path.is_empty() {
752 return Err(KernelError::EmptyPath);
753 }
754
755 let path_for_secret = path.clone();
756 let memory_index = self.memories.len();
757 self.local_secrets
758 .insert(path_for_secret.clone(), secret.trim().to_string());
759 self.commit_memory(
760 path,
761 Some("_".to_string()),
762 Value::String("***".to_string()),
763 )?;
764 Ok(&self.memories[memory_index])
765 }
766
767 pub fn pointer(
768 &mut self,
769 path: impl IntoPath,
770 target: impl IntoPath,
771 ) -> Result<&Memory, KernelError> {
772 let target = target.into_path().map_err(KernelError::InvalidPath)?;
773 if target.is_empty() {
774 return Err(KernelError::EmptyPath);
775 }
776 self.postulate_with_operator(path, Some("__".to_string()), Value::Pointer(target))
777 }
778
779 pub fn claim_identity(&mut self, id: &str) -> Result<&Memory, KernelError> {
780 let id = normalize_identity(id)?;
781 self.active_identity = Some(id.clone());
782 self.commit_memory(Vec::new(), Some("@".to_string()), Value::Identity(id))
783 }
784
785 pub fn identity(&mut self, path: impl IntoPath, id: &str) -> Result<&Memory, KernelError> {
786 let id = normalize_identity(id)?;
787 self.postulate_with_operator(path, Some("@".to_string()), Value::Identity(id))
788 }
789
790 pub fn read(&self, path: impl IntoPath) -> Option<&Value> {
791 let Ok(path) = path.into_path() else {
792 return None;
793 };
794 self.resolve_index_pointer_path(&path, 8)
795 .and_then(|resolved| self.read_owner_path(&resolved))
796 }
797
798 pub fn read_fresh(&mut self, path: impl IntoPath) -> Option<Value> {
799 let Ok(path) = path.into_path() else {
800 return None;
801 };
802 let resolved = self
803 .resolve_index_pointer_path(&path, 8)
804 .unwrap_or_else(|| path.clone());
805 self.ensure_target_fresh(&resolved, &mut BTreeSet::new());
806 self.resolve_index_pointer_path(&path, 8)
807 .and_then(|resolved| self.read_owner_path(&resolved).cloned())
808 }
809
810 pub fn read_public(&self, path: impl IntoPath) -> Option<&Value> {
811 let Ok(path) = path.into_path() else {
812 return None;
813 };
814 self.resolve_index_pointer_path(&path, 8)
815 .and_then(|resolved| self.index.get(&resolved))
816 }
817
818 pub fn children(&self, prefix: impl IntoPath) -> Result<Vec<String>, KernelError> {
819 let prefix = prefix.into_path().map_err(KernelError::InvalidPath)?;
820 let mut children = BTreeSet::new();
821
822 for path in self.index.keys() {
823 if path.len() <= prefix.len() || !path_starts_with(path, &prefix) {
824 continue;
825 }
826 children.insert(path[prefix.len()].clone());
827 }
828
829 Ok(children.into_iter().collect())
830 }
831
832 pub fn read_public_subtree(&self, prefix: impl IntoPath) -> Result<Option<Value>, KernelError> {
833 let prefix = prefix.into_path().map_err(KernelError::InvalidPath)?;
834 if let Some(value) = self.index.get(&prefix) {
835 return Ok(Some(value.clone()));
836 }
837
838 let mut root = BTreeMap::new();
839 let mut wrote_any = false;
840
841 for (path, value) in &self.index {
842 if path.len() <= prefix.len() || !path_starts_with(path, &prefix) {
843 continue;
844 }
845 insert_subtree_value(&mut root, &path[prefix.len()..], value.clone());
846 wrote_any = true;
847 }
848
849 Ok(wrote_any.then_some(Value::Object(root)))
850 }
851
852 pub fn explain_fresh(&mut self, path: impl IntoPath) -> Result<ExplainResult, KernelError> {
853 let path = path.into_path().map_err(KernelError::InvalidPath)?;
854 self.read_fresh(path.clone());
855 self.explain(path)
856 }
857
858 pub fn explain(&self, path: impl IntoPath) -> Result<ExplainResult, KernelError> {
859 let path = path.into_path().map_err(KernelError::InvalidPath)?;
860 let resolution = self
861 .resolve_index_pointer_trace(&path, 8)
862 .unwrap_or_else(|| PointerResolution {
863 resolved_path: path.clone(),
864 pointer_chain: Vec::new(),
865 });
866 let value = self.read_owner_path(&resolution.resolved_path).cloned();
867 let record = self.derivations.get(&resolution.resolved_path);
868 let derivation = record.map(|record| ExplainDerivation {
869 expression: record.expression.clone(),
870 inputs: record
871 .refs
872 .iter()
873 .map(|reference| {
874 let masked = self.is_under_secret_scope(&reference.path);
875 ExplainInput {
876 label: reference.label.clone(),
877 path: reference.path.clone(),
878 value: if masked {
879 Some(Value::String("****".to_string()))
880 } else {
881 self.read(reference.path.clone()).cloned()
882 },
883 origin: if masked {
884 ExplainOrigin::Secret
885 } else {
886 ExplainOrigin::Public
887 },
888 masked,
889 }
890 })
891 .collect(),
892 });
893 let depends_on = record
894 .map(|record| {
895 record
896 .refs
897 .iter()
898 .map(|reference| reference.path.clone())
899 .collect()
900 })
901 .unwrap_or_default();
902 let expr = record.map(|record| record.expression.clone());
903 let secret = self.is_under_secret_scope(&resolution.resolved_path);
904 let wave = self
905 .last_recompute_wave_by_target
906 .get(&resolution.resolved_path);
907 let recomputed = wave
908 .map(|wave| wave.recomputed.iter().cloned().collect::<Vec<_>>())
909 .unwrap_or_default();
910
911 Ok(ExplainResult {
912 path,
913 value,
914 expr,
915 meta: ExplainMeta {
916 depends_on,
917 resolved_path: resolution.resolved_path,
918 pointer_chain: resolution.pointer_chain,
919 secret,
920 k: recomputed.len(),
921 recomputed,
922 source_path: wave.map(|wave| wave.source_path.clone()),
923 },
924 derivation,
925 })
926 }
927
928 pub fn export_snapshot(&self) -> Snapshot {
929 Snapshot {
930 memories: self.memories.clone(),
931 local_secrets: self.local_secrets.clone(),
932 local_noises: self.local_noises.clone(),
933 key_spaces: self.key_spaces.clone(),
934 operators: self.operators.clone(),
935 }
936 }
937
938 pub fn hydrate(snapshot: Snapshot) -> Result<Self, KernelError> {
939 let mut kernel = Self::new();
940 kernel.operators.extend(snapshot.operators.clone());
941 kernel.key_spaces = snapshot.key_spaces.clone();
942 let mut expected_prev_hash = None;
943
944 for (index, memory) in snapshot.memories.into_iter().enumerate() {
945 if memory.prev_hash != expected_prev_hash {
946 return Err(KernelError::HydrationChainMismatch {
947 index,
948 expected_prev_hash,
949 actual_prev_hash: memory.prev_hash,
950 });
951 }
952
953 let operator_kind = memory
954 .operator
955 .as_deref()
956 .and_then(|operator| kernel.operator_kind(operator))
957 .map(ToOwned::to_owned);
958 if operator_kind.as_deref() == Some("secret") {
959 if let Some(secret) = snapshot.local_secrets.get(&memory.path) {
960 kernel
961 .local_secrets
962 .insert(memory.path.clone(), secret.clone());
963 }
964 }
965 if operator_kind.as_deref() == Some("noise") {
966 if let Some(noise) = snapshot.local_noises.get(&memory.path) {
967 kernel
968 .local_noises
969 .insert(memory.path.clone(), noise.clone());
970 }
971 }
972
973 let expected = hash_memory(
974 &memory.path,
975 memory.operator.as_deref(),
976 memory.expression.as_ref(),
977 &memory.value,
978 &kernel.compute_effective_secret(&memory.path),
979 memory.prev_hash.as_deref(),
980 );
981 if expected != memory.hash {
982 return Err(KernelError::HydrationHashMismatch {
983 path: memory.path,
984 expected,
985 actual: memory.hash,
986 });
987 }
988
989 if operator_kind.as_deref() == Some("eval") {
990 if let Some(expression) = expression_string_from_memory(&memory) {
991 let eval_scope = parent_path(&memory.path);
992 kernel.register_derivation(memory.path.clone(), eval_scope, expression);
993 }
994 }
995 kernel.apply_memory(&memory)?;
996 expected_prev_hash = Some(memory.hash.clone());
997 let operator_kind = memory
998 .operator
999 .as_deref()
1000 .and_then(|operator| kernel.operator_kind(operator));
1001 if operator_kind == Some("identity") && memory.path.is_empty() {
1002 if let Value::Identity(id) = &memory.value {
1003 kernel.active_identity = Some(id.clone());
1004 }
1005 }
1006 kernel.memories.push(memory);
1007 }
1008
1009 Ok(kernel)
1010 }
1011
1012 pub fn learn(&mut self, memory: &Memory) -> Result<&Memory, KernelError> {
1013 let memory_index = self.memories.len();
1014 self.learn_record(memory)?;
1015 Ok(&self.memories[memory_index])
1016 }
1017
1018 pub fn replay_memories<I>(&mut self, memories: I) -> Result<(), KernelError>
1019 where
1020 I: IntoIterator<Item = Memory>,
1021 {
1022 let mut replayed = Self::new();
1023 replayed.operators = self.operators.clone();
1024 replayed.recompute_mode = self.recompute_mode;
1025
1026 for memory in memories {
1027 replayed.learn(&memory)?;
1028 }
1029
1030 replayed.clear_events();
1031 *self = replayed;
1032 Ok(())
1033 }
1034
1035 fn resolve_index_pointer_path(&self, path: &[String], max_hops: usize) -> Option<Path> {
1036 self.resolve_index_pointer_trace(path, max_hops)
1037 .map(|resolution| resolution.resolved_path)
1038 }
1039
1040 fn resolve_index_pointer_trace(
1041 &self,
1042 path: &[String],
1043 max_hops: usize,
1044 ) -> Option<PointerResolution> {
1045 let mut current = path.to_vec();
1046 let mut visited = BTreeSet::new();
1047 let mut pointer_chain = Vec::new();
1048
1049 for _ in 0..max_hops {
1050 if let Some(Value::Pointer(target)) = self.index.get(¤t) {
1051 if !visited.insert(current.clone()) {
1052 return None;
1053 }
1054 pointer_chain.push(current.clone());
1055 current = target.clone();
1056 continue;
1057 }
1058
1059 let mut redirected = false;
1060 for prefix_len in (0..current.len()).rev() {
1061 let prefix = current[..prefix_len].to_vec();
1062 let Some(Value::Pointer(target)) = self.index.get(&prefix) else {
1063 continue;
1064 };
1065 if !visited.insert(prefix.clone()) {
1066 return None;
1067 }
1068 pointer_chain.push(prefix.clone());
1069 let suffix = current[prefix_len..].to_vec();
1070 current = target.iter().cloned().chain(suffix).collect();
1071 redirected = true;
1072 break;
1073 }
1074
1075 if redirected {
1076 continue;
1077 }
1078
1079 return Some(PointerResolution {
1080 resolved_path: current,
1081 pointer_chain,
1082 });
1083 }
1084
1085 None
1086 }
1087
1088 fn read_owner_path(&self, path: &[String]) -> Option<&Value> {
1089 if self.is_under_secret_scope(path) {
1090 return self.private_index.get(path);
1091 }
1092 self.index.get(path)
1093 }
1094
1095 fn commit_memory(
1096 &mut self,
1097 path: Path,
1098 operator: Option<String>,
1099 value: Value,
1100 ) -> Result<&Memory, KernelError> {
1101 self.commit_memory_with_expression(path, operator, value.clone(), Some(value), true)
1102 }
1103
1104 fn commit_memory_with_expression(
1105 &mut self,
1106 path: Path,
1107 operator: Option<String>,
1108 value: Value,
1109 expression: Option<Value>,
1110 invalidate: bool,
1111 ) -> Result<&Memory, KernelError> {
1112 ensure_value_is_supported(&value)?;
1113 if let Some(expression) = &expression {
1114 ensure_value_is_supported(expression)?;
1115 }
1116
1117 let prev_hash = self.memories.last().map(|memory| memory.hash.clone());
1118 let effective_secret = self.compute_effective_secret(&path);
1119 let stored_value = self.stored_value_for_memory(&path, operator.as_deref(), &value)?;
1120 let hash = hash_memory(
1121 &path,
1122 operator.as_deref(),
1123 expression.as_ref(),
1124 &stored_value,
1125 &effective_secret,
1126 prev_hash.as_deref(),
1127 );
1128 let source_path = path.clone();
1129 let memory_index = self.memories.len();
1130 let memory = Memory {
1131 path,
1132 operator,
1133 expression,
1134 value: stored_value,
1135 prev_hash,
1136 hash,
1137 };
1138
1139 self.apply_memory(&memory)?;
1140 self.bump_path_version(&source_path);
1141 self.memories.push(memory);
1142 self.record_event_from_memory(memory_index, &source_path);
1143 if invalidate {
1144 self.invalidate_from_path(&source_path);
1145 }
1146 Ok(&self.memories[memory_index])
1147 }
1148
1149 fn apply_memory(&mut self, memory: &Memory) -> Result<(), KernelError> {
1150 let operator_kind = memory
1151 .operator
1152 .as_deref()
1153 .and_then(|operator| self.operator_kind(operator))
1154 .map(ToOwned::to_owned);
1155
1156 match operator_kind.as_deref() {
1157 Some("secret") => {
1158 self.secret_scopes.insert(memory.path.clone());
1159 move_index_prefix_to_private(
1160 &mut self.index,
1161 &mut self.private_index,
1162 &memory.path,
1163 );
1164 }
1165 Some("noise") => {
1166 self.noise_scopes.insert(memory.path.clone());
1167 }
1168 Some("remove") => {
1169 remove_index_prefix(&mut self.index, &memory.path);
1170 remove_index_prefix(&mut self.private_index, &memory.path);
1171 self.secret_scopes
1172 .retain(|scope| !path_starts_with(scope, &memory.path));
1173 self.noise_scopes
1174 .retain(|scope| !path_starts_with(scope, &memory.path));
1175 self.local_secrets
1176 .retain(|scope, _| !path_starts_with(scope, &memory.path));
1177 self.local_noises
1178 .retain(|scope, _| !path_starts_with(scope, &memory.path));
1179 self.clear_derivations_by_prefix(&memory.path);
1180 }
1181 Some("identity") if memory.path.is_empty() => {
1182 if let Value::Identity(id) = &memory.value {
1183 self.active_identity = Some(id.clone());
1184 }
1185 self.index.insert(memory.path.clone(), memory.value.clone());
1186 }
1187 _ if self.is_under_secret_scope(&memory.path) => {
1188 self.index.remove(&memory.path);
1189 let value = self.value_for_private_index(memory)?;
1190 self.private_index.insert(memory.path.clone(), value);
1191 }
1192 _ => {
1193 self.index.insert(memory.path.clone(), memory.value.clone());
1194 }
1195 }
1196 Ok(())
1197 }
1198
1199 fn record_event_from_memory(&mut self, memory_index: usize, path: &[String]) {
1200 let Some(memory) = self.memories.get(memory_index) else {
1201 return;
1202 };
1203 self.events.push(KernelEvent {
1204 path: path.to_vec(),
1205 operator: memory.operator.clone(),
1206 value: self.read_owner_path(path).cloned(),
1207 memory_hash: memory.hash.clone(),
1208 });
1209 }
1210
1211 fn learn_record(&mut self, memory: &Memory) -> Result<(), KernelError> {
1212 let operator_kind = memory
1213 .operator
1214 .as_deref()
1215 .and_then(|operator| self.operator_kind(operator))
1216 .map(ToOwned::to_owned);
1217
1218 if memory.path.is_empty() && operator_kind.as_deref() != Some("identity") {
1219 return Err(KernelError::EmptyPath);
1220 }
1221
1222 match operator_kind.as_deref() {
1223 Some("secret") => {
1224 let secret = secret_from_memory(memory);
1225 let memory_index = self.memories.len();
1226 self.local_secrets.insert(memory.path.clone(), secret);
1227 self.commit_memory_with_expression(
1228 memory.path.clone(),
1229 memory.operator.clone(),
1230 Value::String("***".to_string()),
1231 memory.expression.clone(),
1232 true,
1233 )?;
1234 debug_assert_eq!(self.memories.len(), memory_index + 1);
1235 }
1236 Some("noise") => {
1237 let noise = secret_from_memory(memory);
1238 let memory_index = self.memories.len();
1239 self.local_noises.insert(memory.path.clone(), noise);
1240 self.commit_memory_with_expression(
1241 memory.path.clone(),
1242 memory.operator.clone(),
1243 Value::String("***".to_string()),
1244 memory.expression.clone(),
1245 true,
1246 )?;
1247 debug_assert_eq!(self.memories.len(), memory_index + 1);
1248 }
1249 Some("identity") => {
1250 let id = identity_from_memory(memory)?;
1251 let id = normalize_identity(&id)?;
1252 self.commit_memory_with_expression(
1253 memory.path.clone(),
1254 memory.operator.clone(),
1255 Value::Identity(id.clone()),
1256 memory.expression.clone(),
1257 true,
1258 )?;
1259 if memory.path.is_empty() {
1260 self.active_identity = Some(id);
1261 }
1262 }
1263 Some("pointer") => {
1264 let target = pointer_from_memory(memory)?;
1265 self.commit_memory_with_expression(
1266 memory.path.clone(),
1267 memory.operator.clone(),
1268 Value::Pointer(target),
1269 memory.expression.clone(),
1270 true,
1271 )?;
1272 }
1273 Some("remove") => {
1274 self.commit_memory_with_expression(
1275 memory.path.clone(),
1276 memory.operator.clone(),
1277 Value::String("-".to_string()),
1278 memory.expression.clone(),
1279 true,
1280 )?;
1281 }
1282 Some("eval") => {
1283 if let Some(expression) = expression_string_from_memory(memory) {
1284 let eval_scope = parent_path(&memory.path);
1285 self.register_derivation(memory.path.clone(), eval_scope, expression);
1286 }
1287 self.commit_memory_with_expression(
1288 memory.path.clone(),
1289 memory.operator.clone(),
1290 memory.value.clone(),
1291 memory.expression.clone(),
1292 true,
1293 )?;
1294 }
1295 _ => {
1296 self.commit_memory_with_expression(
1297 memory.path.clone(),
1298 memory.operator.clone(),
1299 memory.value.clone(),
1300 memory.expression.clone(),
1301 true,
1302 )?;
1303 }
1304 }
1305
1306 Ok(())
1307 }
1308
1309 fn is_under_secret_scope(&self, path: &[String]) -> bool {
1310 self.secret_scopes
1311 .iter()
1312 .any(|scope| path_starts_with(path, scope))
1313 }
1314
1315 fn stored_value_for_memory(
1316 &self,
1317 path: &[String],
1318 operator: Option<&str>,
1319 value: &Value,
1320 ) -> Result<Value, KernelError> {
1321 if !self.should_encrypt_memory_value(path, operator, value) {
1322 return Ok(value.clone());
1323 }
1324 let nonce = random_blob_v3_nonce().ok_or(KernelError::RandomUnavailable)?;
1325 let blob = self.encrypt_secret_value_v3(path.to_vec(), value.clone(), nonce)?;
1326 Ok(Value::String(blob))
1327 }
1328
1329 fn should_encrypt_memory_value(
1330 &self,
1331 path: &[String],
1332 operator: Option<&str>,
1333 value: &Value,
1334 ) -> bool {
1335 operator.is_none()
1336 && self.is_under_secret_scope(path)
1337 && !matches!(value, Value::Pointer(_) | Value::Identity(_))
1338 }
1339
1340 fn value_for_private_index(&self, memory: &Memory) -> Result<Value, KernelError> {
1341 if !self.should_encrypt_memory_value(
1342 &memory.path,
1343 memory.operator.as_deref(),
1344 &memory.value,
1345 ) {
1346 return Ok(memory.value.clone());
1347 }
1348 let Value::String(blob) = &memory.value else {
1349 return Err(KernelError::SecretBlobDecryptFailed(memory.path.clone()));
1350 };
1351 self.decrypt_secret_value_v3(memory.path.clone(), blob)?
1352 .ok_or_else(|| KernelError::SecretBlobDecryptFailed(memory.path.clone()))
1353 }
1354
1355 fn compute_effective_secret(&self, path: &[String]) -> String {
1356 let active_noise = self.find_active_noise(path);
1357 let mut seed = String::from("root");
1358
1359 if let Some((_, noise)) = &active_noise {
1360 seed = portable_hash_fnv1a(&format!("noise::{noise}"));
1361 }
1362
1363 for index in 1..=path.len() {
1364 let secret_path = path[..index].to_vec();
1365 let Some(secret) = self.local_secrets.get(&secret_path) else {
1366 continue;
1367 };
1368 if !secret_allowed_under_noise(
1369 active_noise.as_ref().map(|(path, _)| path),
1370 &secret_path,
1371 ) {
1372 continue;
1373 }
1374 seed = portable_hash_fnv1a(&format!("{seed}::{secret}"));
1375 }
1376
1377 if seed == "root" {
1378 String::new()
1379 } else {
1380 seed
1381 }
1382 }
1383
1384 fn find_active_noise(&self, path: &[String]) -> Option<(Path, String)> {
1385 let mut active = None;
1386 for index in 1..=path.len() {
1387 let noise_path = path[..index].to_vec();
1388 if let Some(noise) = self.local_noises.get(&noise_path) {
1389 active = Some((noise_path, noise.clone()));
1390 }
1391 }
1392 active
1393 }
1394
1395 fn collect_secret_chain_v3(
1396 &self,
1397 target_path: &[String],
1398 mode: SecretMaterialMode,
1399 ) -> Result<Vec<Vec<u8>>, KernelError> {
1400 let scope_path = self
1401 .resolve_branch_scope(target_path)
1402 .ok_or_else(|| KernelError::NoSecretContext(target_path.to_vec()))?;
1403 if mode == SecretMaterialMode::Branch && scope_path.is_empty() {
1404 return Err(KernelError::RootSecretBranchUnsupported);
1405 }
1406
1407 let anchor_path = match mode {
1408 SecretMaterialMode::Branch => scope_path.clone(),
1409 SecretMaterialMode::Value => target_path.to_vec(),
1410 };
1411 let active_noise = self.find_active_noise(&anchor_path);
1412 let noise_boundary = active_noise
1413 .as_ref()
1414 .map(|(path, _)| path.join("."))
1415 .unwrap_or_else(|| V3_NO_NOISE_SENTINEL.to_string());
1416
1417 let mut chain = vec![
1418 V3_DOMAIN.as_bytes().to_vec(),
1419 match mode {
1420 SecretMaterialMode::Branch => b"branch".to_vec(),
1421 SecretMaterialMode::Value => b"value".to_vec(),
1422 },
1423 scope_path.join(".").into_bytes(),
1424 anchor_path.join(".").into_bytes(),
1425 noise_boundary.into_bytes(),
1426 ];
1427 chain.extend(self.collect_lineage_segments(&anchor_path, active_noise.as_ref()));
1428 Ok(chain)
1429 }
1430
1431 fn resolve_branch_scope(&self, path: &[String]) -> Option<Path> {
1432 let mut best = self.local_secrets.get(&Vec::new()).map(|_| Vec::new());
1433 for index in 1..=path.len() {
1434 let scope_path = path[..index].to_vec();
1435 if self.local_secrets.contains_key(&scope_path) {
1436 best = Some(scope_path);
1437 }
1438 }
1439 best
1440 }
1441
1442 fn collect_lineage_segments(
1443 &self,
1444 anchor_path: &[String],
1445 active_noise: Option<&(Path, String)>,
1446 ) -> Vec<Vec<u8>> {
1447 let mut out = Vec::new();
1448
1449 if let Some((path, noise)) = active_noise {
1450 out.push(lineage_segment("noise", &path.join("."), noise));
1451 } else if let Some(root_secret) = self.local_secrets.get(&Vec::new()) {
1452 out.push(lineage_segment("secret", "", root_secret));
1453 }
1454
1455 for index in 1..=anchor_path.len() {
1456 let secret_path = anchor_path[..index].to_vec();
1457 let Some(secret) = self.local_secrets.get(&secret_path) else {
1458 continue;
1459 };
1460 if !secret_allowed_under_noise(active_noise.map(|(path, _)| path), &secret_path) {
1461 continue;
1462 }
1463 out.push(lineage_segment("secret", &secret_path.join("."), secret));
1464 }
1465
1466 out
1467 }
1468
1469 fn register_derivation(&mut self, target_path: Path, eval_scope: Path, expression: String) {
1470 self.unregister_derivation(&target_path);
1471
1472 let mut seen = BTreeSet::new();
1473 let refs = extract_expression_refs(&expression)
1474 .into_iter()
1475 .flat_map(|label| {
1476 self.resolve_derivation_ref_paths(&label, &eval_scope)
1477 .into_iter()
1478 .map(move |path| (label.clone(), path))
1479 })
1480 .filter_map(|(label, path)| {
1481 seen.insert((label.clone(), path.clone()))
1482 .then_some(DerivationRef { label, path })
1483 })
1484 .collect::<Vec<_>>();
1485 let ref_versions = refs
1486 .iter()
1487 .map(|reference| {
1488 (
1489 reference.path.clone(),
1490 self.current_path_version(&reference.path),
1491 )
1492 })
1493 .collect::<BTreeMap<_, _>>();
1494
1495 for reference in &refs {
1496 self.ref_subscribers
1497 .entry(reference.path.clone())
1498 .or_default()
1499 .insert(target_path.clone());
1500 }
1501
1502 self.derivations.insert(
1503 target_path,
1504 DerivationRecord {
1505 eval_scope,
1506 expression,
1507 refs,
1508 ref_versions,
1509 },
1510 );
1511 }
1512
1513 fn resolve_derivation_ref_paths(&self, label: &str, eval_scope: &[String]) -> Vec<Path> {
1514 let Ok(parts) = label.into_path() else {
1515 return Vec::new();
1516 };
1517 if parts.is_empty() {
1518 return Vec::new();
1519 }
1520 if label.contains('.') {
1521 return vec![parts];
1522 }
1523
1524 let relative = eval_scope
1525 .iter()
1526 .cloned()
1527 .chain(parts.iter().cloned())
1528 .collect::<Path>();
1529 if relative == parts || self.read(relative.clone()).is_some() {
1530 return vec![relative];
1531 }
1532 if self.read(parts.clone()).is_some() {
1533 return vec![parts];
1534 }
1535 vec![relative]
1536 }
1537
1538 fn unregister_derivation(&mut self, target_path: &[String]) {
1539 let Some(record) = self.derivations.remove(target_path) else {
1540 return;
1541 };
1542 self.last_recompute_wave_by_target.remove(target_path);
1543
1544 for reference in record.refs {
1545 if let Some(subscribers) = self.ref_subscribers.get_mut(&reference.path) {
1546 subscribers.remove(target_path);
1547 if subscribers.is_empty() {
1548 self.ref_subscribers.remove(&reference.path);
1549 }
1550 }
1551 }
1552 }
1553
1554 fn clear_derivations_by_prefix(&mut self, prefix: &[String]) {
1555 let targets = self
1556 .derivations
1557 .keys()
1558 .filter(|target| path_starts_with(target, prefix))
1559 .cloned()
1560 .collect::<Vec<_>>();
1561
1562 for target in targets {
1563 self.unregister_derivation(&target);
1564 }
1565 }
1566
1567 fn invalidate_from_path(&mut self, source_path: &[String]) {
1568 if self.recompute_mode == RecomputeMode::Lazy {
1569 return;
1570 }
1571
1572 let started_wave = self.begin_recompute_wave(source_path);
1573 let mut queue = VecDeque::from([source_path.to_vec()]);
1574 let mut seen_targets = BTreeSet::new();
1575
1576 while let Some(changed_path) = queue.pop_front() {
1577 let subscribers = self
1578 .ref_subscribers
1579 .get(&changed_path)
1580 .cloned()
1581 .unwrap_or_default();
1582
1583 for target_path in subscribers {
1584 if !seen_targets.insert(target_path.clone()) {
1585 continue;
1586 }
1587 if self.recompute_target(&target_path) {
1588 queue.push_back(target_path);
1589 }
1590 }
1591 }
1592
1593 if started_wave {
1594 self.finalize_recompute_wave();
1595 }
1596 }
1597
1598 fn recompute_target(&mut self, target_path: &[String]) -> bool {
1599 let Some(record) = self.derivations.get(target_path).cloned() else {
1600 return false;
1601 };
1602
1603 let value = self
1604 .evaluate_expression(&record.eval_scope, &record.expression)
1605 .unwrap_or_else(|| Value::String(record.expression.clone()));
1606
1607 let recomputed = self
1608 .commit_memory_with_expression(
1609 target_path.to_vec(),
1610 Some("=".to_string()),
1611 value,
1612 Some(Value::String(record.expression)),
1613 false,
1614 )
1615 .is_ok();
1616
1617 if recomputed {
1618 self.refresh_derivation_ref_versions(target_path);
1619 self.record_recomputed_target(target_path);
1620 }
1621
1622 recomputed
1623 }
1624
1625 fn ensure_target_fresh(
1626 &mut self,
1627 target_path: &[String],
1628 visiting: &mut BTreeSet<Path>,
1629 ) -> bool {
1630 if self.recompute_mode != RecomputeMode::Lazy {
1631 return false;
1632 }
1633 if !self.derivations.contains_key(target_path) {
1634 return false;
1635 }
1636 if !visiting.insert(target_path.to_vec()) {
1637 return false;
1638 }
1639
1640 let started_wave = self.begin_recompute_wave(target_path);
1641 let refs = self
1642 .derivations
1643 .get(target_path)
1644 .map(|record| record.refs.clone())
1645 .unwrap_or_default();
1646
1647 for reference in refs {
1648 if self.derivations.contains_key(&reference.path) {
1649 self.ensure_target_fresh(&reference.path, visiting);
1650 }
1651 }
1652
1653 let changed = if self.derivation_refs_changed(target_path) {
1654 self.recompute_target(target_path)
1655 } else {
1656 false
1657 };
1658
1659 visiting.remove(target_path);
1660 if started_wave {
1661 self.finalize_recompute_wave();
1662 }
1663 changed
1664 }
1665
1666 fn current_path_version(&self, path: &[String]) -> u64 {
1667 self.path_versions.get(path).copied().unwrap_or_default()
1668 }
1669
1670 fn bump_path_version(&mut self, path: &[String]) {
1671 self.path_version_clock = self.path_version_clock.saturating_add(1);
1672 self.path_versions
1673 .insert(path.to_vec(), self.path_version_clock);
1674 }
1675
1676 fn derivation_refs_changed(&self, target_path: &[String]) -> bool {
1677 let Some(record) = self.derivations.get(target_path) else {
1678 return false;
1679 };
1680
1681 record.refs.iter().any(|reference| {
1682 self.current_path_version(&reference.path)
1683 > record
1684 .ref_versions
1685 .get(&reference.path)
1686 .copied()
1687 .unwrap_or_default()
1688 })
1689 }
1690
1691 fn refresh_derivation_ref_versions(&mut self, target_path: &[String]) {
1692 let Some(refs) = self
1693 .derivations
1694 .get(target_path)
1695 .map(|record| record.refs.clone())
1696 else {
1697 return;
1698 };
1699
1700 let ref_versions = refs
1701 .iter()
1702 .map(|reference| {
1703 (
1704 reference.path.clone(),
1705 self.current_path_version(&reference.path),
1706 )
1707 })
1708 .collect::<BTreeMap<_, _>>();
1709
1710 if let Some(record) = self.derivations.get_mut(target_path) {
1711 record.ref_versions = ref_versions;
1712 }
1713 }
1714
1715 fn begin_recompute_wave(&mut self, source_path: &[String]) -> bool {
1716 if self.active_recompute_wave.is_some() {
1717 return false;
1718 }
1719 self.active_recompute_wave = Some(RecomputeWave {
1720 source_path: source_path.to_vec(),
1721 recomputed: BTreeSet::new(),
1722 });
1723 true
1724 }
1725
1726 fn record_recomputed_target(&mut self, target_path: &[String]) {
1727 let Some(wave) = &mut self.active_recompute_wave else {
1728 return;
1729 };
1730 wave.recomputed.insert(target_path.to_vec());
1731 }
1732
1733 fn finalize_recompute_wave(&mut self) {
1734 let Some(wave) = self.active_recompute_wave.take() else {
1735 return;
1736 };
1737 if wave.recomputed.is_empty() {
1738 return;
1739 }
1740 let wave = Arc::new(wave);
1741 for target_path in &wave.recomputed {
1742 self.last_recompute_wave_by_target
1743 .insert(target_path.clone(), Arc::clone(&wave));
1744 }
1745 }
1746
1747 fn evaluate_expression(&self, eval_scope: &[String], expression: &str) -> Option<Value> {
1748 evaluate_expression(self, eval_scope, expression)
1749 }
1750
1751 fn collect_from_scope<I, P>(&self, scope: &[String], paths: I) -> Result<Value, KernelError>
1752 where
1753 I: IntoIterator<Item = P>,
1754 P: IntoPath,
1755 {
1756 let mut values = Vec::new();
1757
1758 for path in paths {
1759 let path = path.into_path().map_err(KernelError::InvalidPath)?;
1760 if path.is_empty() {
1761 return Err(KernelError::EmptyPath);
1762 }
1763 let path = resolve_query_path(scope, path);
1764 values.push(self.read(path).cloned().unwrap_or(Value::Null));
1765 }
1766
1767 if values.is_empty() {
1768 return Err(KernelError::EmptyQuery);
1769 }
1770
1771 Ok(Value::Array(values))
1772 }
1773
1774 fn inspect_memories<'a>(&self, memories: impl Iterator<Item = &'a Memory>) -> InspectResult {
1775 InspectResult {
1776 memories: memories
1777 .map(|memory| InspectMemory {
1778 path: memory.path.clone(),
1779 operator: memory.operator.clone(),
1780 expression: if self.is_under_secret_scope(&memory.path) {
1781 None
1782 } else {
1783 memory.expression.clone()
1784 },
1785 value: if self.is_under_secret_scope(&memory.path) {
1786 Value::String("****".to_string())
1787 } else {
1788 memory.value.clone()
1789 },
1790 prev_hash: memory.prev_hash.clone(),
1791 hash: memory.hash.clone(),
1792 })
1793 .collect(),
1794 index: self.index.clone(),
1795 secret_scopes: self.secret_scopes.iter().cloned().collect(),
1796 noise_scopes: self.noise_scopes.iter().cloned().collect(),
1797 derivations: self.derivations.keys().cloned().collect(),
1798 }
1799 }
1800}
1801
1802fn remove_index_prefix(index: &mut BTreeMap<Path, Value>, prefix: &[String]) {
1803 index.retain(|path, _| !path_starts_with(path, prefix));
1804}
1805
1806fn insert_subtree_value(root: &mut BTreeMap<String, Value>, rel_path: &[String], value: Value) {
1807 let Some((head, tail)) = rel_path.split_first() else {
1808 return;
1809 };
1810 if tail.is_empty() {
1811 root.insert(head.clone(), value);
1812 return;
1813 }
1814
1815 let entry = root
1816 .entry(head.clone())
1817 .or_insert_with(|| Value::Object(BTreeMap::new()));
1818 if !matches!(entry, Value::Object(_)) {
1819 *entry = Value::Object(BTreeMap::new());
1820 }
1821 let Value::Object(child) = entry else {
1822 return;
1823 };
1824 insert_subtree_value(child, tail, value);
1825}
1826
1827fn default_operators() -> BTreeMap<String, OperatorDefinition> {
1828 [
1829 ("_", "secret"),
1830 ("~", "noise"),
1831 ("__", "pointer"),
1832 ("->", "pointer"),
1833 ("@", "identity"),
1834 ("=", "eval"),
1835 ("?", "query"),
1836 ("-", "remove"),
1837 ]
1838 .into_iter()
1839 .map(|(operator, kind)| {
1840 (
1841 operator.to_string(),
1842 OperatorDefinition {
1843 kind: kind.to_string(),
1844 },
1845 )
1846 })
1847 .collect()
1848}
1849
1850fn move_index_prefix_to_private(
1851 index: &mut BTreeMap<Path, Value>,
1852 private_index: &mut BTreeMap<Path, Value>,
1853 prefix: &[String],
1854) {
1855 let keys = index
1856 .keys()
1857 .filter(|path| path_starts_with(path, prefix))
1858 .cloned()
1859 .collect::<Vec<_>>();
1860
1861 for key in keys {
1862 if let Some(value) = index.remove(&key) {
1863 private_index.insert(key, value);
1864 }
1865 }
1866}
1867
1868fn path_starts_with(path: &[String], prefix: &[String]) -> bool {
1869 path.len() >= prefix.len() && path.iter().zip(prefix).all(|(left, right)| left == right)
1870}
1871
1872fn parent_path(path: &[String]) -> Path {
1873 path.split_last()
1874 .map(|(_, parent)| parent.to_vec())
1875 .unwrap_or_default()
1876}
1877
1878fn resolve_query_path(scope: &[String], path: Path) -> Path {
1879 if scope.is_empty() || path.len() != 1 {
1880 return path;
1881 }
1882 scope.iter().cloned().chain(path).collect()
1883}
1884
1885fn secret_from_memory(memory: &Memory) -> String {
1886 memory
1887 .expression
1888 .as_ref()
1889 .and_then(string_from_value)
1890 .filter(|value| !value.is_empty())
1891 .map(|value| value.trim().to_string())
1892 .or_else(|| match &memory.value {
1893 Value::String(value) => {
1894 let value = value.trim();
1895 (!value.is_empty() && value != "***" && value != "****").then(|| value.to_string())
1896 }
1897 _ => None,
1898 })
1899 .unwrap_or_else(|| "***".to_string())
1900}
1901
1902fn identity_from_memory(memory: &Memory) -> Result<String, KernelError> {
1903 identity_from_value(&memory.value)
1904 .or_else(|| memory.expression.as_ref().and_then(identity_from_value))
1905 .ok_or_else(|| KernelError::InvalidIdentity(String::new()))
1906}
1907
1908fn identity_from_value(value: &Value) -> Option<String> {
1909 match value {
1910 Value::Identity(id) | Value::String(id) => Some(id.clone()),
1911 Value::Object(values) => values.get("__id").and_then(identity_from_value),
1912 _ => None,
1913 }
1914}
1915
1916fn pointer_from_memory(memory: &Memory) -> Result<Path, KernelError> {
1917 pointer_from_value(&memory.value)
1918 .or_else(|| memory.expression.as_ref().and_then(pointer_from_value))
1919 .filter(|path| !path.is_empty())
1920 .ok_or(KernelError::EmptyPath)
1921}
1922
1923fn pointer_from_value(value: &Value) -> Option<Path> {
1924 match value {
1925 Value::Pointer(path) => Some(path.clone()),
1926 Value::String(path) => path.as_str().into_path().ok(),
1927 Value::Object(values) => values.get("__ptr").and_then(pointer_from_value),
1928 _ => None,
1929 }
1930}
1931
1932fn expression_string_from_memory(memory: &Memory) -> Option<String> {
1933 memory.expression.as_ref().and_then(string_from_value)
1934}
1935
1936fn string_from_value(value: &Value) -> Option<String> {
1937 match value {
1938 Value::String(value) => Some(value.trim().to_string()),
1939 _ => None,
1940 }
1941}
1942
1943fn ensure_value_is_supported(value: &Value) -> Result<(), KernelError> {
1944 match value {
1945 Value::Number(number) if !number.is_finite() => Err(KernelError::NonFiniteNumber),
1946 Value::Array(values) => {
1947 for value in values {
1948 ensure_value_is_supported(value)?;
1949 }
1950 Ok(())
1951 }
1952 Value::Object(values) => {
1953 for value in values.values() {
1954 ensure_value_is_supported(value)?;
1955 }
1956 Ok(())
1957 }
1958 Value::Pointer(path) if path.is_empty() => Err(KernelError::EmptyPath),
1959 Value::Identity(id) => normalize_identity(id).map(|_| ()),
1960 _ => Ok(()),
1961 }
1962}
1963
1964fn normalize_identity(input: &str) -> Result<String, KernelError> {
1965 let id = input.trim().to_ascii_lowercase();
1966 if id.len() < 3 || id.len() > 63 {
1967 return Err(KernelError::InvalidIdentity(input.to_string()));
1968 }
1969 if id.contains('.') {
1970 return Err(KernelError::InvalidIdentity(input.to_string()));
1971 }
1972
1973 let bytes = id.as_bytes();
1974 let is_label_char =
1975 |byte: u8| byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'-';
1976 let is_edge_char = |byte: u8| byte.is_ascii_lowercase() || byte.is_ascii_digit();
1977
1978 if !bytes.iter().copied().all(is_label_char) {
1979 return Err(KernelError::InvalidIdentity(input.to_string()));
1980 }
1981 if !is_edge_char(bytes[0]) || !is_edge_char(bytes[bytes.len() - 1]) {
1982 return Err(KernelError::InvalidIdentity(input.to_string()));
1983 }
1984
1985 Ok(id)
1986}
1987
1988fn hash_memory(
1989 path: &[String],
1990 operator: Option<&str>,
1991 expression: Option<&Value>,
1992 value: &Value,
1993 effective_secret: &str,
1994 prev_hash: Option<&str>,
1995) -> String {
1996 let mut input = String::new();
1997 input.push_str("{\"path\":");
1998 push_json_string(&mut input, &path.join("."));
1999 input.push_str(",\"operator\":");
2000 push_json_optional_string(&mut input, operator);
2001 input.push_str(",\"expression\":");
2002 push_json_optional_value(&mut input, expression);
2003 input.push_str(",\"value\":");
2004 push_json_value(&mut input, value);
2005 input.push_str(",\"effectiveSecret\":");
2006 push_json_string(&mut input, effective_secret);
2007 input.push_str(",\"prevHash\":");
2008 push_json_string(&mut input, prev_hash.unwrap_or(""));
2009 input.push('}');
2010
2011 portable_hash_fnv1a(&input)
2012}
2013
2014fn secret_allowed_under_noise(noise_path: Option<&Path>, secret_path: &[String]) -> bool {
2015 let Some(noise_path) = noise_path else {
2016 return true;
2017 };
2018 path_starts_with(secret_path, noise_path)
2019}
2020
2021fn event_matches_subscription_path(subscribed_path: &[String], written_path: &[String]) -> bool {
2022 subscribed_path.is_empty()
2023 || subscribed_path == written_path
2024 || path_starts_with(subscribed_path, written_path)
2025 || path_starts_with(written_path, subscribed_path)
2026}
2027
2028fn portable_hash_fnv1a(input: &str) -> String {
2029 let mut hash = 0x811c_9dc5_u32;
2030 for unit in input.encode_utf16() {
2031 hash ^= u32::from(unit);
2032 hash = hash.wrapping_mul(0x0100_0193);
2033 }
2034 format!("{hash:08x}")
2035}
2036
2037fn push_json_optional_string(out: &mut String, value: Option<&str>) {
2038 match value {
2039 Some(value) => push_json_string(out, value),
2040 None => out.push_str("null"),
2041 }
2042}
2043
2044fn push_json_optional_value(out: &mut String, value: Option<&Value>) {
2045 match value {
2046 Some(value) => push_json_value(out, value),
2047 None => out.push_str("null"),
2048 }
2049}
2050
2051fn push_json_string(out: &mut String, value: &str) {
2052 out.push('"');
2053 for ch in value.chars() {
2054 match ch {
2055 '"' => out.push_str("\\\""),
2056 '\\' => out.push_str("\\\\"),
2057 '\u{08}' => out.push_str("\\b"),
2058 '\u{0c}' => out.push_str("\\f"),
2059 '\n' => out.push_str("\\n"),
2060 '\r' => out.push_str("\\r"),
2061 '\t' => out.push_str("\\t"),
2062 ch if ch <= '\u{1f}' => {
2063 out.push_str("\\u00");
2064 push_hex_nibble(out, (ch as u32 >> 4) & 0x0f);
2065 push_hex_nibble(out, ch as u32 & 0x0f);
2066 }
2067 ch => out.push(ch),
2068 }
2069 }
2070 out.push('"');
2071}
2072
2073fn push_hex_nibble(out: &mut String, value: u32) {
2074 let ch = match value {
2075 0..=9 => char::from(b'0' + value as u8),
2076 10..=15 => char::from(b'a' + (value as u8 - 10)),
2077 _ => unreachable!("hex nibble must be <= 15"),
2078 };
2079 out.push(ch);
2080}
2081
2082fn push_json_value(out: &mut String, value: &Value) {
2083 match value {
2084 Value::Null => out.push_str("null"),
2085 Value::Bool(value) => out.push_str(if *value { "true" } else { "false" }),
2086 Value::Number(value) => {
2087 if value.to_bits() == (-0.0_f64).to_bits() {
2088 out.push('0');
2089 } else {
2090 out.push_str(&value.to_string());
2091 }
2092 }
2093 Value::String(value) => push_json_string(out, value),
2094 Value::Array(values) => {
2095 out.push('[');
2096 for (index, value) in values.iter().enumerate() {
2097 if index > 0 {
2098 out.push(',');
2099 }
2100 push_json_value(out, value);
2101 }
2102 out.push(']');
2103 }
2104 Value::Object(values) => {
2105 out.push('{');
2106 for (index, (key, value)) in values.iter().enumerate() {
2107 if index > 0 {
2108 out.push(',');
2109 }
2110 push_json_string(out, key);
2111 out.push(':');
2112 push_json_value(out, value);
2113 }
2114 out.push('}');
2115 }
2116 Value::Pointer(path) => {
2117 out.push_str("{\"__ptr\":");
2118 push_json_string(out, &path.join("."));
2119 out.push('}');
2120 }
2121 Value::Identity(id) => {
2122 out.push_str("{\"__id\":");
2123 push_json_string(out, id);
2124 out.push('}');
2125 }
2126 }
2127}
2128
2129fn json_to_value(input: &str) -> Option<Value> {
2130 let value = serde_json::from_str::<serde_json::Value>(input).ok()?;
2131 serde_json_to_value(value)
2132}
2133
2134fn serde_json_to_value(value: serde_json::Value) -> Option<Value> {
2135 match value {
2136 serde_json::Value::Null => Some(Value::Null),
2137 serde_json::Value::Bool(value) => Some(Value::Bool(value)),
2138 serde_json::Value::Number(value) => value.as_f64().map(Value::Number),
2139 serde_json::Value::String(value) => Some(Value::String(value)),
2140 serde_json::Value::Array(values) => values
2141 .into_iter()
2142 .map(serde_json_to_value)
2143 .collect::<Option<Vec<_>>>()
2144 .map(Value::Array),
2145 serde_json::Value::Object(values) => values
2146 .into_iter()
2147 .map(|(key, value)| serde_json_to_value(value).map(|value| (key, value)))
2148 .collect::<Option<BTreeMap<_, _>>>()
2149 .map(Value::Object),
2150 }
2151}