1use std::sync::Arc;
5
6use arrow_array::RecordBatch;
7use reifydb_core::{
8 expression::Expression,
9 interface::catalog::policy::{CallableOp, DataOp, PolicyTargetType, SessionOp},
10 value::batch::empty_batch,
11};
12use reifydb_evaluate::{expression::context::EvalContext, lower::LoweredExpr, stack::SymbolTable};
13use reifydb_policy::{
14 enforce::{
15 CompiledWritePolicies, PolicyTarget, compile_write_policies, enforce_identity_policy,
16 enforce_session_policy, enforce_write_policies,
17 },
18 evaluate::PolicyEvaluator as PolicyEvaluatorTrait,
19};
20use reifydb_transaction::transaction::Transaction;
21use reifydb_value::{
22 Result,
23 params::Params,
24 value::{
25 column_view::{ColumnView, ViewData},
26 identity::IdentityId,
27 },
28};
29
30use crate::vm::services::Services;
31
32pub struct PolicyEvaluator<'a> {
33 services: &'a Arc<Services>,
34 symbols: &'a SymbolTable,
35}
36
37impl<'a> PolicyEvaluator<'a> {
38 pub fn new(services: &'a Arc<Services>, symbols: &'a SymbolTable) -> Self {
39 Self {
40 services,
41 symbols,
42 }
43 }
44
45 pub fn enforce_write_policies(
46 &self,
47 tx: &mut Transaction<'_>,
48 target_namespace: &str,
49 target_object: &str,
50 operation: DataOp,
51 row_columns: &RecordBatch,
52 target_type: PolicyTargetType,
53 ) -> Result<()> {
54 let target = PolicyTarget {
55 namespace: target_namespace,
56 object: target_object,
57 operation: operation.as_str(),
58 target_type,
59 };
60 enforce_write_policies(&self.services.catalog, tx, &target, row_columns, self)
61 }
62
63 pub fn compile_write_policies(
64 &self,
65 tx: &mut Transaction<'_>,
66 target_namespace: &str,
67 target_object: &str,
68 operation: DataOp,
69 target_type: PolicyTargetType,
70 ) -> Result<Option<CompiledWritePolicies>> {
71 let target = PolicyTarget {
72 namespace: target_namespace,
73 object: target_object,
74 operation: operation.as_str(),
75 target_type,
76 };
77 compile_write_policies(&self.services.catalog, tx, &target)
78 }
79
80 pub fn enforce_compiled(
81 &self,
82 compiled: &CompiledWritePolicies,
83 identity: IdentityId,
84 row_columns: &RecordBatch,
85 ) -> Result<()> {
86 compiled.enforce(row_columns, identity, self)
87 }
88
89 pub fn enforce_compiled_row_dependent(
90 &self,
91 compiled: &CompiledWritePolicies,
92 identity: IdentityId,
93 row_columns: &RecordBatch,
94 ) -> Result<()> {
95 compiled.enforce_row_dependent(row_columns, identity, self)
96 }
97
98 pub fn enforce_session_policy(
99 &self,
100 tx: &mut Transaction<'_>,
101 session_type: SessionOp,
102 default_deny: bool,
103 ) -> Result<()> {
104 enforce_session_policy(&self.services.catalog, tx, session_type.as_str(), default_deny, self)
105 }
106
107 pub fn enforce_identity_policy(
108 &self,
109 tx: &mut Transaction<'_>,
110 target_namespace: &str,
111 target_object: &str,
112 operation: CallableOp,
113 target_type: PolicyTargetType,
114 ) -> Result<()> {
115 let target = PolicyTarget {
116 namespace: target_namespace,
117 object: target_object,
118 operation: operation.as_str(),
119 target_type,
120 };
121 enforce_identity_policy(&self.services.catalog, tx, &target, self)
122 }
123}
124
125impl PolicyEvaluatorTrait for PolicyEvaluator<'_> {
126 fn evaluate_condition(
127 &self,
128 expr: &Expression,
129 batch: &RecordBatch,
130 row_count: usize,
131 identity: IdentityId,
132 ) -> Result<bool> {
133 let lowered = LoweredExpr::new(expr.clone(), "policy");
134
135 let base = EvalContext {
136 params: &Params::None,
137 symbols: self.symbols,
138 routines: &self.services.routines,
139 runtime_context: &self.services.runtime_context,
140 identity,
141 batch: empty_batch(),
142 row_count: 1,
143 target: None,
144 take: None,
145 };
146 let eval_ctx = base.with_eval(batch.clone(), row_count);
147
148 let result = lowered.evaluate(&eval_ctx)?;
149 let view = ColumnView::try_from(&result)?;
150
151 let denied = match &view.data {
152 ViewData::Bool(container) => {
153 (0..row_count).any(|i| !(view.is_defined(i) && container.value(i)))
154 }
155 _ => true,
156 };
157
158 Ok(!denied)
159 }
160}