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::{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_object: &str,
48		operation: &str,
49		row_columns: &Columns,
50		target_type: PolicyTargetType,
51	) -> Result<()> {
52		enforce_write_policies(
53			&self.services.catalog,
54			tx,
55			target_namespace,
56			target_object,
57			operation,
58			row_columns,
59			target_type,
60			self,
61		)
62	}
63
64	pub fn enforce_session_policy(
65		&self,
66		tx: &mut Transaction<'_>,
67		session_type: &str,
68		default_deny: bool,
69	) -> Result<()> {
70		enforce_session_policy(&self.services.catalog, tx, session_type, default_deny, self)
71	}
72
73	pub fn enforce_identity_policy(
74		&self,
75		tx: &mut Transaction<'_>,
76		target_namespace: &str,
77		target_object: &str,
78		operation: &str,
79		target_type: PolicyTargetType,
80	) -> Result<()> {
81		enforce_identity_policy(
82			&self.services.catalog,
83			tx,
84			target_namespace,
85			target_object,
86			operation,
87			target_type,
88			self,
89		)
90	}
91}
92
93impl PolicyEvaluatorTrait for PolicyEvaluator<'_> {
94	fn evaluate_condition(
95		&self,
96		expr: &Expression,
97		columns: &Columns,
98		row_count: usize,
99		identity: IdentityId,
100	) -> Result<bool> {
101		let compile_ctx = CompileContext {
102			functions: &self.services.functions,
103			symbols: self.symbols,
104		};
105		let compiled = compile_expression(&compile_ctx, expr)?;
106
107		let session = EvalSession {
108			params: &Params::None,
109			symbols: self.symbols,
110			functions: &self.services.functions,
111			runtime_context: &self.services.runtime_context,
112			arena: None,
113			identity,
114			is_aggregate_context: false,
115		};
116		let eval_ctx = session.eval(columns.clone(), row_count);
117
118		let result = compiled.execute(&eval_ctx)?;
119
120		let denied = match result.data() {
121			ColumnData::Bool(container) => {
122				(0..row_count).any(|i| !container.is_defined(i) || !container.data().get(i))
123			}
124			ColumnData::Option {
125				inner,
126				bitvec,
127			} => match inner.as_ref() {
128				ColumnData::Bool(container) => (0..row_count).any(|i| {
129					let defined = i < bitvec.len() && bitvec.get(i);
130					let valid = defined && container.is_defined(i);
131					!(valid && container.data().get(i))
132				}),
133				_ => true,
134			},
135			_ => true,
136		};
137
138		Ok(!denied)
139	}
140}