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