Skip to main content

reifydb_core/interface/catalog/
policy.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use serde::{Deserialize, Serialize};
5
6// Security policy types
7
8pub type PolicyId = u64;
9
10/// CRUD verbs for data-shape targets (Table, View, Series, RingBuffer, Dictionary, Column,
11/// Namespace). Reads are `from` because `FROM` is the RQL read verb.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13pub enum DataOp {
14	From,
15	Insert,
16	Update,
17	Delete,
18}
19
20impl DataOp {
21	pub const ALL: &'static [DataOp] = &[DataOp::From, DataOp::Insert, DataOp::Update, DataOp::Delete];
22
23	pub fn as_str(&self) -> &'static str {
24		match self {
25			Self::From => "from",
26			Self::Insert => "insert",
27			Self::Update => "update",
28			Self::Delete => "delete",
29		}
30	}
31
32	pub fn parse(s: &str) -> Option<Self> {
33		match s {
34			"from" => Some(Self::From),
35			"insert" => Some(Self::Insert),
36			"update" => Some(Self::Update),
37			"delete" => Some(Self::Delete),
38			_ => None,
39		}
40	}
41}
42
43/// Procedure / Function invocation.
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
45pub enum CallableOp {
46	Call,
47}
48
49impl CallableOp {
50	pub const ALL: &'static [CallableOp] = &[CallableOp::Call];
51
52	pub fn as_str(&self) -> &'static str {
53		match self {
54			Self::Call => "call",
55		}
56	}
57
58	pub fn parse(s: &str) -> Option<Self> {
59		match s {
60			"call" => Some(Self::Call),
61			_ => None,
62		}
63	}
64}
65
66/// Session-scoped transaction kinds.
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
68pub enum SessionOp {
69	Admin,
70	Command,
71	Query,
72	Subscription,
73}
74
75impl SessionOp {
76	pub const ALL: &'static [SessionOp] =
77		&[SessionOp::Admin, SessionOp::Command, SessionOp::Query, SessionOp::Subscription];
78
79	pub fn as_str(&self) -> &'static str {
80		match self {
81			Self::Admin => "admin",
82			Self::Command => "command",
83			Self::Query => "query",
84			Self::Subscription => "subscription",
85		}
86	}
87
88	pub fn parse(s: &str) -> Option<Self> {
89		match s {
90			"admin" => Some(Self::Admin),
91			"command" => Some(Self::Command),
92			"query" => Some(Self::Query),
93			"subscription" => Some(Self::Subscription),
94			_ => None,
95		}
96	}
97}
98
99#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
100pub enum PolicyTargetType {
101	Table,
102	Column,
103	Namespace,
104	Procedure,
105	Function,
106	Subscription,
107	Series,
108	Dictionary,
109	Session,
110	Feature,
111	View,
112	RingBuffer,
113}
114
115impl PolicyTargetType {
116	pub fn as_str(&self) -> &'static str {
117		match self {
118			Self::Table => "table",
119			Self::Column => "column",
120			Self::Namespace => "namespace",
121			Self::Procedure => "procedure",
122			Self::Function => "function",
123			Self::Subscription => "subscription",
124			Self::Series => "series",
125			Self::Dictionary => "dictionary",
126			Self::Session => "session",
127			Self::Feature => "feature",
128			Self::View => "view",
129			Self::RingBuffer => "ringbuffer",
130		}
131	}
132
133	/// True iff `op` is a recognised operation name for this target type.
134	/// Routes through the per-category enum's `parse`, so the enum is the single source
135	/// of truth and drift is impossible.
136	pub fn is_valid_operation(&self, op: &str) -> bool {
137		match self {
138			Self::Table
139			| Self::View
140			| Self::Series
141			| Self::RingBuffer
142			| Self::Dictionary
143			| Self::Column
144			| Self::Namespace => DataOp::parse(op).is_some(),
145			Self::Procedure | Self::Function => CallableOp::parse(op).is_some(),
146			Self::Session => SessionOp::parse(op).is_some(),
147			Self::Subscription | Self::Feature => false,
148		}
149	}
150
151	/// Static list of canonical operation names for this target type. Used by the CA_086
152	/// error help text to tell callers what operations *are* accepted.
153	pub fn valid_operation_names(&self) -> &'static [&'static str] {
154		match self {
155			Self::Table
156			| Self::View
157			| Self::Series
158			| Self::RingBuffer
159			| Self::Dictionary
160			| Self::Column
161			| Self::Namespace => &["from", "insert", "update", "delete"],
162			Self::Procedure | Self::Function => &["call"],
163			Self::Session => &["admin", "command", "query", "subscription"],
164			Self::Subscription | Self::Feature => &[],
165		}
166	}
167}
168
169#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
170pub struct Policy {
171	pub id: PolicyId,
172	pub name: Option<String>,
173	pub target_type: PolicyTargetType,
174	pub target_namespace: Option<String>,
175	pub target_shape: Option<String>,
176	pub enabled: bool,
177}
178
179#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
180pub struct PolicyOperation {
181	pub policy_id: PolicyId,
182	pub operation: String,
183	pub body_source: String,
184}
185
186pub struct PolicyToCreate {
187	pub name: Option<String>,
188	pub target_type: PolicyTargetType,
189	pub target_namespace: Option<String>,
190	pub target_shape: Option<String>,
191	pub operations: Vec<PolicyOpToCreate>,
192}
193
194pub struct PolicyOpToCreate {
195	pub operation: String,
196	pub body_source: String,
197}