@feltdb/core 0.8.4 → 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/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/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 +507 -6
- 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 +79 -70
- 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_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 +13 -4
- 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/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 +3 -4
- 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 +2 -1
- package/dist/create/server-source/crates/feltdb/tests/pr35_equality_index.rs +80 -25
- 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/auth.rs +164 -13
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +326 -6
- package/dist/studio-app/assets/{feltdb_wasm-CVQWgXO-.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-DwgNAIIX.js → index-j8IlhNqJ.js} +1 -1
- package/dist/studio-app/index.html +1 -1
- 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-CNVpvaZV.wasm +0 -0
|
@@ -123,7 +123,9 @@ impl PolicySubject {
|
|
|
123
123
|
/// Returns None if the subject is not recognized.
|
|
124
124
|
pub fn from_str(s: &str) -> Option<Self> {
|
|
125
125
|
if let Some(field) = s.strip_prefix("self(").and_then(|s| s.strip_suffix(")")) {
|
|
126
|
-
return Some(PolicySubject::Self_ {
|
|
126
|
+
return Some(PolicySubject::Self_ {
|
|
127
|
+
field: field.to_string(),
|
|
128
|
+
});
|
|
127
129
|
}
|
|
128
130
|
match s {
|
|
129
131
|
"authenticated" => Some(PolicySubject::Authenticated),
|
|
@@ -222,9 +224,7 @@ impl AuthorizationState {
|
|
|
222
224
|
let capability = format!("{}:{}", self.state_namespace, collection);
|
|
223
225
|
self.snapshot_rows
|
|
224
226
|
.iter()
|
|
225
|
-
.find(|row|
|
|
226
|
-
row.capability == capability && row.key == key && !row.deleted
|
|
227
|
-
})
|
|
227
|
+
.find(|row| row.capability == capability && row.key == key && !row.deleted)
|
|
228
228
|
.map(|row| row.value.clone())
|
|
229
229
|
}
|
|
230
230
|
|
|
@@ -240,21 +240,28 @@ impl AuthorizationState {
|
|
|
240
240
|
|
|
241
241
|
/// Find a field in a collection that references another collection.
|
|
242
242
|
/// Returns the field name if found.
|
|
243
|
-
pub fn find_reference_field(
|
|
244
|
-
|
|
243
|
+
pub fn find_reference_field(
|
|
244
|
+
&self,
|
|
245
|
+
from_collection: &str,
|
|
246
|
+
to_collection: &str,
|
|
247
|
+
) -> Option<String> {
|
|
248
|
+
let collection = self
|
|
249
|
+
.schema
|
|
250
|
+
.collections
|
|
245
251
|
.iter()
|
|
246
252
|
.find(|c| c.name == from_collection)?;
|
|
247
253
|
|
|
248
|
-
collection.fields
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
254
|
+
collection.fields.iter().find_map(|field| {
|
|
255
|
+
if let crate::state_contract::FieldType::Reference {
|
|
256
|
+
collection: ref_col,
|
|
257
|
+
} = &field.field_type
|
|
258
|
+
{
|
|
259
|
+
if ref_col == to_collection {
|
|
260
|
+
return Some(field.name.clone());
|
|
255
261
|
}
|
|
256
|
-
|
|
257
|
-
|
|
262
|
+
}
|
|
263
|
+
None
|
|
264
|
+
})
|
|
258
265
|
}
|
|
259
266
|
|
|
260
267
|
/// Find which collection contains membership information (references both User and Organization).
|
|
@@ -263,7 +270,10 @@ impl AuthorizationState {
|
|
|
263
270
|
// Look for a collection that has references to both User and Organization
|
|
264
271
|
for collection in &self.schema.collections {
|
|
265
272
|
let has_user_ref = collection.fields.iter().any(|f| {
|
|
266
|
-
if let crate::state_contract::FieldType::Reference {
|
|
273
|
+
if let crate::state_contract::FieldType::Reference {
|
|
274
|
+
collection: ref_col,
|
|
275
|
+
} = &f.field_type
|
|
276
|
+
{
|
|
267
277
|
ref_col == "User" || ref_col == "Users"
|
|
268
278
|
} else {
|
|
269
279
|
false
|
|
@@ -271,7 +281,10 @@ impl AuthorizationState {
|
|
|
271
281
|
});
|
|
272
282
|
|
|
273
283
|
let has_org_ref = collection.fields.iter().any(|f| {
|
|
274
|
-
if let crate::state_contract::FieldType::Reference {
|
|
284
|
+
if let crate::state_contract::FieldType::Reference {
|
|
285
|
+
collection: ref_col,
|
|
286
|
+
} = &f.field_type
|
|
287
|
+
{
|
|
275
288
|
ref_col == "Organization" || ref_col == "Organizations"
|
|
276
289
|
} else {
|
|
277
290
|
false
|
|
@@ -288,7 +301,9 @@ impl AuthorizationState {
|
|
|
288
301
|
/// Find field names for user and organization references within a collection.
|
|
289
302
|
/// Returns (user_field, org_field) if both are found.
|
|
290
303
|
pub fn find_membership_fields(&self, collection_name: &str) -> Option<(String, String)> {
|
|
291
|
-
let collection = self
|
|
304
|
+
let collection = self
|
|
305
|
+
.schema
|
|
306
|
+
.collections
|
|
292
307
|
.iter()
|
|
293
308
|
.find(|c| c.name == collection_name)?;
|
|
294
309
|
|
|
@@ -296,11 +311,15 @@ impl AuthorizationState {
|
|
|
296
311
|
let mut org_field = None;
|
|
297
312
|
|
|
298
313
|
for field in &collection.fields {
|
|
299
|
-
if let crate::state_contract::FieldType::Reference {
|
|
314
|
+
if let crate::state_contract::FieldType::Reference {
|
|
315
|
+
collection: ref_col,
|
|
316
|
+
} = &field.field_type
|
|
317
|
+
{
|
|
300
318
|
if (ref_col == "User" || ref_col == "Users") && user_field.is_none() {
|
|
301
319
|
user_field = Some(field.name.clone());
|
|
302
320
|
}
|
|
303
|
-
if (ref_col == "Organization" || ref_col == "Organizations") && org_field.is_none()
|
|
321
|
+
if (ref_col == "Organization" || ref_col == "Organizations") && org_field.is_none()
|
|
322
|
+
{
|
|
304
323
|
org_field = Some(field.name.clone());
|
|
305
324
|
}
|
|
306
325
|
}
|
|
@@ -387,12 +406,10 @@ impl PolicyEvaluator {
|
|
|
387
406
|
PolicySubject::Authenticated => Self::evaluate_authenticated(context),
|
|
388
407
|
PolicySubject::Owner => Self::evaluate_owner(context),
|
|
389
408
|
PolicySubject::Member => Self::evaluate_member(context),
|
|
390
|
-
PolicySubject::Self_ { .. } =>
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
))
|
|
395
|
-
}
|
|
409
|
+
PolicySubject::Self_ { .. } => Err(PolicyAuthorizationError::new(
|
|
410
|
+
"INVALID_POLICY_CONTEXT",
|
|
411
|
+
"self policies require record-level context; use evaluate_record instead",
|
|
412
|
+
)),
|
|
396
413
|
}
|
|
397
414
|
}
|
|
398
415
|
|
|
@@ -448,12 +465,10 @@ impl PolicyEvaluator {
|
|
|
448
465
|
if actor.id == *owner_id {
|
|
449
466
|
Ok(AuthorizationDecision::Allow)
|
|
450
467
|
} else {
|
|
451
|
-
Err(PolicyAuthorizationError::unauthorized(
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
),
|
|
456
|
-
))
|
|
468
|
+
Err(PolicyAuthorizationError::unauthorized(format!(
|
|
469
|
+
"actor {} is not the owner ({})",
|
|
470
|
+
actor.id, owner_id
|
|
471
|
+
)))
|
|
457
472
|
}
|
|
458
473
|
}
|
|
459
474
|
|
|
@@ -474,19 +489,19 @@ impl PolicyEvaluator {
|
|
|
474
489
|
)
|
|
475
490
|
})?;
|
|
476
491
|
|
|
477
|
-
let is_member = context
|
|
492
|
+
let is_member = context
|
|
493
|
+
.resource_attributes
|
|
494
|
+
.get("is_member")
|
|
478
495
|
.map(|v| v == "true")
|
|
479
496
|
.unwrap_or(false);
|
|
480
497
|
|
|
481
498
|
if is_member {
|
|
482
499
|
Ok(AuthorizationDecision::Allow)
|
|
483
500
|
} else {
|
|
484
|
-
Err(PolicyAuthorizationError::unauthorized(
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
),
|
|
489
|
-
))
|
|
501
|
+
Err(PolicyAuthorizationError::unauthorized(format!(
|
|
502
|
+
"actor {} is not a member of organization {}",
|
|
503
|
+
actor.id, organization_id
|
|
504
|
+
)))
|
|
490
505
|
}
|
|
491
506
|
}
|
|
492
507
|
|
|
@@ -530,12 +545,10 @@ impl PolicyEvaluator {
|
|
|
530
545
|
if actor.id == owner_id {
|
|
531
546
|
Ok(AuthorizationDecision::Allow)
|
|
532
547
|
} else {
|
|
533
|
-
Err(PolicyAuthorizationError::unauthorized(
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
),
|
|
538
|
-
))
|
|
548
|
+
Err(PolicyAuthorizationError::unauthorized(format!(
|
|
549
|
+
"actor {} is not the owner ({})",
|
|
550
|
+
actor.id, owner_id
|
|
551
|
+
)))
|
|
539
552
|
}
|
|
540
553
|
}
|
|
541
554
|
|
|
@@ -559,7 +572,8 @@ impl PolicyEvaluator {
|
|
|
559
572
|
})?;
|
|
560
573
|
|
|
561
574
|
// Find the reference field from this collection to Organization
|
|
562
|
-
let org_ref_field = auth_state
|
|
575
|
+
let org_ref_field = auth_state
|
|
576
|
+
.find_reference_field(&context.collection, "Organization")
|
|
563
577
|
.or_else(|| auth_state.find_reference_field(&context.collection, "Organizations"))
|
|
564
578
|
.ok_or_else(|| {
|
|
565
579
|
PolicyAuthorizationError::new(
|
|
@@ -569,7 +583,8 @@ impl PolicyEvaluator {
|
|
|
569
583
|
})?;
|
|
570
584
|
|
|
571
585
|
// Extract the organization ID from the record
|
|
572
|
-
let organization_id = context
|
|
586
|
+
let organization_id = context
|
|
587
|
+
.field(&org_ref_field)
|
|
573
588
|
.and_then(|v| v.as_str())
|
|
574
589
|
.ok_or_else(|| {
|
|
575
590
|
PolicyAuthorizationError::new(
|
|
@@ -588,7 +603,8 @@ impl PolicyEvaluator {
|
|
|
588
603
|
})?;
|
|
589
604
|
|
|
590
605
|
// Find the field names for user and organization references in the membership collection
|
|
591
|
-
let (user_field, org_field) = auth_state
|
|
606
|
+
let (user_field, org_field) = auth_state
|
|
607
|
+
.find_membership_fields(&membership_collection)
|
|
592
608
|
.ok_or_else(|| {
|
|
593
609
|
PolicyAuthorizationError::new(
|
|
594
610
|
"MEMBERSHIP_NOT_DEFINED",
|
|
@@ -622,12 +638,10 @@ impl PolicyEvaluator {
|
|
|
622
638
|
if has_membership {
|
|
623
639
|
Ok(AuthorizationDecision::Allow)
|
|
624
640
|
} else {
|
|
625
|
-
Err(PolicyAuthorizationError::unauthorized(
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
),
|
|
630
|
-
))
|
|
641
|
+
Err(PolicyAuthorizationError::unauthorized(format!(
|
|
642
|
+
"actor {} is not a member of organization {}",
|
|
643
|
+
actor.id, organization_id
|
|
644
|
+
)))
|
|
631
645
|
}
|
|
632
646
|
}
|
|
633
647
|
|
|
@@ -639,12 +653,11 @@ impl PolicyEvaluator {
|
|
|
639
653
|
context: &RecordAuthorizationContext,
|
|
640
654
|
) -> Result<AuthorizationDecision, PolicyAuthorizationError> {
|
|
641
655
|
let actor = context.actor.as_ref().ok_or_else(|| {
|
|
642
|
-
PolicyAuthorizationError::unauthenticated(
|
|
643
|
-
"self policy requires an authenticated actor",
|
|
644
|
-
)
|
|
656
|
+
PolicyAuthorizationError::unauthenticated("self policy requires an authenticated actor")
|
|
645
657
|
})?;
|
|
646
658
|
|
|
647
|
-
let field_value = context
|
|
659
|
+
let field_value = context
|
|
660
|
+
.field(field)
|
|
648
661
|
.and_then(|v| v.as_str())
|
|
649
662
|
.ok_or_else(|| {
|
|
650
663
|
PolicyAuthorizationError::new(
|
|
@@ -656,12 +669,10 @@ impl PolicyEvaluator {
|
|
|
656
669
|
if actor.id == field_value {
|
|
657
670
|
Ok(AuthorizationDecision::Allow)
|
|
658
671
|
} else {
|
|
659
|
-
Err(PolicyAuthorizationError::unauthorized(
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
),
|
|
664
|
-
))
|
|
672
|
+
Err(PolicyAuthorizationError::unauthorized(format!(
|
|
673
|
+
"actor {} does not match identity field {}",
|
|
674
|
+
actor.id, field
|
|
675
|
+
)))
|
|
665
676
|
}
|
|
666
677
|
}
|
|
667
678
|
}
|
|
@@ -720,9 +731,15 @@ mod tests {
|
|
|
720
731
|
|
|
721
732
|
#[test]
|
|
722
733
|
fn policy_subject_from_str() {
|
|
723
|
-
assert_eq!(
|
|
734
|
+
assert_eq!(
|
|
735
|
+
PolicySubject::from_str("authenticated"),
|
|
736
|
+
Some(PolicySubject::Authenticated)
|
|
737
|
+
);
|
|
724
738
|
assert_eq!(PolicySubject::from_str("owner"), Some(PolicySubject::Owner));
|
|
725
|
-
assert_eq!(
|
|
739
|
+
assert_eq!(
|
|
740
|
+
PolicySubject::from_str("member"),
|
|
741
|
+
Some(PolicySubject::Member)
|
|
742
|
+
);
|
|
726
743
|
assert_eq!(PolicySubject::from_str("invalid"), None);
|
|
727
744
|
}
|
|
728
745
|
|
|
@@ -932,12 +949,8 @@ mod tests {
|
|
|
932
949
|
#[test]
|
|
933
950
|
fn existing_owner_policy_works_with_state() {
|
|
934
951
|
let record = serde_json::json!({"_id": "rec1", "owner_id": "user123"});
|
|
935
|
-
let context =
|
|
936
|
-
Some(Actor::new("user123")),
|
|
937
|
-
"Project",
|
|
938
|
-
"rec1",
|
|
939
|
-
record,
|
|
940
|
-
);
|
|
952
|
+
let context =
|
|
953
|
+
RecordAuthorizationContext::new(Some(Actor::new("user123")), "Project", "rec1", record);
|
|
941
954
|
|
|
942
955
|
// Should work even though authorization_state is None
|
|
943
956
|
let result = PolicyEvaluator::evaluate_record(PolicySubject::Owner, &context);
|
|
@@ -947,12 +960,8 @@ mod tests {
|
|
|
947
960
|
#[test]
|
|
948
961
|
fn existing_authenticated_policy_works_with_state() {
|
|
949
962
|
let record = serde_json::json!({"_id": "rec1"});
|
|
950
|
-
let context =
|
|
951
|
-
Some(Actor::new("user123")),
|
|
952
|
-
"Project",
|
|
953
|
-
"rec1",
|
|
954
|
-
record,
|
|
955
|
-
);
|
|
963
|
+
let context =
|
|
964
|
+
RecordAuthorizationContext::new(Some(Actor::new("user123")), "Project", "rec1", record);
|
|
956
965
|
|
|
957
966
|
// Should work even though authorization_state is None
|
|
958
967
|
let result = PolicyEvaluator::evaluate_record(PolicySubject::Authenticated, &context);
|
|
@@ -963,7 +972,9 @@ mod tests {
|
|
|
963
972
|
// These tests verify that member policy is enforced using database state,
|
|
964
973
|
// not caller-supplied attributes.
|
|
965
974
|
|
|
966
|
-
fn make_schema_with_collections(
|
|
975
|
+
fn make_schema_with_collections(
|
|
976
|
+
collections: Vec<crate::state_contract::CollectionSchema>,
|
|
977
|
+
) -> Arc<crate::state_contract::StateSchema> {
|
|
967
978
|
Arc::new(crate::state_contract::StateSchema {
|
|
968
979
|
contract_version: 1,
|
|
969
980
|
schema_version: 1,
|
|
@@ -973,7 +984,10 @@ mod tests {
|
|
|
973
984
|
})
|
|
974
985
|
}
|
|
975
986
|
|
|
976
|
-
fn make_collection(
|
|
987
|
+
fn make_collection(
|
|
988
|
+
name: &str,
|
|
989
|
+
fields: Vec<crate::state_contract::FieldSchema>,
|
|
990
|
+
) -> crate::state_contract::CollectionSchema {
|
|
977
991
|
crate::state_contract::CollectionSchema {
|
|
978
992
|
name: name.into(),
|
|
979
993
|
version: 1,
|
|
@@ -982,7 +996,10 @@ mod tests {
|
|
|
982
996
|
}
|
|
983
997
|
}
|
|
984
998
|
|
|
985
|
-
fn make_field(
|
|
999
|
+
fn make_field(
|
|
1000
|
+
name: &str,
|
|
1001
|
+
field_type: crate::state_contract::FieldType,
|
|
1002
|
+
) -> crate::state_contract::FieldSchema {
|
|
986
1003
|
crate::state_contract::FieldSchema {
|
|
987
1004
|
name: name.into(),
|
|
988
1005
|
field_type,
|
|
@@ -999,19 +1016,51 @@ mod tests {
|
|
|
999
1016
|
use crate::state_contract::FieldType;
|
|
1000
1017
|
|
|
1001
1018
|
let schema = make_schema_with_collections(vec![
|
|
1002
|
-
make_collection(
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1019
|
+
make_collection(
|
|
1020
|
+
"Project",
|
|
1021
|
+
vec![
|
|
1022
|
+
make_field(
|
|
1023
|
+
"_id",
|
|
1024
|
+
FieldType::Primitive {
|
|
1025
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1026
|
+
},
|
|
1027
|
+
),
|
|
1028
|
+
make_field(
|
|
1029
|
+
"organization",
|
|
1030
|
+
FieldType::Reference {
|
|
1031
|
+
collection: "Organization".into(),
|
|
1032
|
+
},
|
|
1033
|
+
),
|
|
1034
|
+
],
|
|
1035
|
+
),
|
|
1036
|
+
make_collection(
|
|
1037
|
+
"Membership",
|
|
1038
|
+
vec![
|
|
1039
|
+
make_field(
|
|
1040
|
+
"_id",
|
|
1041
|
+
FieldType::Primitive {
|
|
1042
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1043
|
+
},
|
|
1044
|
+
),
|
|
1045
|
+
make_field(
|
|
1046
|
+
"user",
|
|
1047
|
+
FieldType::Reference {
|
|
1048
|
+
collection: "User".into(),
|
|
1049
|
+
},
|
|
1050
|
+
),
|
|
1051
|
+
make_field(
|
|
1052
|
+
"organization",
|
|
1053
|
+
FieldType::Reference {
|
|
1054
|
+
collection: "Organization".into(),
|
|
1055
|
+
},
|
|
1056
|
+
),
|
|
1057
|
+
],
|
|
1058
|
+
),
|
|
1011
1059
|
]);
|
|
1012
1060
|
|
|
1013
1061
|
let project = serde_json::json!({"_id": "proj1", "organization": "org1"});
|
|
1014
|
-
let membership =
|
|
1062
|
+
let membership =
|
|
1063
|
+
serde_json::json!({"_id": "mem1", "user": "alice", "organization": "org1"});
|
|
1015
1064
|
|
|
1016
1065
|
let snapshot = Arc::new(vec![
|
|
1017
1066
|
make_stored_row("Project", "proj1", project),
|
|
@@ -1036,19 +1085,51 @@ mod tests {
|
|
|
1036
1085
|
use crate::state_contract::FieldType;
|
|
1037
1086
|
|
|
1038
1087
|
let schema = make_schema_with_collections(vec![
|
|
1039
|
-
make_collection(
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1088
|
+
make_collection(
|
|
1089
|
+
"Project",
|
|
1090
|
+
vec![
|
|
1091
|
+
make_field(
|
|
1092
|
+
"_id",
|
|
1093
|
+
FieldType::Primitive {
|
|
1094
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1095
|
+
},
|
|
1096
|
+
),
|
|
1097
|
+
make_field(
|
|
1098
|
+
"organization",
|
|
1099
|
+
FieldType::Reference {
|
|
1100
|
+
collection: "Organization".into(),
|
|
1101
|
+
},
|
|
1102
|
+
),
|
|
1103
|
+
],
|
|
1104
|
+
),
|
|
1105
|
+
make_collection(
|
|
1106
|
+
"Membership",
|
|
1107
|
+
vec![
|
|
1108
|
+
make_field(
|
|
1109
|
+
"_id",
|
|
1110
|
+
FieldType::Primitive {
|
|
1111
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1112
|
+
},
|
|
1113
|
+
),
|
|
1114
|
+
make_field(
|
|
1115
|
+
"user",
|
|
1116
|
+
FieldType::Reference {
|
|
1117
|
+
collection: "User".into(),
|
|
1118
|
+
},
|
|
1119
|
+
),
|
|
1120
|
+
make_field(
|
|
1121
|
+
"organization",
|
|
1122
|
+
FieldType::Reference {
|
|
1123
|
+
collection: "Organization".into(),
|
|
1124
|
+
},
|
|
1125
|
+
),
|
|
1126
|
+
],
|
|
1127
|
+
),
|
|
1048
1128
|
]);
|
|
1049
1129
|
|
|
1050
1130
|
let project = serde_json::json!({"_id": "proj1", "organization": "org1"});
|
|
1051
|
-
let membership =
|
|
1131
|
+
let membership =
|
|
1132
|
+
serde_json::json!({"_id": "mem1", "user": "alice", "organization": "org1"});
|
|
1052
1133
|
|
|
1053
1134
|
let snapshot = Arc::new(vec![
|
|
1054
1135
|
make_stored_row("Project", "proj1", project),
|
|
@@ -1074,19 +1155,51 @@ mod tests {
|
|
|
1074
1155
|
use crate::state_contract::FieldType;
|
|
1075
1156
|
|
|
1076
1157
|
let schema = make_schema_with_collections(vec![
|
|
1077
|
-
make_collection(
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1158
|
+
make_collection(
|
|
1159
|
+
"Project",
|
|
1160
|
+
vec![
|
|
1161
|
+
make_field(
|
|
1162
|
+
"_id",
|
|
1163
|
+
FieldType::Primitive {
|
|
1164
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1165
|
+
},
|
|
1166
|
+
),
|
|
1167
|
+
make_field(
|
|
1168
|
+
"organization",
|
|
1169
|
+
FieldType::Reference {
|
|
1170
|
+
collection: "Organization".into(),
|
|
1171
|
+
},
|
|
1172
|
+
),
|
|
1173
|
+
],
|
|
1174
|
+
),
|
|
1175
|
+
make_collection(
|
|
1176
|
+
"Membership",
|
|
1177
|
+
vec![
|
|
1178
|
+
make_field(
|
|
1179
|
+
"_id",
|
|
1180
|
+
FieldType::Primitive {
|
|
1181
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1182
|
+
},
|
|
1183
|
+
),
|
|
1184
|
+
make_field(
|
|
1185
|
+
"user",
|
|
1186
|
+
FieldType::Reference {
|
|
1187
|
+
collection: "User".into(),
|
|
1188
|
+
},
|
|
1189
|
+
),
|
|
1190
|
+
make_field(
|
|
1191
|
+
"organization",
|
|
1192
|
+
FieldType::Reference {
|
|
1193
|
+
collection: "Organization".into(),
|
|
1194
|
+
},
|
|
1195
|
+
),
|
|
1196
|
+
],
|
|
1197
|
+
),
|
|
1086
1198
|
]);
|
|
1087
1199
|
|
|
1088
1200
|
let project = serde_json::json!({"_id": "proj1", "organization": "org1"});
|
|
1089
|
-
let membership =
|
|
1201
|
+
let membership =
|
|
1202
|
+
serde_json::json!({"_id": "mem1", "user": "alice", "organization": "org1"});
|
|
1090
1203
|
|
|
1091
1204
|
let snapshot = Arc::new(vec![
|
|
1092
1205
|
make_stored_row("Project", "proj1", project),
|
|
@@ -1112,20 +1225,52 @@ mod tests {
|
|
|
1112
1225
|
use crate::state_contract::FieldType;
|
|
1113
1226
|
|
|
1114
1227
|
let schema = make_schema_with_collections(vec![
|
|
1115
|
-
make_collection(
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1228
|
+
make_collection(
|
|
1229
|
+
"Project",
|
|
1230
|
+
vec![
|
|
1231
|
+
make_field(
|
|
1232
|
+
"_id",
|
|
1233
|
+
FieldType::Primitive {
|
|
1234
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1235
|
+
},
|
|
1236
|
+
),
|
|
1237
|
+
make_field(
|
|
1238
|
+
"organization",
|
|
1239
|
+
FieldType::Reference {
|
|
1240
|
+
collection: "Organization".into(),
|
|
1241
|
+
},
|
|
1242
|
+
),
|
|
1243
|
+
],
|
|
1244
|
+
),
|
|
1245
|
+
make_collection(
|
|
1246
|
+
"Membership",
|
|
1247
|
+
vec![
|
|
1248
|
+
make_field(
|
|
1249
|
+
"_id",
|
|
1250
|
+
FieldType::Primitive {
|
|
1251
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1252
|
+
},
|
|
1253
|
+
),
|
|
1254
|
+
make_field(
|
|
1255
|
+
"user",
|
|
1256
|
+
FieldType::Reference {
|
|
1257
|
+
collection: "User".into(),
|
|
1258
|
+
},
|
|
1259
|
+
),
|
|
1260
|
+
make_field(
|
|
1261
|
+
"organization",
|
|
1262
|
+
FieldType::Reference {
|
|
1263
|
+
collection: "Organization".into(),
|
|
1264
|
+
},
|
|
1265
|
+
),
|
|
1266
|
+
],
|
|
1267
|
+
),
|
|
1124
1268
|
]);
|
|
1125
1269
|
|
|
1126
1270
|
// Alice is member of org1, project is in org2
|
|
1127
1271
|
let project = serde_json::json!({"_id": "proj1", "organization": "org2"});
|
|
1128
|
-
let membership =
|
|
1272
|
+
let membership =
|
|
1273
|
+
serde_json::json!({"_id": "mem1", "user": "alice", "organization": "org1"});
|
|
1129
1274
|
|
|
1130
1275
|
let snapshot = Arc::new(vec![
|
|
1131
1276
|
make_stored_row("Project", "proj1", project),
|
|
@@ -1149,16 +1294,15 @@ mod tests {
|
|
|
1149
1294
|
#[test]
|
|
1150
1295
|
fn member_policy_no_state_fails() {
|
|
1151
1296
|
let project = serde_json::json!({"_id": "proj1", "organization": "org1"});
|
|
1152
|
-
let context =
|
|
1153
|
-
Some(Actor::new("alice")),
|
|
1154
|
-
"Project",
|
|
1155
|
-
"proj1",
|
|
1156
|
-
project,
|
|
1157
|
-
); // No state attached
|
|
1297
|
+
let context =
|
|
1298
|
+
RecordAuthorizationContext::new(Some(Actor::new("alice")), "Project", "proj1", project); // No state attached
|
|
1158
1299
|
|
|
1159
1300
|
let result = PolicyEvaluator::evaluate_record(PolicySubject::Member, &context);
|
|
1160
1301
|
assert!(result.is_err());
|
|
1161
|
-
assert_eq!(
|
|
1302
|
+
assert_eq!(
|
|
1303
|
+
result.unwrap_err().code,
|
|
1304
|
+
"AUTHORIZATION_STATE_NOT_AVAILABLE"
|
|
1305
|
+
);
|
|
1162
1306
|
}
|
|
1163
1307
|
|
|
1164
1308
|
#[test]
|
|
@@ -1166,21 +1310,45 @@ mod tests {
|
|
|
1166
1310
|
use crate::state_contract::FieldType;
|
|
1167
1311
|
|
|
1168
1312
|
let schema = make_schema_with_collections(vec![
|
|
1169
|
-
make_collection(
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1313
|
+
make_collection(
|
|
1314
|
+
"Project",
|
|
1315
|
+
vec![
|
|
1316
|
+
make_field(
|
|
1317
|
+
"_id",
|
|
1318
|
+
FieldType::Primitive {
|
|
1319
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1320
|
+
},
|
|
1321
|
+
),
|
|
1322
|
+
// No organization reference
|
|
1323
|
+
],
|
|
1324
|
+
),
|
|
1325
|
+
make_collection(
|
|
1326
|
+
"Membership",
|
|
1327
|
+
vec![
|
|
1328
|
+
make_field(
|
|
1329
|
+
"_id",
|
|
1330
|
+
FieldType::Primitive {
|
|
1331
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1332
|
+
},
|
|
1333
|
+
),
|
|
1334
|
+
make_field(
|
|
1335
|
+
"user",
|
|
1336
|
+
FieldType::Reference {
|
|
1337
|
+
collection: "User".into(),
|
|
1338
|
+
},
|
|
1339
|
+
),
|
|
1340
|
+
make_field(
|
|
1341
|
+
"organization",
|
|
1342
|
+
FieldType::Reference {
|
|
1343
|
+
collection: "Organization".into(),
|
|
1344
|
+
},
|
|
1345
|
+
),
|
|
1346
|
+
],
|
|
1347
|
+
),
|
|
1178
1348
|
]);
|
|
1179
1349
|
|
|
1180
1350
|
let project = serde_json::json!({"_id": "proj1"});
|
|
1181
|
-
let snapshot = Arc::new(vec![
|
|
1182
|
-
make_stored_row("Project", "proj1", project),
|
|
1183
|
-
]);
|
|
1351
|
+
let snapshot = Arc::new(vec![make_stored_row("Project", "proj1", project)]);
|
|
1184
1352
|
|
|
1185
1353
|
let auth_state = AuthorizationState::new(schema, "tenant:123", snapshot);
|
|
1186
1354
|
let context = RecordAuthorizationContext::new(
|
|
@@ -1201,21 +1369,50 @@ mod tests {
|
|
|
1201
1369
|
use crate::state_contract::FieldType;
|
|
1202
1370
|
|
|
1203
1371
|
let schema = make_schema_with_collections(vec![
|
|
1204
|
-
make_collection(
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1372
|
+
make_collection(
|
|
1373
|
+
"Project",
|
|
1374
|
+
vec![
|
|
1375
|
+
make_field(
|
|
1376
|
+
"_id",
|
|
1377
|
+
FieldType::Primitive {
|
|
1378
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1379
|
+
},
|
|
1380
|
+
),
|
|
1381
|
+
make_field(
|
|
1382
|
+
"organization",
|
|
1383
|
+
FieldType::Reference {
|
|
1384
|
+
collection: "Organization".into(),
|
|
1385
|
+
},
|
|
1386
|
+
),
|
|
1387
|
+
],
|
|
1388
|
+
),
|
|
1389
|
+
make_collection(
|
|
1390
|
+
"Membership",
|
|
1391
|
+
vec![
|
|
1392
|
+
make_field(
|
|
1393
|
+
"_id",
|
|
1394
|
+
FieldType::Primitive {
|
|
1395
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1396
|
+
},
|
|
1397
|
+
),
|
|
1398
|
+
make_field(
|
|
1399
|
+
"user",
|
|
1400
|
+
FieldType::Reference {
|
|
1401
|
+
collection: "User".into(),
|
|
1402
|
+
},
|
|
1403
|
+
),
|
|
1404
|
+
make_field(
|
|
1405
|
+
"organization",
|
|
1406
|
+
FieldType::Reference {
|
|
1407
|
+
collection: "Organization".into(),
|
|
1408
|
+
},
|
|
1409
|
+
),
|
|
1410
|
+
],
|
|
1411
|
+
),
|
|
1213
1412
|
]);
|
|
1214
1413
|
|
|
1215
1414
|
let project = serde_json::json!({"_id": "proj1"}); // Missing organization field
|
|
1216
|
-
let snapshot = Arc::new(vec![
|
|
1217
|
-
make_stored_row("Project", "proj1", project),
|
|
1218
|
-
]);
|
|
1415
|
+
let snapshot = Arc::new(vec![make_stored_row("Project", "proj1", project)]);
|
|
1219
1416
|
|
|
1220
1417
|
let auth_state = AuthorizationState::new(schema, "tenant:123", snapshot);
|
|
1221
1418
|
let context = RecordAuthorizationContext::new(
|
|
@@ -1236,20 +1433,54 @@ mod tests {
|
|
|
1236
1433
|
use crate::state_contract::FieldType;
|
|
1237
1434
|
|
|
1238
1435
|
let schema = make_schema_with_collections(vec![
|
|
1239
|
-
make_collection(
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1436
|
+
make_collection(
|
|
1437
|
+
"Project",
|
|
1438
|
+
vec![
|
|
1439
|
+
make_field(
|
|
1440
|
+
"_id",
|
|
1441
|
+
FieldType::Primitive {
|
|
1442
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1443
|
+
},
|
|
1444
|
+
),
|
|
1445
|
+
make_field(
|
|
1446
|
+
"organization",
|
|
1447
|
+
FieldType::Reference {
|
|
1448
|
+
collection: "Organization".into(),
|
|
1449
|
+
},
|
|
1450
|
+
),
|
|
1451
|
+
],
|
|
1452
|
+
),
|
|
1453
|
+
make_collection(
|
|
1454
|
+
"Membership",
|
|
1455
|
+
vec![
|
|
1456
|
+
make_field(
|
|
1457
|
+
"_id",
|
|
1458
|
+
FieldType::Primitive {
|
|
1459
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1460
|
+
},
|
|
1461
|
+
),
|
|
1462
|
+
make_field(
|
|
1463
|
+
"user",
|
|
1464
|
+
FieldType::Reference {
|
|
1465
|
+
collection: "User".into(),
|
|
1466
|
+
},
|
|
1467
|
+
),
|
|
1468
|
+
make_field(
|
|
1469
|
+
"organization",
|
|
1470
|
+
FieldType::Reference {
|
|
1471
|
+
collection: "Organization".into(),
|
|
1472
|
+
},
|
|
1473
|
+
),
|
|
1474
|
+
],
|
|
1475
|
+
),
|
|
1248
1476
|
]);
|
|
1249
1477
|
|
|
1250
1478
|
let project = serde_json::json!({"_id": "proj1", "organization": "org1"});
|
|
1251
|
-
let mut membership = make_stored_row(
|
|
1252
|
-
|
|
1479
|
+
let mut membership = make_stored_row(
|
|
1480
|
+
"Membership",
|
|
1481
|
+
"mem1",
|
|
1482
|
+
serde_json::json!({"_id": "mem1", "user": "alice", "organization": "org1"}),
|
|
1483
|
+
);
|
|
1253
1484
|
membership.deleted = true; // Mark as deleted
|
|
1254
1485
|
|
|
1255
1486
|
let snapshot = Arc::new(vec![
|
|
@@ -1276,24 +1507,67 @@ mod tests {
|
|
|
1276
1507
|
use crate::state_contract::FieldType;
|
|
1277
1508
|
|
|
1278
1509
|
let schema = make_schema_with_collections(vec![
|
|
1279
|
-
make_collection(
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1510
|
+
make_collection(
|
|
1511
|
+
"Project",
|
|
1512
|
+
vec![
|
|
1513
|
+
make_field(
|
|
1514
|
+
"_id",
|
|
1515
|
+
FieldType::Primitive {
|
|
1516
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1517
|
+
},
|
|
1518
|
+
),
|
|
1519
|
+
make_field(
|
|
1520
|
+
"organization",
|
|
1521
|
+
FieldType::Reference {
|
|
1522
|
+
collection: "Organization".into(),
|
|
1523
|
+
},
|
|
1524
|
+
),
|
|
1525
|
+
],
|
|
1526
|
+
),
|
|
1527
|
+
make_collection(
|
|
1528
|
+
"Membership",
|
|
1529
|
+
vec![
|
|
1530
|
+
make_field(
|
|
1531
|
+
"_id",
|
|
1532
|
+
FieldType::Primitive {
|
|
1533
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1534
|
+
},
|
|
1535
|
+
),
|
|
1536
|
+
make_field(
|
|
1537
|
+
"user",
|
|
1538
|
+
FieldType::Reference {
|
|
1539
|
+
collection: "User".into(),
|
|
1540
|
+
},
|
|
1541
|
+
),
|
|
1542
|
+
make_field(
|
|
1543
|
+
"organization",
|
|
1544
|
+
FieldType::Reference {
|
|
1545
|
+
collection: "Organization".into(),
|
|
1546
|
+
},
|
|
1547
|
+
),
|
|
1548
|
+
],
|
|
1549
|
+
),
|
|
1288
1550
|
]);
|
|
1289
1551
|
|
|
1290
1552
|
let project = serde_json::json!({"_id": "proj1", "organization": "org2"});
|
|
1291
1553
|
|
|
1292
1554
|
let snapshot = Arc::new(vec![
|
|
1293
1555
|
make_stored_row("Project", "proj1", project),
|
|
1294
|
-
make_stored_row(
|
|
1295
|
-
|
|
1296
|
-
|
|
1556
|
+
make_stored_row(
|
|
1557
|
+
"Membership",
|
|
1558
|
+
"mem1",
|
|
1559
|
+
serde_json::json!({"_id": "mem1", "user": "alice", "organization": "org1"}),
|
|
1560
|
+
),
|
|
1561
|
+
make_stored_row(
|
|
1562
|
+
"Membership",
|
|
1563
|
+
"mem2",
|
|
1564
|
+
serde_json::json!({"_id": "mem2", "user": "alice", "organization": "org2"}),
|
|
1565
|
+
),
|
|
1566
|
+
make_stored_row(
|
|
1567
|
+
"Membership",
|
|
1568
|
+
"mem3",
|
|
1569
|
+
serde_json::json!({"_id": "mem3", "user": "bob", "organization": "org2"}),
|
|
1570
|
+
),
|
|
1297
1571
|
]);
|
|
1298
1572
|
|
|
1299
1573
|
let auth_state = AuthorizationState::new(schema, "tenant:123", snapshot);
|
|
@@ -1314,21 +1588,51 @@ mod tests {
|
|
|
1314
1588
|
use crate::state_contract::FieldType;
|
|
1315
1589
|
|
|
1316
1590
|
let schema = make_schema_with_collections(vec![
|
|
1317
|
-
make_collection(
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1591
|
+
make_collection(
|
|
1592
|
+
"Project",
|
|
1593
|
+
vec![
|
|
1594
|
+
make_field(
|
|
1595
|
+
"_id",
|
|
1596
|
+
FieldType::Primitive {
|
|
1597
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1598
|
+
},
|
|
1599
|
+
),
|
|
1600
|
+
make_field(
|
|
1601
|
+
"organization",
|
|
1602
|
+
FieldType::Reference {
|
|
1603
|
+
collection: "Organization".into(),
|
|
1604
|
+
},
|
|
1605
|
+
),
|
|
1606
|
+
],
|
|
1607
|
+
),
|
|
1608
|
+
make_collection(
|
|
1609
|
+
"Membership",
|
|
1610
|
+
vec![
|
|
1611
|
+
make_field(
|
|
1612
|
+
"_id",
|
|
1613
|
+
FieldType::Primitive {
|
|
1614
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1615
|
+
},
|
|
1616
|
+
),
|
|
1617
|
+
make_field(
|
|
1618
|
+
"user",
|
|
1619
|
+
FieldType::Reference {
|
|
1620
|
+
collection: "User".into(),
|
|
1621
|
+
},
|
|
1622
|
+
),
|
|
1623
|
+
make_field(
|
|
1624
|
+
"organization",
|
|
1625
|
+
FieldType::Reference {
|
|
1626
|
+
collection: "Organization".into(),
|
|
1627
|
+
},
|
|
1628
|
+
),
|
|
1629
|
+
],
|
|
1630
|
+
),
|
|
1326
1631
|
]);
|
|
1327
1632
|
|
|
1328
|
-
let project =
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
]);
|
|
1633
|
+
let project =
|
|
1634
|
+
serde_json::json!({"_id": "proj1", "organization": "org1", "is_member": "true"});
|
|
1635
|
+
let snapshot = Arc::new(vec![make_stored_row("Project", "proj1", project)]);
|
|
1332
1636
|
|
|
1333
1637
|
let auth_state = AuthorizationState::new(schema, "tenant:123", snapshot);
|
|
1334
1638
|
let context = RecordAuthorizationContext::new(
|
|
@@ -1350,19 +1654,51 @@ mod tests {
|
|
|
1350
1654
|
use crate::state_contract::FieldType;
|
|
1351
1655
|
|
|
1352
1656
|
let schema = make_schema_with_collections(vec![
|
|
1353
|
-
make_collection(
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1657
|
+
make_collection(
|
|
1658
|
+
"Project",
|
|
1659
|
+
vec![
|
|
1660
|
+
make_field(
|
|
1661
|
+
"_id",
|
|
1662
|
+
FieldType::Primitive {
|
|
1663
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1664
|
+
},
|
|
1665
|
+
),
|
|
1666
|
+
make_field(
|
|
1667
|
+
"organization",
|
|
1668
|
+
FieldType::Reference {
|
|
1669
|
+
collection: "Organization".into(),
|
|
1670
|
+
},
|
|
1671
|
+
),
|
|
1672
|
+
],
|
|
1673
|
+
),
|
|
1674
|
+
make_collection(
|
|
1675
|
+
"Membership",
|
|
1676
|
+
vec![
|
|
1677
|
+
make_field(
|
|
1678
|
+
"_id",
|
|
1679
|
+
FieldType::Primitive {
|
|
1680
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1681
|
+
},
|
|
1682
|
+
),
|
|
1683
|
+
make_field(
|
|
1684
|
+
"user",
|
|
1685
|
+
FieldType::Reference {
|
|
1686
|
+
collection: "User".into(),
|
|
1687
|
+
},
|
|
1688
|
+
),
|
|
1689
|
+
make_field(
|
|
1690
|
+
"organization",
|
|
1691
|
+
FieldType::Reference {
|
|
1692
|
+
collection: "Organization".into(),
|
|
1693
|
+
},
|
|
1694
|
+
),
|
|
1695
|
+
],
|
|
1696
|
+
),
|
|
1362
1697
|
]);
|
|
1363
1698
|
|
|
1364
1699
|
let project = serde_json::json!({"_id": "proj1", "organization": "org1"});
|
|
1365
|
-
let membership =
|
|
1700
|
+
let membership =
|
|
1701
|
+
serde_json::json!({"_id": "mem1", "user": "alice", "organization": "org1"});
|
|
1366
1702
|
|
|
1367
1703
|
let snapshot = Arc::new(vec![
|
|
1368
1704
|
make_stored_row("Project", "proj1", project),
|
|
@@ -1392,19 +1728,51 @@ mod tests {
|
|
|
1392
1728
|
use crate::state_contract::FieldType;
|
|
1393
1729
|
|
|
1394
1730
|
let schema = make_schema_with_collections(vec![
|
|
1395
|
-
make_collection(
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1731
|
+
make_collection(
|
|
1732
|
+
"Project",
|
|
1733
|
+
vec![
|
|
1734
|
+
make_field(
|
|
1735
|
+
"_id",
|
|
1736
|
+
FieldType::Primitive {
|
|
1737
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1738
|
+
},
|
|
1739
|
+
),
|
|
1740
|
+
make_field(
|
|
1741
|
+
"organization",
|
|
1742
|
+
FieldType::Reference {
|
|
1743
|
+
collection: "Organization".into(),
|
|
1744
|
+
},
|
|
1745
|
+
),
|
|
1746
|
+
],
|
|
1747
|
+
),
|
|
1748
|
+
make_collection(
|
|
1749
|
+
"Membership",
|
|
1750
|
+
vec![
|
|
1751
|
+
make_field(
|
|
1752
|
+
"_id",
|
|
1753
|
+
FieldType::Primitive {
|
|
1754
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1755
|
+
},
|
|
1756
|
+
),
|
|
1757
|
+
make_field(
|
|
1758
|
+
"user_id",
|
|
1759
|
+
FieldType::Reference {
|
|
1760
|
+
collection: "User".into(),
|
|
1761
|
+
},
|
|
1762
|
+
), // Variation: user_id not user
|
|
1763
|
+
make_field(
|
|
1764
|
+
"organization",
|
|
1765
|
+
FieldType::Reference {
|
|
1766
|
+
collection: "Organization".into(),
|
|
1767
|
+
},
|
|
1768
|
+
),
|
|
1769
|
+
],
|
|
1770
|
+
),
|
|
1404
1771
|
]);
|
|
1405
1772
|
|
|
1406
1773
|
let project = serde_json::json!({"_id": "proj1", "organization": "org1"});
|
|
1407
|
-
let membership =
|
|
1774
|
+
let membership =
|
|
1775
|
+
serde_json::json!({"_id": "mem1", "user_id": "alice", "organization": "org1"});
|
|
1408
1776
|
|
|
1409
1777
|
let snapshot = Arc::new(vec![
|
|
1410
1778
|
make_stored_row("Project", "proj1", project),
|
|
@@ -1433,21 +1801,50 @@ mod tests {
|
|
|
1433
1801
|
use crate::state_contract::FieldType;
|
|
1434
1802
|
|
|
1435
1803
|
let schema = make_schema_with_collections(vec![
|
|
1436
|
-
make_collection(
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1804
|
+
make_collection(
|
|
1805
|
+
"Project",
|
|
1806
|
+
vec![
|
|
1807
|
+
make_field(
|
|
1808
|
+
"_id",
|
|
1809
|
+
FieldType::Primitive {
|
|
1810
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1811
|
+
},
|
|
1812
|
+
),
|
|
1813
|
+
make_field(
|
|
1814
|
+
"organization",
|
|
1815
|
+
FieldType::Reference {
|
|
1816
|
+
collection: "Organization".into(),
|
|
1817
|
+
},
|
|
1818
|
+
),
|
|
1819
|
+
],
|
|
1820
|
+
),
|
|
1821
|
+
make_collection(
|
|
1822
|
+
"Membership",
|
|
1823
|
+
vec![
|
|
1824
|
+
make_field(
|
|
1825
|
+
"_id",
|
|
1826
|
+
FieldType::Primitive {
|
|
1827
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1828
|
+
},
|
|
1829
|
+
),
|
|
1830
|
+
make_field(
|
|
1831
|
+
"user",
|
|
1832
|
+
FieldType::Reference {
|
|
1833
|
+
collection: "User".into(),
|
|
1834
|
+
},
|
|
1835
|
+
),
|
|
1836
|
+
make_field(
|
|
1837
|
+
"organization",
|
|
1838
|
+
FieldType::Reference {
|
|
1839
|
+
collection: "Organization".into(),
|
|
1840
|
+
},
|
|
1841
|
+
),
|
|
1842
|
+
],
|
|
1843
|
+
),
|
|
1445
1844
|
]);
|
|
1446
1845
|
|
|
1447
1846
|
let project = serde_json::json!({"_id": "proj1", "organization": "org1", "role": "admin"});
|
|
1448
|
-
let snapshot = Arc::new(vec![
|
|
1449
|
-
make_stored_row("Project", "proj1", project),
|
|
1450
|
-
]);
|
|
1847
|
+
let snapshot = Arc::new(vec![make_stored_row("Project", "proj1", project)]);
|
|
1451
1848
|
|
|
1452
1849
|
let auth_state = AuthorizationState::new(schema, "tenant:123", snapshot);
|
|
1453
1850
|
let context = RecordAuthorizationContext::new(
|
|
@@ -1469,17 +1866,28 @@ mod tests {
|
|
|
1469
1866
|
use crate::state_contract::FieldType;
|
|
1470
1867
|
|
|
1471
1868
|
let schema = make_schema_with_collections(vec![
|
|
1472
|
-
make_collection(
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1869
|
+
make_collection(
|
|
1870
|
+
"Project",
|
|
1871
|
+
vec![
|
|
1872
|
+
make_field(
|
|
1873
|
+
"_id",
|
|
1874
|
+
FieldType::Primitive {
|
|
1875
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1876
|
+
},
|
|
1877
|
+
),
|
|
1878
|
+
make_field(
|
|
1879
|
+
"organization",
|
|
1880
|
+
FieldType::Reference {
|
|
1881
|
+
collection: "Organization".into(),
|
|
1882
|
+
},
|
|
1883
|
+
),
|
|
1884
|
+
],
|
|
1885
|
+
),
|
|
1476
1886
|
// No membership collection defined
|
|
1477
1887
|
]);
|
|
1478
1888
|
|
|
1479
1889
|
let project = serde_json::json!({"_id": "proj1", "organization": "org1"});
|
|
1480
|
-
let snapshot = Arc::new(vec![
|
|
1481
|
-
make_stored_row("Project", "proj1", project),
|
|
1482
|
-
]);
|
|
1890
|
+
let snapshot = Arc::new(vec![make_stored_row("Project", "proj1", project)]);
|
|
1483
1891
|
|
|
1484
1892
|
let auth_state = AuthorizationState::new(schema, "tenant:123", snapshot);
|
|
1485
1893
|
let context = RecordAuthorizationContext::new(
|
|
@@ -1500,19 +1908,51 @@ mod tests {
|
|
|
1500
1908
|
use crate::state_contract::FieldType;
|
|
1501
1909
|
|
|
1502
1910
|
let schema = make_schema_with_collections(vec![
|
|
1503
|
-
make_collection(
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1911
|
+
make_collection(
|
|
1912
|
+
"Project",
|
|
1913
|
+
vec![
|
|
1914
|
+
make_field(
|
|
1915
|
+
"_id",
|
|
1916
|
+
FieldType::Primitive {
|
|
1917
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1918
|
+
},
|
|
1919
|
+
),
|
|
1920
|
+
make_field(
|
|
1921
|
+
"organization",
|
|
1922
|
+
FieldType::Reference {
|
|
1923
|
+
collection: "Organizations".into(),
|
|
1924
|
+
},
|
|
1925
|
+
), // Plural
|
|
1926
|
+
],
|
|
1927
|
+
),
|
|
1928
|
+
make_collection(
|
|
1929
|
+
"Membership",
|
|
1930
|
+
vec![
|
|
1931
|
+
make_field(
|
|
1932
|
+
"_id",
|
|
1933
|
+
FieldType::Primitive {
|
|
1934
|
+
primitive: crate::state_contract::PrimitiveType::String,
|
|
1935
|
+
},
|
|
1936
|
+
),
|
|
1937
|
+
make_field(
|
|
1938
|
+
"user",
|
|
1939
|
+
FieldType::Reference {
|
|
1940
|
+
collection: "Users".into(),
|
|
1941
|
+
},
|
|
1942
|
+
), // Plural
|
|
1943
|
+
make_field(
|
|
1944
|
+
"organization",
|
|
1945
|
+
FieldType::Reference {
|
|
1946
|
+
collection: "Organizations".into(),
|
|
1947
|
+
},
|
|
1948
|
+
), // Plural
|
|
1949
|
+
],
|
|
1950
|
+
),
|
|
1512
1951
|
]);
|
|
1513
1952
|
|
|
1514
1953
|
let project = serde_json::json!({"_id": "proj1", "organization": "org1"});
|
|
1515
|
-
let membership =
|
|
1954
|
+
let membership =
|
|
1955
|
+
serde_json::json!({"_id": "mem1", "user": "alice", "organization": "org1"});
|
|
1516
1956
|
|
|
1517
1957
|
let snapshot = Arc::new(vec![
|
|
1518
1958
|
make_stored_row("Project", "proj1", project),
|
|
@@ -1543,7 +1983,9 @@ mod tests {
|
|
|
1543
1983
|
);
|
|
1544
1984
|
|
|
1545
1985
|
let result = PolicyEvaluator::evaluate_record(
|
|
1546
|
-
PolicySubject::Self_ {
|
|
1986
|
+
PolicySubject::Self_ {
|
|
1987
|
+
field: "user".to_string(),
|
|
1988
|
+
},
|
|
1547
1989
|
&context,
|
|
1548
1990
|
);
|
|
1549
1991
|
assert_eq!(result, Ok(AuthorizationDecision::Allow));
|
|
@@ -1559,7 +2001,9 @@ mod tests {
|
|
|
1559
2001
|
);
|
|
1560
2002
|
|
|
1561
2003
|
let result = PolicyEvaluator::evaluate_record(
|
|
1562
|
-
PolicySubject::Self_ {
|
|
2004
|
+
PolicySubject::Self_ {
|
|
2005
|
+
field: "user".to_string(),
|
|
2006
|
+
},
|
|
1563
2007
|
&context,
|
|
1564
2008
|
);
|
|
1565
2009
|
assert!(result.is_err());
|
|
@@ -1576,7 +2020,9 @@ mod tests {
|
|
|
1576
2020
|
);
|
|
1577
2021
|
|
|
1578
2022
|
let result = PolicyEvaluator::evaluate_record(
|
|
1579
|
-
PolicySubject::Self_ {
|
|
2023
|
+
PolicySubject::Self_ {
|
|
2024
|
+
field: "user".to_string(),
|
|
2025
|
+
},
|
|
1580
2026
|
&context,
|
|
1581
2027
|
);
|
|
1582
2028
|
assert!(result.is_err());
|
|
@@ -1593,7 +2039,9 @@ mod tests {
|
|
|
1593
2039
|
);
|
|
1594
2040
|
|
|
1595
2041
|
let result = PolicyEvaluator::evaluate_record(
|
|
1596
|
-
PolicySubject::Self_ {
|
|
2042
|
+
PolicySubject::Self_ {
|
|
2043
|
+
field: "user".to_string(),
|
|
2044
|
+
},
|
|
1597
2045
|
&context,
|
|
1598
2046
|
);
|
|
1599
2047
|
assert!(result.is_err());
|
|
@@ -1610,7 +2058,9 @@ mod tests {
|
|
|
1610
2058
|
);
|
|
1611
2059
|
|
|
1612
2060
|
let result = PolicyEvaluator::evaluate_record(
|
|
1613
|
-
PolicySubject::Self_ {
|
|
2061
|
+
PolicySubject::Self_ {
|
|
2062
|
+
field: "user".to_string(),
|
|
2063
|
+
},
|
|
1614
2064
|
&context,
|
|
1615
2065
|
);
|
|
1616
2066
|
assert!(result.is_err());
|
|
@@ -1627,7 +2077,9 @@ mod tests {
|
|
|
1627
2077
|
);
|
|
1628
2078
|
|
|
1629
2079
|
let result = PolicyEvaluator::evaluate_record(
|
|
1630
|
-
PolicySubject::Self_ {
|
|
2080
|
+
PolicySubject::Self_ {
|
|
2081
|
+
field: "owner".to_string(),
|
|
2082
|
+
},
|
|
1631
2083
|
&context,
|
|
1632
2084
|
);
|
|
1633
2085
|
assert_eq!(result, Ok(AuthorizationDecision::Allow));
|
|
@@ -1643,7 +2095,9 @@ mod tests {
|
|
|
1643
2095
|
);
|
|
1644
2096
|
|
|
1645
2097
|
let result = PolicyEvaluator::evaluate_record(
|
|
1646
|
-
PolicySubject::Self_ {
|
|
2098
|
+
PolicySubject::Self_ {
|
|
2099
|
+
field: "owner".to_string(),
|
|
2100
|
+
},
|
|
1647
2101
|
&context,
|
|
1648
2102
|
);
|
|
1649
2103
|
assert!(result.is_err());
|
|
@@ -1663,7 +2117,9 @@ mod tests {
|
|
|
1663
2117
|
|
|
1664
2118
|
#[test]
|
|
1665
2119
|
fn policy_subject_as_str_for_self() {
|
|
1666
|
-
let subject = PolicySubject::Self_ {
|
|
2120
|
+
let subject = PolicySubject::Self_ {
|
|
2121
|
+
field: "user".to_string(),
|
|
2122
|
+
};
|
|
1667
2123
|
assert_eq!(subject.as_str(), "self");
|
|
1668
2124
|
}
|
|
1669
2125
|
}
|