Skip to main content

reifydb_engine/policy/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use std::sync::Arc;
5
6use reifydb_core::{
7	interface::catalog::policy::PolicyTargetType,
8	value::column::{columns::Columns, data::ColumnData},
9};
10use reifydb_policy::{
11	enforce::{PolicyTarget, enforce_identity_policy, enforce_session_policy, enforce_write_policies},
12	evaluate::PolicyEvaluator as PolicyEvaluatorTrait,
13};
14use reifydb_rql::expression::Expression;
15use reifydb_transaction::transaction::Transaction;
16use reifydb_type::{Result, params::Params, value::identity::IdentityId};
17
18use crate::{
19	expression::{
20		compile::compile_expression,
21		context::{CompileContext, EvalSession},
22	},
23	vm::{services::Services, stack::SymbolTable},
24};
25
26/// Engine-side implementation of the policy evaluator trait.
27///
28/// Holds references to `Services` (for functions/clock) and `SymbolTable`
29/// (for variable resolution), and compiles+evaluates RQL expressions.
30pub struct PolicyEvaluator<'a> {
31	services: &'a Arc<Services>,
32	symbols: &'a SymbolTable,
33}
34
35impl<'a> PolicyEvaluator<'a> {
36	pub fn new(services: &'a Arc<Services>, symbols: &'a SymbolTable) -> Self {
37		Self {
38			services,
39			symbols,
40		}
41	}
42
43	pub fn enforce_write_policies(
44		&self,
45		tx: &mut Transaction<'_>,
46		target_namespace: &str,
47		target_shape: &str,
48		operation: &str,
49		row_columns: &Columns,
50		target_type: PolicyTargetType,
51	) -> Result<()> {
52		let target = PolicyTarget {
53			namespace: target_namespace,
54			shape: target_shape,
55			operation,
56			target_type,
57		};
58		enforce_write_policies(&self.services.catalog, tx, &target, row_columns, self)
59	}
60
61	pub fn enforce_session_policy(
62		&self,
63		tx: &mut Transaction<'_>,
64		session_type: &str,
65		default_deny: bool,
66	) -> Result<()> {
67		enforce_session_policy(&self.services.catalog, tx, session_type, default_deny, self)
68	}
69
70	pub fn enforce_identity_policy(
71		&self,
72		tx: &mut Transaction<'_>,
73		target_namespace: &str,
74		target_shape: &str,
75		operation: &str,
76		target_type: PolicyTargetType,
77	) -> Result<()> {
78		let target = PolicyTarget {
79			namespace: target_namespace,
80			shape: target_shape,
81			operation,
82			target_type,
83		};
84		enforce_identity_policy(&self.services.catalog, tx, &target, self)
85	}
86}
87
88impl PolicyEvaluatorTrait for PolicyEvaluator<'_> {
89	fn evaluate_condition(
90		&self,
91		expr: &Expression,
92		columns: &Columns,
93		row_count: usize,
94		identity: IdentityId,
95	) -> Result<bool> {
96		let compile_ctx = CompileContext {
97			functions: &self.services.functions,
98			symbols: self.symbols,
99		};
100		let compiled = compile_expression(&compile_ctx, expr)?;
101
102		let session = EvalSession {
103			params: &Params::None,
104			symbols: self.symbols,
105			functions: &self.services.functions,
106			runtime_context: &self.services.runtime_context,
107			arena: None,
108			identity,
109			is_aggregate_context: false,
110		};
111		let eval_ctx = session.eval(columns.clone(), row_count);
112
113		let result = compiled.execute(&eval_ctx)?;
114
115		let denied = match result.data() {
116			ColumnData::Bool(container) => {
117				(0..row_count).any(|i| !container.is_defined(i) || !container.data().get(i))
118			}
119			ColumnData::Option {
120				inner,
121				bitvec,
122			} => match inner.as_ref() {
123				ColumnData::Bool(container) => (0..row_count).any(|i| {
124					let defined = i < bitvec.len() && bitvec.get(i);
125					let valid = defined && container.is_defined(i);
126					!(valid && container.data().get(i))
127				}),
128				_ => true,
129			},
130			_ => true,
131		};
132
133		Ok(!denied)
134	}
135}