Skip to main content

reifydb_engine/policy/
mod.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
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, EvalContext},
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	symbol_table: &'a SymbolTable,
33}
34
35impl<'a> PolicyEvaluator<'a> {
36	pub fn new(services: &'a Arc<Services>, symbol_table: &'a SymbolTable) -> Self {
37		Self {
38			services,
39			symbol_table,
40		}
41	}
42
43	pub fn enforce_write_policies(
44		&self,
45		tx: &mut Transaction<'_>,
46		identity: IdentityId,
47		target_namespace: &str,
48		target_object: &str,
49		operation: &str,
50		row_columns: &Columns,
51		target_type: PolicyTargetType,
52	) -> Result<()> {
53		enforce_write_policies(
54			&self.services.catalog,
55			tx,
56			identity,
57			target_namespace,
58			target_object,
59			operation,
60			row_columns,
61			target_type,
62			self,
63		)
64	}
65
66	pub fn enforce_session_policy(
67		&self,
68		tx: &mut Transaction<'_>,
69		identity: IdentityId,
70		session_type: &str,
71		default_deny: bool,
72	) -> Result<()> {
73		enforce_session_policy(&self.services.catalog, tx, identity, session_type, default_deny, self)
74	}
75
76	pub fn enforce_identity_policy(
77		&self,
78		tx: &mut Transaction<'_>,
79		identity: IdentityId,
80		target_namespace: &str,
81		target_object: &str,
82		operation: &str,
83		target_type: PolicyTargetType,
84	) -> Result<()> {
85		enforce_identity_policy(
86			&self.services.catalog,
87			tx,
88			identity,
89			target_namespace,
90			target_object,
91			operation,
92			target_type,
93			self,
94		)
95	}
96}
97
98impl PolicyEvaluatorTrait for PolicyEvaluator<'_> {
99	fn evaluate_condition(
100		&self,
101		expr: &Expression,
102		columns: &Columns,
103		row_count: usize,
104		identity: IdentityId,
105	) -> Result<bool> {
106		let compile_ctx = CompileContext {
107			functions: &self.services.functions,
108			symbol_table: self.symbol_table,
109		};
110		let compiled = compile_expression(&compile_ctx, expr)?;
111
112		let eval_ctx = EvalContext {
113			target: None,
114			columns: columns.clone(),
115			row_count,
116			take: None,
117			params: &Params::None,
118			symbol_table: self.symbol_table,
119			is_aggregate_context: false,
120			functions: &self.services.functions,
121			clock: &self.services.clock,
122			arena: None,
123			identity,
124		};
125
126		let result = compiled.execute(&eval_ctx)?;
127
128		let denied = match result.data() {
129			ColumnData::Bool(container) => {
130				(0..row_count).any(|i| !container.is_defined(i) || !container.data().get(i))
131			}
132			ColumnData::Option {
133				inner,
134				bitvec,
135			} => match inner.as_ref() {
136				ColumnData::Bool(container) => (0..row_count).any(|i| {
137					let defined = i < bitvec.len() && bitvec.get(i);
138					let valid = defined && container.is_defined(i);
139					!(valid && container.data().get(i))
140				}),
141				_ => true,
142			},
143			_ => true,
144		};
145
146		Ok(!denied)
147	}
148}