@feltdb/core 0.4.15 → 0.4.16

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 (37) hide show
  1. package/dist/cli/index.js +1 -1
  2. package/dist/create/package-versions.js +1 -1
  3. package/dist/create/server-source/crates/feltdb/Cargo.toml +1 -1
  4. package/dist/create/server-source/crates/feltdb/src/application.rs +93 -0
  5. package/dist/create/server-source/crates/feltdb/src/authorization_security_tests.rs +787 -0
  6. package/dist/create/server-source/crates/feltdb/src/lib.rs +139 -0
  7. package/dist/create/server-source/crates/feltdb/src/policy_evaluation.rs +1669 -0
  8. package/dist/create/server-source/crates/feltdb/src/state_contract.rs +1269 -15
  9. package/dist/create/server-source/crates/feltdb/tests/pr7_self_authorization_proof.rs +406 -0
  10. package/dist/create/server-source/crates/feltdb/tests/pr8_vocabulary_assessment.rs +908 -0
  11. package/dist/create/server-source/crates/feltdb/tests/pr9_phase2_boundary_tests.rs +1028 -0
  12. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3a_path_a_tests.rs +332 -0
  13. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_authorized_mutations.rs +342 -0
  14. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_role_based_authorization.rs +313 -0
  15. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_simple_auth_delete.rs +90 -0
  16. package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_team_delete_role_authorization.rs +571 -0
  17. package/dist/create/server-source/crates/feltdb/tests/pr9_teams_role_based_access.rs +506 -0
  18. package/dist/create/server-source/crates/feltdb/tests/saas_authorization_integration.rs +81 -0
  19. package/dist/create/server-source/crates/feltdb/tests/saas_invitation_lifecycle.rs +434 -0
  20. package/dist/create/server-source/crates/feltdb-server/src/main.rs +130 -23
  21. package/dist/create/server-source/crates/feltdb-wasm/src/lib.rs +2 -2
  22. package/dist/db.d.ts +10 -0
  23. package/dist/db.d.ts.map +1 -1
  24. package/dist/db.js +3 -1
  25. package/dist/file-db.d.ts +69 -0
  26. package/dist/file-db.d.ts.map +1 -0
  27. package/dist/file-db.js +355 -0
  28. package/dist/index.d.ts +1 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +1 -0
  31. package/dist/studio-app/assets/{feltdb_wasm-CJEJryDx.js → feltdb_wasm-CBGD0zRu.js} +1 -1
  32. package/dist/studio-app/assets/feltdb_wasm_bg-C6ATF9mJ.wasm +0 -0
  33. package/dist/studio-app/assets/{index-D_p8T7nO.js → index-D74dfBgZ.js} +9 -9
  34. package/dist/studio-app/index.html +1 -1
  35. package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
  36. package/package.json +7 -2
  37. package/dist/studio-app/assets/feltdb_wasm_bg-BJxQXtoo.wasm +0 -0
@@ -7,6 +7,9 @@ pub mod admission;
7
7
  pub mod application;
8
8
  pub mod application_runtime;
9
9
  pub mod authorization;
10
+ pub mod policy_evaluation;
11
+ #[cfg(test)]
12
+ mod authorization_security_tests;
10
13
  pub mod capabilities;
11
14
  mod capability;
12
15
  mod content_distribution;
@@ -233,6 +236,7 @@ use std::path::{Path, PathBuf};
233
236
  use std::sync::{Arc, Mutex};
234
237
  use std::time::{SystemTime, UNIX_EPOCH};
235
238
  use tokio::sync::broadcast;
239
+ use crate::state_contract::AuthorizationContext;
236
240
 
237
241
  pub type Result<T> = std::result::Result<T, FlowError>;
238
242
 
@@ -485,6 +489,112 @@ impl FeltDb {
485
489
  Ok(())
486
490
  }
487
491
 
492
+ /// Evaluate authorization for a mutation
493
+ fn evaluate_authorization(&self, context: &AuthorizationContext) -> Result<()> {
494
+ // Check basic capabilities
495
+ if !context.capabilities.contains(&"state:write".to_string()) {
496
+ return Err(FlowError::CapabilityError(
497
+ "AUTHORIZATION_DENIED:missing_state_write_capability".to_string(),
498
+ ));
499
+ }
500
+
501
+ // Tenant isolation check happens implicitly at mutation boundary
502
+ // by only checking against current database tenant_id
503
+
504
+ Ok(())
505
+ }
506
+
507
+ /// Insert a record with authorization context
508
+ pub fn insert_with_authorization<T: Serialize>(
509
+ &self,
510
+ key: &str,
511
+ value: T,
512
+ context: &AuthorizationContext,
513
+ ) -> Result<()> {
514
+ // Authorize mutation inside FeltDB boundary
515
+ self.evaluate_authorization(context)?;
516
+
517
+ let capability = key
518
+ .split_once(':')
519
+ .map(|(cap, _)| cap)
520
+ .unwrap_or("default")
521
+ .to_string();
522
+
523
+ // Check if capability is writable
524
+ if !context.writable_collections.is_empty()
525
+ && !context.writable_collections.contains(&capability)
526
+ {
527
+ return Err(FlowError::CapabilityError(
528
+ format!("AUTHORIZATION_DENIED:not_writable_collection:{}", capability),
529
+ ));
530
+ }
531
+
532
+ // Authorized: apply mutation
533
+ self.insert_internal(capability, key.to_string(), value)?;
534
+ Ok(())
535
+ }
536
+
537
+ /// Update a record with authorization context
538
+ pub fn update_with_authorization<T: Serialize>(
539
+ &self,
540
+ key: &str,
541
+ value: T,
542
+ context: &AuthorizationContext,
543
+ ) -> Result<()> {
544
+ // Authorize mutation inside FeltDB boundary
545
+ self.evaluate_authorization(context)?;
546
+
547
+ let capability = key
548
+ .split_once(':')
549
+ .map(|(cap, _)| cap)
550
+ .unwrap_or("default")
551
+ .to_string();
552
+
553
+ // Check if capability is writable
554
+ if !context.writable_collections.is_empty()
555
+ && !context.writable_collections.contains(&capability)
556
+ {
557
+ return Err(FlowError::CapabilityError(
558
+ format!("AUTHORIZATION_DENIED:not_writable_collection:{}", capability),
559
+ ));
560
+ }
561
+
562
+ // Authorized: apply mutation
563
+ // Pre-state evaluation would happen here in full implementation
564
+ self.update_internal(capability, key.to_string(), value)?;
565
+ Ok(())
566
+ }
567
+
568
+ /// Delete a record with authorization context
569
+ pub fn delete_with_authorization(
570
+ &self,
571
+ key: &str,
572
+ context: &AuthorizationContext,
573
+ ) -> Result<()> {
574
+ // Authorize mutation inside FeltDB boundary
575
+ self.evaluate_authorization(context)?;
576
+
577
+ let capability = key
578
+ .split_once(':')
579
+ .map(|(cap, _)| cap)
580
+ .unwrap_or("default")
581
+ .to_string();
582
+
583
+ // Check if capability is writable
584
+ if !context.writable_collections.is_empty()
585
+ && !context.writable_collections.contains(&capability)
586
+ {
587
+ return Err(FlowError::CapabilityError(
588
+ format!("AUTHORIZATION_DENIED:not_writable_collection:{}", capability),
589
+ ));
590
+ }
591
+
592
+ // Authorized: apply mutation
593
+ // Pre-state evaluation would happen here in full implementation
594
+ self.delete_internal(capability, key.to_string())?;
595
+ Ok(())
596
+ }
597
+
488
598
  pub fn get<T: DeserializeOwned>(&self, key: &str) -> Result<Option<T>> {
489
599
  let capability = key
490
600
  .split_once(':')
@@ -785,6 +895,35 @@ impl FeltDb {
785
895
  Ok(commit)
786
896
  }
787
897
 
898
+ /// Apply atomic transaction with authorization context (atomic rejection on deny)
899
+ pub fn apply_atomic_transaction_with_authorization(
900
+ &self,
901
+ transaction_id: &str,
902
+ expected_parent: Option<u64>,
903
+ preconditions: &[AtomicPrecondition],
904
+ mutations: &[AtomicMutation],
905
+ audit: Option<Value>,
906
+ context: &AuthorizationContext,
907
+ ) -> Result<AtomicCommit> {
908
+ // Authorize ALL mutations before applying ANY of them (atomicity guarantee)
909
+ self.evaluate_authorization(context)?;
910
+
911
+ // Check writable collections for all mutations
912
+ for mutation in mutations {
913
+ if !context.writable_collections.is_empty()
914
+ && !context.writable_collections.contains(&mutation.capability)
915
+ {
916
+ return Err(FlowError::CapabilityError(format!(
917
+ "AUTHORIZATION_DENIED:not_writable_collection:{}",
918
+ mutation.capability
919
+ )));
920
+ }
921
+ }
922
+
923
+ // All authorized: proceed with atomic transaction (no partial application)
924
+ self.apply_atomic_transaction(transaction_id, expected_parent, preconditions, mutations, audit)
925
+ }
926
+
788
927
  fn insert_internal<T: Serialize>(
789
928
  &self,
790
929
  capability: String,