@feltdb/core 0.8.3 → 0.8.5
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.
- package/dist/cli/commands.js +4 -1
- package/dist/cli/provisioning-neutrality.js +79 -0
- package/dist/collection.d.ts +43 -1
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +192 -22
- package/dist/create/create.js +25 -21
- package/dist/create/managed-account.js +11 -0
- package/dist/create/package-versions.js +1 -1
- package/dist/create/server-source/Cargo.lock +165 -0
- package/dist/create/server-source/Cargo.toml +9 -0
- package/dist/create/server-source/crates/feltdb/Cargo.toml +3 -0
- package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +44 -44
- package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +12 -24
- package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +7 -13
- package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +13 -10
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +12 -9
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +78 -25
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +16 -13
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +13 -5
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +41 -22
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +33 -15
- package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +100 -33
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +56 -20
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +116 -41
- package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +186 -55
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +64 -26
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +46 -15
- package/dist/create/server-source/crates/feltdb/src/admission.rs +8 -15
- package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +43 -13
- package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +15 -42
- package/dist/create/server-source/crates/feltdb/src/analytics.rs +65 -19
- package/dist/create/server-source/crates/feltdb/src/application.rs +113 -30
- package/dist/create/server-source/crates/feltdb/src/authorization_security_tests.rs +475 -140
- package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +17 -15
- package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +0 -1
- package/dist/create/server-source/crates/feltdb/src/causal_backlog_bound.rs +59 -15
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +266 -114
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +25 -7
- package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +10 -15
- package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +3 -11
- package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +14 -5
- package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +21 -25
- package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +14 -11
- package/dist/create/server-source/crates/feltdb/src/dedup_bound_investigation.rs +103 -22
- package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +18 -15
- package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +12 -8
- package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +1 -5
- package/dist/create/server-source/crates/feltdb/src/durable_operation_identity.rs +87 -23
- package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +3 -7
- package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +10 -9
- package/dist/create/server-source/crates/feltdb/src/equality_index.rs +595 -0
- package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +1 -6
- package/dist/create/server-source/crates/feltdb/src/indexing.rs +35 -38
- package/dist/create/server-source/crates/feltdb/src/lib.rs +1050 -117
- package/dist/create/server-source/crates/feltdb/src/managed_cas_tests.rs +4 -1
- package/dist/create/server-source/crates/feltdb/src/metrics.rs +0 -1
- package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +1 -2
- package/dist/create/server-source/crates/feltdb/src/multi_operation_transaction.rs +107 -30
- package/dist/create/server-source/crates/feltdb/src/observability.rs +19 -6
- package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +12 -11
- package/dist/create/server-source/crates/feltdb/src/operation_log.rs +9 -4
- package/dist/create/server-source/crates/feltdb/src/p1_application_atomicity.rs +65 -18
- package/dist/create/server-source/crates/feltdb/src/p1_atomicity_acceptance.rs +193 -57
- package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +37 -27
- package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +38 -10
- package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +20 -14
- package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +394 -229
- package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +8 -6
- package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +11 -13
- package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +90 -72
- package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +3 -3
- package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +33 -11
- package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +6 -6
- package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +14 -56
- package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +29 -27
- package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +35 -17
- package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +8 -2
- package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +59 -15
- package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +70 -17
- package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +23 -6
- package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +12 -3
- package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +41 -11
- package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +56 -25
- package/dist/create/server-source/crates/feltdb/src/policy_evaluation.rs +701 -245
- package/dist/create/server-source/crates/feltdb/src/production_api.rs +31 -13
- package/dist/create/server-source/crates/feltdb/src/query_execution_diagnostics.rs +126 -0
- package/dist/create/server-source/crates/feltdb/src/query_performance.rs +6 -8
- package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +5 -5
- package/dist/create/server-source/crates/feltdb/src/replica_acknowledgements.rs +48 -18
- package/dist/create/server-source/crates/feltdb/src/replica_membership.rs +30 -11
- package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +6 -3
- package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +4 -3
- package/dist/create/server-source/crates/feltdb/src/sharding.rs +36 -10
- package/dist/create/server-source/crates/feltdb/src/state_conflict_contract.rs +516 -0
- package/dist/create/server-source/crates/feltdb/src/state_contract.rs +305 -6
- package/dist/create/server-source/crates/feltdb/src/state_diff_contract.rs +222 -0
- package/dist/create/server-source/crates/feltdb/src/state_facade.rs +82 -54
- package/dist/create/server-source/crates/feltdb/src/state_hash.rs +2 -2
- package/dist/create/server-source/crates/feltdb/src/state_model.rs +1514 -537
- package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +6 -3
- package/dist/create/server-source/crates/feltdb/src/state_trigger.rs +672 -0
- package/dist/create/server-source/crates/feltdb/src/submission.rs +5 -11
- package/dist/create/server-source/crates/feltdb/src/sync.rs +12 -0
- package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +6 -8
- package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +24 -35
- package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +24 -8
- package/dist/create/server-source/crates/feltdb/src/transaction_preconditions.rs +248 -59
- package/dist/create/server-source/crates/feltdb/src/transactions.rs +17 -20
- package/dist/create/server-source/crates/feltdb/src/trigger_contract.rs +749 -0
- package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +1 -0
- package/dist/create/server-source/crates/feltdb/src/workload.rs +512 -4
- package/dist/create/server-source/crates/feltdb/src/workload_diagnostics.rs +442 -0
- package/dist/create/server-source/crates/feltdb/tests/branching_evidence.rs +299 -0
- package/dist/create/server-source/crates/feltdb/tests/current_revision_authority_evidence.rs +288 -0
- package/dist/create/server-source/crates/feltdb/tests/durable_format_compatibility.rs +392 -0
- package/dist/create/server-source/crates/feltdb/tests/feltdb_state_boundary_tests.rs +436 -220
- package/dist/create/server-source/crates/feltdb/tests/fixtures/state_conflict_contract_corpus.json +1916 -0
- package/dist/create/server-source/crates/feltdb/tests/fixtures/state_diff_contract_corpus.json +1878 -0
- package/dist/create/server-source/crates/feltdb/tests/fixtures/trigger_contract_corpus.json +1862 -0
- package/dist/create/server-source/crates/feltdb/tests/pr34_query_collection.rs +234 -0
- package/dist/create/server-source/crates/feltdb/tests/pr35_equality_index.rs +947 -0
- package/dist/create/server-source/crates/feltdb/tests/pr7_self_authorization_proof.rs +5 -8
- package/dist/create/server-source/crates/feltdb/tests/pr8_vocabulary_assessment.rs +52 -44
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase2_boundary_tests.rs +33 -16
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3a_path_a_tests.rs +22 -7
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_authorized_mutations.rs +41 -22
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_role_based_authorization.rs +25 -8
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_simple_auth_delete.rs +9 -6
- package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_team_delete_role_authorization.rs +120 -69
- package/dist/create/server-source/crates/feltdb/tests/pr9_teams_role_based_access.rs +21 -10
- package/dist/create/server-source/crates/feltdb/tests/production_readiness_contract.rs +1032 -0
- package/dist/create/server-source/crates/feltdb/tests/reconciliation_application.rs +868 -0
- package/dist/create/server-source/crates/feltdb/tests/reconciliation_wire_format_evidence.rs +221 -0
- package/dist/create/server-source/crates/feltdb/tests/resource_scoped_revisions.rs +338 -0
- package/dist/create/server-source/crates/feltdb/tests/revision_identity_contract.rs +1039 -0
- package/dist/create/server-source/crates/feltdb/tests/revision_model_decision.rs +739 -0
- package/dist/create/server-source/crates/feltdb/tests/revision_retention_boundary_evidence.rs +427 -0
- package/dist/create/server-source/crates/feltdb/tests/saas_authorization_integration.rs +3 -3
- package/dist/create/server-source/crates/feltdb/tests/saas_invitation_lifecycle.rs +25 -22
- package/dist/create/server-source/crates/feltdb/tests/state_conflict_contract_conformance.rs +1799 -0
- package/dist/create/server-source/crates/feltdb/tests/state_diff_contract_conformance.rs +1316 -0
- package/dist/create/server-source/crates/feltdb/tests/state_model_integration.rs +53 -61
- package/dist/create/server-source/crates/feltdb/tests/state_persistence_integration.rs +156 -61
- package/dist/create/server-source/crates/feltdb/tests/state_store_boundary_evidence.rs +299 -0
- package/dist/create/server-source/crates/feltdb/tests/sync_divergence_evidence.rs +255 -0
- package/dist/create/server-source/crates/feltdb/tests/three_way_input_boundary_evidence.rs +249 -0
- package/dist/create/server-source/crates/feltdb/tests/trigger_contract_conformance.rs +994 -0
- package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +2 -1
- package/dist/create/server-source/crates/feltdb-server/src/audit.rs +1137 -29
- package/dist/create/server-source/crates/feltdb-server/src/auth.rs +164 -13
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +800 -34
- package/dist/db.d.ts +33 -34
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +74 -20
- package/dist/deployment.d.ts +30 -0
- package/dist/deployment.d.ts.map +1 -0
- package/dist/deployment.js +130 -0
- package/dist/embedded-transaction.d.ts +22 -4
- package/dist/embedded-transaction.d.ts.map +1 -1
- package/dist/embedded-transaction.js +51 -5
- package/dist/feltdb.d.ts +14 -2
- package/dist/feltdb.d.ts.map +1 -1
- package/dist/file-db.js +1 -1
- package/dist/http-client.d.ts +14 -0
- package/dist/http-client.d.ts.map +1 -1
- package/dist/http-client.js +23 -5
- package/dist/http-db.d.ts +119 -1
- package/dist/http-db.d.ts.map +1 -1
- package/dist/http-db.js +346 -31
- package/dist/index-core.d.ts +2 -0
- package/dist/index-core.d.ts.map +1 -1
- package/dist/index-core.js +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/indexeddb-db.d.ts.map +1 -1
- package/dist/indexeddb-db.js +35 -21
- package/dist/managed-recovery.d.ts +192 -0
- package/dist/managed-recovery.d.ts.map +1 -0
- package/dist/managed-recovery.js +242 -0
- package/dist/memory-db.js +1 -1
- package/dist/studio-app/assets/{feltdb_wasm-DB8cX151.js → feltdb_wasm-DaNwCLRX.js} +1 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-DnsHNv6g.wasm +0 -0
- package/dist/studio-app/assets/index-j8IlhNqJ.js +29 -0
- package/dist/studio-app/index.html +1 -1
- package/dist/transaction.d.ts +30 -0
- package/dist/transaction.d.ts.map +1 -1
- package/dist/transaction.js +41 -0
- package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
- package/dist/workload.d.ts +2 -1
- package/dist/workload.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-ClhDHp0S.wasm +0 -0
- package/dist/studio-app/assets/index-B0k4UAlI.js +0 -29
|
@@ -17,10 +17,8 @@
|
|
|
17
17
|
|
|
18
18
|
use feltdb::{
|
|
19
19
|
state_contract::{
|
|
20
|
-
|
|
21
|
-
FieldConstraints,
|
|
22
|
-
AuthorizationContext, CanonicalQuery, begin_read, execute_query,
|
|
23
|
-
QueryFilter,
|
|
20
|
+
begin_read, execute_query, AuthorizationContext, CanonicalQuery, CollectionSchema,
|
|
21
|
+
FieldConstraints, FieldSchema, FieldType, PrimitiveType, QueryFilter, StateSchema,
|
|
24
22
|
},
|
|
25
23
|
FeltDb,
|
|
26
24
|
};
|
|
@@ -324,8 +322,7 @@ fn pr7_phase3_self_authorization_proof() -> Result<(), Box<dyn std::error::Error
|
|
|
324
322
|
field_projections: Default::default(),
|
|
325
323
|
};
|
|
326
324
|
|
|
327
|
-
let _bob_context = begin_read(&db, &schema, "app", bob_auth)
|
|
328
|
-
.map_err(|e| format!("{:?}", e))?;
|
|
325
|
+
let _bob_context = begin_read(&db, &schema, "app", bob_auth).map_err(|e| format!("{:?}", e))?;
|
|
329
326
|
|
|
330
327
|
// Query as Bob with self(user) policy
|
|
331
328
|
let _query = CanonicalQuery {
|
|
@@ -360,8 +357,8 @@ fn pr7_phase3_self_authorization_proof() -> Result<(), Box<dyn std::error::Error
|
|
|
360
357
|
field_projections: Default::default(),
|
|
361
358
|
};
|
|
362
359
|
|
|
363
|
-
let _alice_context =
|
|
364
|
-
.map_err(|e| format!("{:?}", e))?;
|
|
360
|
+
let _alice_context =
|
|
361
|
+
begin_read(&db, &schema, "app", alice_auth).map_err(|e| format!("{:?}", e))?;
|
|
365
362
|
|
|
366
363
|
println!(" • Alice is member of Org A");
|
|
367
364
|
println!(" • Invitation.organization = {}", org_a_id);
|
|
@@ -17,8 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
use feltdb::{
|
|
19
19
|
state_contract::{
|
|
20
|
-
|
|
21
|
-
FieldConstraints,
|
|
20
|
+
CollectionSchema, FieldConstraints, FieldSchema, FieldType, PrimitiveType, StateSchema,
|
|
22
21
|
},
|
|
23
22
|
FeltDb,
|
|
24
23
|
};
|
|
@@ -150,10 +149,7 @@ fn pr8_resource_inventory_and_pattern_mapping() -> Result<(), Box<dyn std::error
|
|
|
150
149
|
for primitive in primitives {
|
|
151
150
|
let count = resources
|
|
152
151
|
.iter()
|
|
153
|
-
.filter(|r|
|
|
154
|
-
r.read_policy.contains(primitive)
|
|
155
|
-
|| r.write_policy.contains(primitive)
|
|
156
|
-
})
|
|
152
|
+
.filter(|r| r.read_policy.contains(primitive) || r.write_policy.contains(primitive))
|
|
157
153
|
.count();
|
|
158
154
|
if count > 0 {
|
|
159
155
|
println!(" ✓ {} - Used in {} resources", primitive, count);
|
|
@@ -184,37 +180,35 @@ fn pr8_pattern_class_1_personal_identity_scoped() -> Result<(), Box<dyn std::err
|
|
|
184
180
|
schema_version: 1,
|
|
185
181
|
application_id: "saas-portal".to_string(),
|
|
186
182
|
revision_id: "rev-1".to_string(),
|
|
187
|
-
collections: vec![
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
primitive: PrimitiveType::String,
|
|
196
|
-
},
|
|
197
|
-
nullable: false,
|
|
198
|
-
required: true,
|
|
199
|
-
default: None,
|
|
200
|
-
constraints: FieldConstraints::default(),
|
|
201
|
-
computed: None,
|
|
183
|
+
collections: vec![CollectionSchema {
|
|
184
|
+
name: "User".to_string(),
|
|
185
|
+
version: 1,
|
|
186
|
+
fields: vec![
|
|
187
|
+
FieldSchema {
|
|
188
|
+
name: "_id".to_string(),
|
|
189
|
+
field_type: FieldType::Primitive {
|
|
190
|
+
primitive: PrimitiveType::String,
|
|
202
191
|
},
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
192
|
+
nullable: false,
|
|
193
|
+
required: true,
|
|
194
|
+
default: None,
|
|
195
|
+
constraints: FieldConstraints::default(),
|
|
196
|
+
computed: None,
|
|
197
|
+
},
|
|
198
|
+
FieldSchema {
|
|
199
|
+
name: "email".to_string(),
|
|
200
|
+
field_type: FieldType::Primitive {
|
|
201
|
+
primitive: PrimitiveType::String,
|
|
213
202
|
},
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
203
|
+
nullable: false,
|
|
204
|
+
required: true,
|
|
205
|
+
default: None,
|
|
206
|
+
constraints: FieldConstraints::default(),
|
|
207
|
+
computed: None,
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
indexes: vec![],
|
|
211
|
+
}],
|
|
218
212
|
};
|
|
219
213
|
|
|
220
214
|
// Setup test data
|
|
@@ -415,11 +409,17 @@ fn pr8_pattern_class_2_organizational_relational() -> Result<(), Box<dyn std::er
|
|
|
415
409
|
let org_a_id = "org-a";
|
|
416
410
|
let proj_id = "proj-1";
|
|
417
411
|
|
|
418
|
-
db.insert(
|
|
419
|
-
|
|
412
|
+
db.insert(
|
|
413
|
+
"User#user-alice",
|
|
414
|
+
json!({ "_id": alice_id, "email": "alice@example.com" }),
|
|
415
|
+
)
|
|
416
|
+
.map_err(|e| format!("{:?}", e))?;
|
|
420
417
|
|
|
421
|
-
db.insert(
|
|
422
|
-
|
|
418
|
+
db.insert(
|
|
419
|
+
"User#user-bob",
|
|
420
|
+
json!({ "_id": bob_id, "email": "bob@example.com" }),
|
|
421
|
+
)
|
|
422
|
+
.map_err(|e| format!("{:?}", e))?;
|
|
423
423
|
|
|
424
424
|
db.insert(
|
|
425
425
|
"Organization#org-a",
|
|
@@ -672,11 +672,17 @@ fn pr8_pattern_class_4_composition_multiple_audiences() -> Result<(), Box<dyn st
|
|
|
672
672
|
let org_a_id = "org-a";
|
|
673
673
|
let inv_id = "inv-1";
|
|
674
674
|
|
|
675
|
-
db.insert(
|
|
676
|
-
|
|
675
|
+
db.insert(
|
|
676
|
+
"User#user-alice",
|
|
677
|
+
json!({ "_id": alice_id, "email": "alice@example.com" }),
|
|
678
|
+
)
|
|
679
|
+
.map_err(|e| format!("{:?}", e))?;
|
|
677
680
|
|
|
678
|
-
db.insert(
|
|
679
|
-
|
|
681
|
+
db.insert(
|
|
682
|
+
"User#user-bob",
|
|
683
|
+
json!({ "_id": bob_id, "email": "bob@example.com" }),
|
|
684
|
+
)
|
|
685
|
+
.map_err(|e| format!("{:?}", e))?;
|
|
680
686
|
|
|
681
687
|
db.insert(
|
|
682
688
|
"Organization#org-a",
|
|
@@ -853,7 +859,9 @@ fn pr8_final_conclusion() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
853
859
|
|
|
854
860
|
println!("RESULTS\n");
|
|
855
861
|
println!(" Gaps: NONE");
|
|
856
|
-
println!(
|
|
862
|
+
println!(
|
|
863
|
+
" Redundancies: owner (minor - can be expressed as self, but kept for convenience)\n"
|
|
864
|
+
);
|
|
857
865
|
|
|
858
866
|
println!("VERDICT: VOCABULARY IS COMPLETE ✓\n");
|
|
859
867
|
|
|
@@ -22,15 +22,14 @@
|
|
|
22
22
|
|
|
23
23
|
use feltdb::{
|
|
24
24
|
state_contract::{
|
|
25
|
-
|
|
26
|
-
FieldConstraints,
|
|
27
|
-
CanonicalQuery, QueryFilter,
|
|
25
|
+
begin_read, execute_query, AuthorizationContext, CanonicalQuery, CollectionSchema,
|
|
26
|
+
FieldConstraints, FieldSchema, FieldType, PrimitiveType, QueryFilter, StateSchema,
|
|
28
27
|
},
|
|
29
28
|
FeltDb,
|
|
30
29
|
};
|
|
31
30
|
use serde_json::{json, Value};
|
|
32
|
-
use tempfile::TempDir;
|
|
33
31
|
use std::fmt;
|
|
32
|
+
use tempfile::TempDir;
|
|
34
33
|
|
|
35
34
|
/// Result of testing an operation at the FeltDB boundary
|
|
36
35
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
@@ -322,19 +321,31 @@ impl TeamBoundaryTestFixture {
|
|
|
322
321
|
let team_id = "team-backend".to_string();
|
|
323
322
|
|
|
324
323
|
// Create users
|
|
325
|
-
db.insert(
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
324
|
+
db.insert(
|
|
325
|
+
"User#user-owner",
|
|
326
|
+
json!({ "_id": owner_id, "email": "owner@example.com" }),
|
|
327
|
+
)
|
|
328
|
+
.map_err(|e| format!("{:?}", e))?;
|
|
329
|
+
db.insert(
|
|
330
|
+
"User#user-admin",
|
|
331
|
+
json!({ "_id": admin_id, "email": "admin@example.com" }),
|
|
332
|
+
)
|
|
333
|
+
.map_err(|e| format!("{:?}", e))?;
|
|
334
|
+
db.insert(
|
|
335
|
+
"User#user-member",
|
|
336
|
+
json!({ "_id": member_id, "email": "member@example.com" }),
|
|
337
|
+
)
|
|
338
|
+
.map_err(|e| format!("{:?}", e))?;
|
|
331
339
|
db.insert(
|
|
332
340
|
"User#user-non-member",
|
|
333
341
|
json!({ "_id": non_member_id, "email": "nonmember@example.com" }),
|
|
334
342
|
)
|
|
335
343
|
.map_err(|e| format!("{:?}", e))?;
|
|
336
|
-
db.insert(
|
|
337
|
-
|
|
344
|
+
db.insert(
|
|
345
|
+
"User#user-revoked",
|
|
346
|
+
json!({ "_id": revoked_id, "email": "revoked@example.com" }),
|
|
347
|
+
)
|
|
348
|
+
.map_err(|e| format!("{:?}", e))?;
|
|
338
349
|
db.insert(
|
|
339
350
|
"User#user-cross-tenant",
|
|
340
351
|
json!({ "_id": cross_tenant_id, "email": "cross@example.com" }),
|
|
@@ -342,10 +353,16 @@ impl TeamBoundaryTestFixture {
|
|
|
342
353
|
.map_err(|e| format!("{:?}", e))?;
|
|
343
354
|
|
|
344
355
|
// Create organizations
|
|
345
|
-
db.insert(
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
356
|
+
db.insert(
|
|
357
|
+
"Organization#org-main",
|
|
358
|
+
json!({ "_id": org_id, "name": "Main Org" }),
|
|
359
|
+
)
|
|
360
|
+
.map_err(|e| format!("{:?}", e))?;
|
|
361
|
+
db.insert(
|
|
362
|
+
"Organization#org-other",
|
|
363
|
+
json!({ "_id": cross_org_id, "name": "Other Org" }),
|
|
364
|
+
)
|
|
365
|
+
.map_err(|e| format!("{:?}", e))?;
|
|
349
366
|
|
|
350
367
|
// Create org memberships (establishes organization access)
|
|
351
368
|
db.insert(
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
|
|
19
19
|
use feltdb::{
|
|
20
20
|
state_contract::{
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
AuthorizationContext, CollectionSchema, FieldConstraints, FieldSchema, FieldType,
|
|
22
|
+
PrimitiveType, StateSchema,
|
|
23
23
|
},
|
|
24
24
|
FeltDb,
|
|
25
25
|
};
|
|
@@ -66,13 +66,28 @@ impl PathATestFixture {
|
|
|
66
66
|
let team_id = "team-backend".to_string();
|
|
67
67
|
|
|
68
68
|
// Create users
|
|
69
|
-
db.insert(
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
db.insert(
|
|
70
|
+
"User#user-owner",
|
|
71
|
+
json!({"_id": owner_id, "email": "owner@example.com"}),
|
|
72
|
+
)?;
|
|
73
|
+
db.insert(
|
|
74
|
+
"User#user-admin",
|
|
75
|
+
json!({"_id": admin_id, "email": "admin@example.com"}),
|
|
76
|
+
)?;
|
|
77
|
+
db.insert(
|
|
78
|
+
"User#user-member",
|
|
79
|
+
json!({"_id": member_id, "email": "member@example.com"}),
|
|
80
|
+
)?;
|
|
81
|
+
db.insert(
|
|
82
|
+
"User#user-non-member",
|
|
83
|
+
json!({"_id": non_member_id, "email": "non-member@example.com"}),
|
|
84
|
+
)?;
|
|
73
85
|
|
|
74
86
|
// Create organization
|
|
75
|
-
db.insert(
|
|
87
|
+
db.insert(
|
|
88
|
+
"Organization#org-1",
|
|
89
|
+
json!({"_id": org_id, "name": "Org 1"}),
|
|
90
|
+
)?;
|
|
76
91
|
|
|
77
92
|
// Create memberships for all users in the organization
|
|
78
93
|
db.insert(
|
|
@@ -3,10 +3,7 @@
|
|
|
3
3
|
//! Test that the new authorized mutation API properly enforces authorization.
|
|
4
4
|
//! Authorization evaluation happens INSIDE the FeltDB boundary, before mutations are applied.
|
|
5
5
|
|
|
6
|
-
use feltdb::{
|
|
7
|
-
state_contract::AuthorizationContext,
|
|
8
|
-
FeltDb,
|
|
9
|
-
};
|
|
6
|
+
use feltdb::{state_contract::AuthorizationContext, FeltDb};
|
|
10
7
|
use serde_json::json;
|
|
11
8
|
use tempfile::TempDir;
|
|
12
9
|
|
|
@@ -43,7 +40,11 @@ fn authorized_insert_requires_state_write_capability() -> Result<(), Box<dyn std
|
|
|
43
40
|
json!({"_id": "user-1", "name": "Alice"}),
|
|
44
41
|
&authorized_context,
|
|
45
42
|
);
|
|
46
|
-
assert!(
|
|
43
|
+
assert!(
|
|
44
|
+
result.is_ok(),
|
|
45
|
+
"Authorized insert should succeed: {:?}",
|
|
46
|
+
result
|
|
47
|
+
);
|
|
47
48
|
|
|
48
49
|
// Verify record was inserted
|
|
49
50
|
let value = db.get::<serde_json::Value>("User#user-1")?;
|
|
@@ -63,7 +64,10 @@ fn authorized_insert_requires_state_write_capability() -> Result<(), Box<dyn std
|
|
|
63
64
|
|
|
64
65
|
// Verify unauthorized insert did not create record
|
|
65
66
|
let value = db.get::<serde_json::Value>("User#user-2")?;
|
|
66
|
-
assert!(
|
|
67
|
+
assert!(
|
|
68
|
+
value.is_none(),
|
|
69
|
+
"Unauthorized insert should not create record"
|
|
70
|
+
);
|
|
67
71
|
|
|
68
72
|
Ok(())
|
|
69
73
|
}
|
|
@@ -123,11 +127,18 @@ fn authorized_delete_requires_state_write_capability() -> Result<(), Box<dyn std
|
|
|
123
127
|
|
|
124
128
|
// Authorized delete should succeed
|
|
125
129
|
let result = db.delete_with_authorization("Team#team-1", &authorized_context);
|
|
126
|
-
assert!(
|
|
130
|
+
assert!(
|
|
131
|
+
result.is_ok(),
|
|
132
|
+
"Authorized delete should succeed: {:?}",
|
|
133
|
+
result
|
|
134
|
+
);
|
|
127
135
|
|
|
128
136
|
// Verify record is deleted
|
|
129
137
|
let value = db.get::<serde_json::Value>("Team#team-1")?;
|
|
130
|
-
assert!(
|
|
138
|
+
assert!(
|
|
139
|
+
value.is_none(),
|
|
140
|
+
"Record should be deleted after authorized delete"
|
|
141
|
+
);
|
|
131
142
|
|
|
132
143
|
Ok(())
|
|
133
144
|
}
|
|
@@ -167,7 +178,13 @@ fn authorized_update_requires_state_write_capability() -> Result<(), Box<dyn std
|
|
|
167
178
|
)?;
|
|
168
179
|
|
|
169
180
|
let original = db.get::<serde_json::Value>("Organization#org-1")?;
|
|
170
|
-
assert_eq!(
|
|
181
|
+
assert_eq!(
|
|
182
|
+
original
|
|
183
|
+
.as_ref()
|
|
184
|
+
.and_then(|v| v.get("name"))
|
|
185
|
+
.and_then(|v| v.as_str()),
|
|
186
|
+
Some("Acme Corp")
|
|
187
|
+
);
|
|
171
188
|
|
|
172
189
|
// Unauthorized update should fail
|
|
173
190
|
let result = db.update_with_authorization(
|
|
@@ -184,7 +201,10 @@ fn authorized_update_requires_state_write_capability() -> Result<(), Box<dyn std
|
|
|
184
201
|
// Verify record was not changed
|
|
185
202
|
let value = db.get::<serde_json::Value>("Organization#org-1")?;
|
|
186
203
|
assert_eq!(
|
|
187
|
-
value
|
|
204
|
+
value
|
|
205
|
+
.as_ref()
|
|
206
|
+
.and_then(|v| v.get("name"))
|
|
207
|
+
.and_then(|v| v.as_str()),
|
|
188
208
|
Some("Acme Corp"),
|
|
189
209
|
"Unauthorized update should not change record"
|
|
190
210
|
);
|
|
@@ -195,12 +215,19 @@ fn authorized_update_requires_state_write_capability() -> Result<(), Box<dyn std
|
|
|
195
215
|
json!({"_id": "org-1", "name": "Acme Inc"}),
|
|
196
216
|
&authorized_context,
|
|
197
217
|
);
|
|
198
|
-
assert!(
|
|
218
|
+
assert!(
|
|
219
|
+
result.is_ok(),
|
|
220
|
+
"Authorized update should succeed: {:?}",
|
|
221
|
+
result
|
|
222
|
+
);
|
|
199
223
|
|
|
200
224
|
// Verify record was updated
|
|
201
225
|
let value = db.get::<serde_json::Value>("Organization#org-1")?;
|
|
202
226
|
assert_eq!(
|
|
203
|
-
value
|
|
227
|
+
value
|
|
228
|
+
.as_ref()
|
|
229
|
+
.and_then(|v| v.get("name"))
|
|
230
|
+
.and_then(|v| v.as_str()),
|
|
204
231
|
Some("Acme Inc"),
|
|
205
232
|
"Authorized update should change record"
|
|
206
233
|
);
|
|
@@ -276,16 +303,8 @@ fn atomic_transaction_with_authorization_denies_on_any_mutation_failure(
|
|
|
276
303
|
};
|
|
277
304
|
|
|
278
305
|
// Create initial records
|
|
279
|
-
db.insert_with_authorization(
|
|
280
|
-
|
|
281
|
-
json!({"_id": "user-1"}),
|
|
282
|
-
&authorized_context,
|
|
283
|
-
)?;
|
|
284
|
-
db.insert_with_authorization(
|
|
285
|
-
"Team#team-1",
|
|
286
|
-
json!({"_id": "team-1"}),
|
|
287
|
-
&authorized_context,
|
|
288
|
-
)?;
|
|
306
|
+
db.insert_with_authorization("User#user-1", json!({"_id": "user-1"}), &authorized_context)?;
|
|
307
|
+
db.insert_with_authorization("Team#team-1", json!({"_id": "team-1"}), &authorized_context)?;
|
|
289
308
|
|
|
290
309
|
// Attempt atomic transaction with unauthorized context
|
|
291
310
|
// Should be rejected without applying ANY mutations
|
package/dist/create/server-source/crates/feltdb/tests/pr9_phase3c_role_based_authorization.rs
CHANGED
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
|
|
25
25
|
use feltdb::{
|
|
26
26
|
state_contract::{
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
AuthorizationContext, CollectionSchema, FieldConstraints, FieldSchema, FieldType,
|
|
28
|
+
PrimitiveType, StateSchema,
|
|
29
29
|
},
|
|
30
30
|
FeltDb,
|
|
31
31
|
};
|
|
@@ -72,13 +72,28 @@ impl RoleAuthTestFixture {
|
|
|
72
72
|
let team_id = "team-backend".to_string();
|
|
73
73
|
|
|
74
74
|
// Create users
|
|
75
|
-
db.insert(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
db.insert(
|
|
76
|
+
"User#user-owner",
|
|
77
|
+
json!({"_id": owner_id, "email": "owner@example.com"}),
|
|
78
|
+
)?;
|
|
79
|
+
db.insert(
|
|
80
|
+
"User#user-admin",
|
|
81
|
+
json!({"_id": admin_id, "email": "admin@example.com"}),
|
|
82
|
+
)?;
|
|
83
|
+
db.insert(
|
|
84
|
+
"User#user-member",
|
|
85
|
+
json!({"_id": member_id, "email": "member@example.com"}),
|
|
86
|
+
)?;
|
|
87
|
+
db.insert(
|
|
88
|
+
"User#user-non-member",
|
|
89
|
+
json!({"_id": non_member_id, "email": "non-member@example.com"}),
|
|
90
|
+
)?;
|
|
79
91
|
|
|
80
92
|
// Create organization
|
|
81
|
-
db.insert(
|
|
93
|
+
db.insert(
|
|
94
|
+
"Organization#org-1",
|
|
95
|
+
json!({"_id": org_id, "name": "Org 1"}),
|
|
96
|
+
)?;
|
|
82
97
|
|
|
83
98
|
// Create organization memberships (all users are org members except non_member)
|
|
84
99
|
db.insert(
|
|
@@ -280,7 +295,9 @@ fn pr9_phase3c_evidence_template() {
|
|
|
280
295
|
println!("For each actor, record:\n");
|
|
281
296
|
|
|
282
297
|
println!("Actor\t\tRole\t\tTeam.owner?\tOrg Member?\tExpected\tActual\tPolicy Evaluated\tPath");
|
|
283
|
-
println!(
|
|
298
|
+
println!(
|
|
299
|
+
"─────────────────────────────────────────────────────────────────────────────────────────"
|
|
300
|
+
);
|
|
284
301
|
println!("owner\t\towner\t\tYES\t\tYES\t\tPERMIT\t\t?\t\t?\t\t\t?\n");
|
|
285
302
|
|
|
286
303
|
println!("Analysis for each result:\n");
|
|
@@ -2,10 +2,7 @@
|
|
|
2
2
|
//!
|
|
3
3
|
//! Minimal test to verify authorized deletion works
|
|
4
4
|
|
|
5
|
-
use feltdb::{
|
|
6
|
-
state_contract::AuthorizationContext,
|
|
7
|
-
FeltDb,
|
|
8
|
-
};
|
|
5
|
+
use feltdb::{state_contract::AuthorizationContext, FeltDb};
|
|
9
6
|
use serde_json::json;
|
|
10
7
|
use tempfile::TempDir;
|
|
11
8
|
|
|
@@ -15,7 +12,10 @@ fn simple_authorized_delete() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
15
12
|
let db = FeltDb::open(temp_dir.path().join("test.db"))?;
|
|
16
13
|
|
|
17
14
|
// Create a simple record
|
|
18
|
-
db.insert(
|
|
15
|
+
db.insert(
|
|
16
|
+
"Team#team-1",
|
|
17
|
+
json!({"_id": "team-1", "name": "Engineering"}),
|
|
18
|
+
)?;
|
|
19
19
|
println!("Created Team#team-1");
|
|
20
20
|
|
|
21
21
|
// Verify it exists
|
|
@@ -83,7 +83,10 @@ fn authorized_delete_unauthorized_context() -> Result<(), Box<dyn std::error::Er
|
|
|
83
83
|
|
|
84
84
|
// Verify record still exists
|
|
85
85
|
let value = db.get::<serde_json::Value>("Team#team-2")?;
|
|
86
|
-
assert!(
|
|
86
|
+
assert!(
|
|
87
|
+
value.is_some(),
|
|
88
|
+
"Record should still exist after denied delete"
|
|
89
|
+
);
|
|
87
90
|
println!("✓ Record unchanged after authorization denial");
|
|
88
91
|
|
|
89
92
|
Ok(())
|