Skip to main content

reifydb_engine/policy/
mod.rs

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