@feltdb/core 0.8.4 → 0.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/dist/create/package-versions.js +1 -1
  2. package/dist/create/server-source/Cargo.lock +165 -0
  3. package/dist/create/server-source/Cargo.toml +9 -0
  4. package/dist/create/server-source/crates/feltdb/Cargo.toml +3 -0
  5. package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +44 -44
  6. package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +12 -24
  7. package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +7 -13
  8. package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +13 -10
  9. package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +12 -9
  10. package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +78 -25
  11. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +16 -13
  12. package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +13 -5
  13. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +41 -22
  14. package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +33 -15
  15. package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +100 -33
  16. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +56 -20
  17. package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +116 -41
  18. package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +186 -55
  19. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +64 -26
  20. package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +46 -15
  21. package/dist/create/server-source/crates/feltdb/src/admission.rs +8 -15
  22. package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +43 -13
  23. package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +15 -42
  24. package/dist/create/server-source/crates/feltdb/src/analytics.rs +65 -19
  25. package/dist/create/server-source/crates/feltdb/src/application.rs +113 -30
  26. package/dist/create/server-source/crates/feltdb/src/authorization_security_tests.rs +475 -140
  27. package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +17 -15
  28. package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +0 -1
  29. package/dist/create/server-source/crates/feltdb/src/causal_backlog_bound.rs +59 -15
  30. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +266 -114
  31. package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +25 -7
  32. package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +10 -15
  33. package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +3 -11
  34. package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +14 -5
  35. package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +21 -25
  36. package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +14 -11
  37. package/dist/create/server-source/crates/feltdb/src/dedup_bound_investigation.rs +103 -22
  38. package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +18 -15
  39. package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +12 -8
  40. package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +1 -5
  41. package/dist/create/server-source/crates/feltdb/src/durable_operation_identity.rs +87 -23
  42. package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +3 -7
  43. package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +10 -9
  44. package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +1 -6
  45. package/dist/create/server-source/crates/feltdb/src/indexing.rs +35 -38
  46. package/dist/create/server-source/crates/feltdb/src/lib.rs +1648 -46
  47. package/dist/create/server-source/crates/feltdb/src/managed_cas_tests.rs +4 -1
  48. package/dist/create/server-source/crates/feltdb/src/metrics.rs +0 -1
  49. package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +1 -2
  50. package/dist/create/server-source/crates/feltdb/src/multi_operation_transaction.rs +107 -30
  51. package/dist/create/server-source/crates/feltdb/src/observability.rs +19 -6
  52. package/dist/create/server-source/crates/feltdb/src/operation.rs +39 -0
  53. package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +12 -11
  54. package/dist/create/server-source/crates/feltdb/src/operation_log.rs +9 -4
  55. package/dist/create/server-source/crates/feltdb/src/p1_application_atomicity.rs +65 -18
  56. package/dist/create/server-source/crates/feltdb/src/p1_atomicity_acceptance.rs +193 -57
  57. package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +37 -27
  58. package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +38 -10
  59. package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +20 -14
  60. package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +394 -229
  61. package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +8 -6
  62. package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +11 -13
  63. package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +79 -70
  64. package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +3 -3
  65. package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +33 -11
  66. package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +6 -6
  67. package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +14 -56
  68. package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +29 -27
  69. package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +35 -17
  70. package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +8 -2
  71. package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +59 -15
  72. package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +70 -17
  73. package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +23 -6
  74. package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +12 -3
  75. package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +41 -11
  76. package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +56 -25
  77. package/dist/create/server-source/crates/feltdb/src/policy_evaluation.rs +701 -245
  78. package/dist/create/server-source/crates/feltdb/src/production_api.rs +31 -13
  79. package/dist/create/server-source/crates/feltdb/src/query_performance.rs +6 -8
  80. package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +5 -5
  81. package/dist/create/server-source/crates/feltdb/src/replica_acknowledgements.rs +48 -18
  82. package/dist/create/server-source/crates/feltdb/src/replica_membership.rs +30 -11
  83. package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +6 -3
  84. package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +4 -3
  85. package/dist/create/server-source/crates/feltdb/src/sharding.rs +36 -10
  86. package/dist/create/server-source/crates/feltdb/src/state_conflict_contract.rs +516 -0
  87. package/dist/create/server-source/crates/feltdb/src/state_contract.rs +13 -4
  88. package/dist/create/server-source/crates/feltdb/src/state_diff_contract.rs +222 -0
  89. package/dist/create/server-source/crates/feltdb/src/state_facade.rs +82 -54
  90. package/dist/create/server-source/crates/feltdb/src/state_hash.rs +2 -2
  91. package/dist/create/server-source/crates/feltdb/src/state_model.rs +1565 -536
  92. package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +6 -3
  93. package/dist/create/server-source/crates/feltdb/src/state_trigger.rs +672 -0
  94. package/dist/create/server-source/crates/feltdb/src/storage.rs +9 -3
  95. package/dist/create/server-source/crates/feltdb/src/submission.rs +5 -11
  96. package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +6 -8
  97. package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +24 -35
  98. package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +24 -8
  99. package/dist/create/server-source/crates/feltdb/src/transaction_preconditions.rs +248 -59
  100. package/dist/create/server-source/crates/feltdb/src/transactions.rs +17 -20
  101. package/dist/create/server-source/crates/feltdb/src/trigger_contract.rs +749 -0
  102. package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +1 -0
  103. package/dist/create/server-source/crates/feltdb/src/workload.rs +512 -4
  104. package/dist/create/server-source/crates/feltdb/src/workload_diagnostics.rs +3 -4
  105. package/dist/create/server-source/crates/feltdb/tests/bounded_read_contract.rs +132 -0
  106. package/dist/create/server-source/crates/feltdb/tests/branching_evidence.rs +299 -0
  107. package/dist/create/server-source/crates/feltdb/tests/compaction_stall_contract.rs +272 -0
  108. package/dist/create/server-source/crates/feltdb/tests/crash_durability_contract.rs +467 -0
  109. package/dist/create/server-source/crates/feltdb/tests/current_revision_authority_evidence.rs +309 -0
  110. package/dist/create/server-source/crates/feltdb/tests/durable_backup_contract.rs +445 -0
  111. package/dist/create/server-source/crates/feltdb/tests/durable_corruption_contract.rs +518 -0
  112. package/dist/create/server-source/crates/feltdb/tests/durable_format_compatibility.rs +392 -0
  113. package/dist/create/server-source/crates/feltdb/tests/feltdb_state_boundary_tests.rs +436 -220
  114. package/dist/create/server-source/crates/feltdb/tests/fixtures/state_conflict_contract_corpus.json +1916 -0
  115. package/dist/create/server-source/crates/feltdb/tests/fixtures/state_diff_contract_corpus.json +1878 -0
  116. package/dist/create/server-source/crates/feltdb/tests/fixtures/trigger_contract_corpus.json +1862 -0
  117. package/dist/create/server-source/crates/feltdb/tests/operational_health_contract.rs +278 -0
  118. package/dist/create/server-source/crates/feltdb/tests/pr34_query_collection.rs +2 -1
  119. package/dist/create/server-source/crates/feltdb/tests/pr35_equality_index.rs +80 -25
  120. package/dist/create/server-source/crates/feltdb/tests/pr7_self_authorization_proof.rs +5 -8
  121. package/dist/create/server-source/crates/feltdb/tests/pr8_vocabulary_assessment.rs +52 -44
  122. package/dist/create/server-source/crates/feltdb/tests/pr9_phase2_boundary_tests.rs +33 -16
  123. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3a_path_a_tests.rs +22 -7
  124. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_authorized_mutations.rs +41 -22
  125. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_role_based_authorization.rs +25 -8
  126. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_simple_auth_delete.rs +9 -6
  127. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_team_delete_role_authorization.rs +120 -69
  128. package/dist/create/server-source/crates/feltdb/tests/pr9_teams_role_based_access.rs +21 -10
  129. package/dist/create/server-source/crates/feltdb/tests/production_readiness_contract.rs +1365 -0
  130. package/dist/create/server-source/crates/feltdb/tests/reconciliation_application.rs +868 -0
  131. package/dist/create/server-source/crates/feltdb/tests/reconciliation_wire_format_evidence.rs +221 -0
  132. package/dist/create/server-source/crates/feltdb/tests/replicated_history_contract.rs +417 -0
  133. package/dist/create/server-source/crates/feltdb/tests/resource_scoped_revisions.rs +338 -0
  134. package/dist/create/server-source/crates/feltdb/tests/revision_identity_contract.rs +1039 -0
  135. package/dist/create/server-source/crates/feltdb/tests/revision_model_decision.rs +739 -0
  136. package/dist/create/server-source/crates/feltdb/tests/revision_retention_boundary_evidence.rs +427 -0
  137. package/dist/create/server-source/crates/feltdb/tests/saas_authorization_integration.rs +3 -3
  138. package/dist/create/server-source/crates/feltdb/tests/saas_invitation_lifecycle.rs +25 -22
  139. package/dist/create/server-source/crates/feltdb/tests/state_conflict_contract_conformance.rs +1799 -0
  140. package/dist/create/server-source/crates/feltdb/tests/state_diff_contract_conformance.rs +1316 -0
  141. package/dist/create/server-source/crates/feltdb/tests/state_model_integration.rs +53 -61
  142. package/dist/create/server-source/crates/feltdb/tests/state_persistence_integration.rs +156 -61
  143. package/dist/create/server-source/crates/feltdb/tests/state_store_boundary_evidence.rs +299 -0
  144. package/dist/create/server-source/crates/feltdb/tests/sync_divergence_evidence.rs +255 -0
  145. package/dist/create/server-source/crates/feltdb/tests/three_way_input_boundary_evidence.rs +249 -0
  146. package/dist/create/server-source/crates/feltdb/tests/trigger_contract_conformance.rs +994 -0
  147. package/dist/create/server-source/crates/feltdb/tests/workload_envelope_contract.rs +442 -0
  148. package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +16 -1
  149. package/dist/create/server-source/crates/feltdb-server/src/auth.rs +164 -13
  150. package/dist/create/server-source/crates/feltdb-server/src/main.rs +695 -47
  151. package/dist/create/server-source/crates/feltdb-server/src/metrics.rs +21 -0
  152. package/dist/studio-app/assets/{feltdb_wasm-CVQWgXO-.js → feltdb_wasm-C1VhI-U5.js} +1 -1
  153. package/dist/studio-app/assets/feltdb_wasm_bg-C8HXbAXb.wasm +0 -0
  154. package/dist/studio-app/assets/{index-DwgNAIIX.js → index-Bbos1m2U.js} +1 -1
  155. package/dist/studio-app/index.html +1 -1
  156. package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
  157. package/dist/workload.d.ts +2 -1
  158. package/dist/workload.d.ts.map +1 -1
  159. package/package.json +1 -1
  160. package/dist/studio-app/assets/feltdb_wasm_bg-CNVpvaZV.wasm +0 -0
@@ -40,6 +40,17 @@ pub struct ApiKeyRecord {
40
40
  pub namespaces: Vec<String>,
41
41
  #[serde(default)]
42
42
  pub revoked: bool,
43
+ /// The worker this credential *is*, when it is a worker credential.
44
+ ///
45
+ /// A key without one authenticates as a service, which is what every key
46
+ /// did before this field existed and what every key without it still does.
47
+ /// A key with one authenticates as `Subject::Worker(worker_id)` and is
48
+ /// thereby **narrower**, not wider: the worker lifecycle routes compare the
49
+ /// authenticated subject against the `worker_id` in the request body, so
50
+ /// such a credential can act as exactly one worker and no other, and cannot
51
+ /// satisfy a check that requires a human or service subject.
52
+ #[serde(default)]
53
+ pub worker_id: Option<String>,
43
54
  }
44
55
 
45
56
  #[derive(Debug, Clone, Serialize)]
@@ -104,6 +115,9 @@ impl KeyStore {
104
115
  scopes: token.scopes,
105
116
  namespaces: vec![token.namespace],
106
117
  revoked: false,
118
+ // Legacy credentials predate worker identity and
119
+ // stay services, which is what they already were.
120
+ worker_id: None,
107
121
  });
108
122
  }
109
123
  (records, true)
@@ -141,12 +155,25 @@ impl KeyStore {
141
155
  .iter()
142
156
  .any(|allowed| allowed == "*" || allowed == namespace);
143
157
  if namespace_allowed && verify_api_key(token, &record.hash) {
144
- Some(Principal {
145
- key_id: record.id.clone(),
146
- scopes: record.scopes.clone(),
147
- subject_type: "service".into(),
148
- identity_id: None,
149
- session_id: None,
158
+ // The credential decides the subject type. A worker
159
+ // credential can never present as a service and a service
160
+ // credential can never present as a worker, because neither
161
+ // the request nor any header participates in this choice.
162
+ Some(match &record.worker_id {
163
+ Some(worker) => Principal {
164
+ key_id: record.id.clone(),
165
+ scopes: record.scopes.clone(),
166
+ subject_type: "worker".into(),
167
+ identity_id: Some(worker.clone()),
168
+ session_id: None,
169
+ },
170
+ None => Principal {
171
+ key_id: record.id.clone(),
172
+ scopes: record.scopes.clone(),
173
+ subject_type: "service".into(),
174
+ identity_id: None,
175
+ session_id: None,
176
+ },
150
177
  })
151
178
  } else {
152
179
  None
@@ -159,6 +186,21 @@ impl KeyStore {
159
186
  name: String,
160
187
  scopes: Vec<String>,
161
188
  namespaces: Vec<String>,
189
+ ) -> Result<CreatedApiKey, String> {
190
+ self.create_for_worker(name, scopes, namespaces, None)
191
+ }
192
+
193
+ /// Issue a credential that authenticates as one specific worker.
194
+ ///
195
+ /// `worker_id` of `None` produces an ordinary service credential, so this
196
+ /// is the one construction path and [`KeyStore::create`] is the common case
197
+ /// spelled out.
198
+ pub fn create_for_worker(
199
+ &self,
200
+ name: String,
201
+ scopes: Vec<String>,
202
+ namespaces: Vec<String>,
203
+ worker_id: Option<String>,
162
204
  ) -> Result<CreatedApiKey, String> {
163
205
  let secret: String = rand::thread_rng()
164
206
  .sample_iter(&Alphanumeric)
@@ -185,6 +227,7 @@ impl KeyStore {
185
227
  scopes,
186
228
  namespaces,
187
229
  revoked: false,
230
+ worker_id,
188
231
  });
189
232
  self.persist()?;
190
233
  Ok(CreatedApiKey { id, secret: token })
@@ -266,13 +309,11 @@ fn verify_api_key(token: &str, stored_hash: &str) -> bool {
266
309
  .is_ok();
267
310
  }
268
311
 
269
- PasswordHash::new(stored_hash)
270
- .ok()
271
- .is_some_and(|parsed| {
272
- Argon2::default()
273
- .verify_password(token.as_bytes(), &parsed)
274
- .is_ok()
275
- })
312
+ PasswordHash::new(stored_hash).ok().is_some_and(|parsed| {
313
+ Argon2::default()
314
+ .verify_password(token.as_bytes(), &parsed)
315
+ .is_ok()
316
+ })
276
317
  }
277
318
 
278
319
  #[cfg(test)]
@@ -341,4 +382,114 @@ mod tests {
341
382
  assert!(migrated.contains("managed-instance"));
342
383
  let _ = fs::remove_file(path);
343
384
  }
385
+
386
+ // ------------------------------------------------------------------
387
+ // Worker identity.
388
+ //
389
+ // The whole worker security boundary rests on one thing: which subject a
390
+ // credential authenticates as. That is decided here, by the stored
391
+ // credential alone — no request field, header or body participates — so
392
+ // these tests are the root of the boundary the workload lifecycle routes
393
+ // enforce further up.
394
+ // ------------------------------------------------------------------
395
+
396
+ fn key_store(name: &str) -> (PathBuf, KeyStore) {
397
+ let path = std::env::temp_dir().join(format!(
398
+ "feltdb-worker-identity-{name}-{}-{}.json",
399
+ std::process::id(),
400
+ rand::random::<u64>()
401
+ ));
402
+ let _ = fs::remove_file(&path);
403
+ let store = KeyStore::load(&path).unwrap();
404
+ (path, store)
405
+ }
406
+
407
+ #[test]
408
+ fn a_worker_credential_authenticates_as_that_one_worker() {
409
+ let (path, store) = key_store("worker");
410
+ let key = store
411
+ .create_for_worker(
412
+ "extractor".into(),
413
+ vec!["state:read".into()],
414
+ vec!["default".into()],
415
+ Some("worker-x".into()),
416
+ )
417
+ .unwrap();
418
+
419
+ let principal = store
420
+ .authenticate(&key.secret, "default")
421
+ .expect("authenticates");
422
+ assert_eq!(principal.subject_type, "worker");
423
+ assert_eq!(
424
+ principal.identity_id.as_deref(),
425
+ Some("worker-x"),
426
+ "the worker it is, not the key it uses, is the identity"
427
+ );
428
+ let _ = fs::remove_file(path);
429
+ }
430
+
431
+ #[test]
432
+ fn a_service_credential_cannot_present_as_a_worker() {
433
+ let (path, store) = key_store("service");
434
+ let key = store
435
+ .create(
436
+ "control-plane".into(),
437
+ vec!["state:read".into()],
438
+ vec!["default".into()],
439
+ )
440
+ .unwrap();
441
+
442
+ let principal = store
443
+ .authenticate(&key.secret, "default")
444
+ .expect("authenticates");
445
+ assert_eq!(
446
+ principal.subject_type, "service",
447
+ "a key issued without a worker is a service, exactly as before this field existed"
448
+ );
449
+ assert_eq!(principal.identity_id, None);
450
+ let _ = fs::remove_file(path);
451
+ }
452
+
453
+ #[test]
454
+ fn worker_identity_survives_a_restart_of_the_credential_store() {
455
+ let (path, store) = key_store("reload");
456
+ let key = store
457
+ .create_for_worker(
458
+ "extractor".into(),
459
+ vec!["state:read".into()],
460
+ vec!["default".into()],
461
+ Some("worker-x".into()),
462
+ )
463
+ .unwrap();
464
+ drop(store);
465
+
466
+ // A credential that forgot which worker it was on restart would silently
467
+ // downgrade to a service and start failing the identity check.
468
+ let reopened = KeyStore::load(&path).unwrap();
469
+ let principal = reopened
470
+ .authenticate(&key.secret, "default")
471
+ .expect("authenticates");
472
+ assert_eq!(principal.subject_type, "worker");
473
+ assert_eq!(principal.identity_id.as_deref(), Some("worker-x"));
474
+ let _ = fs::remove_file(path);
475
+ }
476
+
477
+ #[test]
478
+ fn a_revoked_worker_credential_authenticates_as_nothing() {
479
+ let (path, store) = key_store("revoked");
480
+ let key = store
481
+ .create_for_worker(
482
+ "extractor".into(),
483
+ vec!["state:read".into()],
484
+ vec!["default".into()],
485
+ Some("worker-x".into()),
486
+ )
487
+ .unwrap();
488
+ assert!(store.revoke(&key.id).unwrap());
489
+ assert!(
490
+ store.authenticate(&key.secret, "default").is_none(),
491
+ "revocation is not weakened by carrying a worker identity"
492
+ );
493
+ let _ = fs::remove_file(path);
494
+ }
344
495
  }