typesec_rbac/graph_policy/
rule.rs1use std::collections::BTreeMap;
4
5use grust::prelude::{Graph, Value};
6use serde::{Deserialize, Deserializer, Serialize};
7
8pub fn deserialize_graph<'de, D>(deserializer: D) -> Result<Graph, D::Error>
10where
11 D: Deserializer<'de>,
12{
13 let value = serde_yaml::Value::deserialize(deserializer)?;
14 let yaml = serde_yaml::to_string(&value).map_err(serde::de::Error::custom)?;
15 Graph::from_yaml(&yaml).map_err(serde::de::Error::custom)
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct GraphRule {
22 #[serde(default = "allow_effect")]
24 pub effect: RuleEffect,
25 #[serde(default)]
27 pub subject: Option<String>,
28 #[serde(default)]
30 pub subject_has_role: Option<String>,
31 pub action: String,
33 pub resource: String,
35 #[serde(default, rename = "where")]
37 pub conditions: GraphConditions,
38}
39
40#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
42#[serde(rename_all = "snake_case")]
43pub enum RuleEffect {
44 Allow,
46 Deny,
48}
49
50fn allow_effect() -> RuleEffect {
51 RuleEffect::Allow
52}
53
54#[derive(Debug, Clone, Default, Serialize, Deserialize)]
57pub struct GraphConditions {
58 #[serde(default)]
60 pub target: Option<TargetCondition>,
61 #[serde(default)]
63 pub relationship: Option<RelationshipCondition>,
64 #[serde(default)]
66 pub path_exists: Option<PathCondition>,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct TargetCondition {
72 pub resource_prefix: String,
74 #[serde(default)]
76 pub label: Option<String>,
77 #[serde(default)]
79 pub property_equals: BTreeMap<String, Scalar>,
80 #[serde(default)]
82 pub property_not_equals: BTreeMap<String, Scalar>,
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct RelationshipCondition {
88 pub resource_prefix: String,
90 pub edge_label: String,
92 #[serde(default)]
94 pub from_label: Option<String>,
95 #[serde(default)]
97 pub to_label: Option<String>,
98 #[serde(default)]
100 pub no_cycle: bool,
101 #[serde(default)]
103 pub from_property_equals: BTreeMap<String, Scalar>,
104 #[serde(default)]
106 pub to_property_equals: BTreeMap<String, Scalar>,
107 #[serde(default)]
109 pub from_property_not_equals: BTreeMap<String, Scalar>,
110 #[serde(default)]
112 pub to_property_not_equals: BTreeMap<String, Scalar>,
113}
114
115#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct PathCondition {
118 pub from: String,
120 pub to: String,
122 pub edge: String,
124 #[serde(default)]
126 pub direction: PathDirection,
127}
128
129#[derive(Debug, Clone, Default, Serialize, Deserialize)]
131#[serde(rename_all = "snake_case")]
132pub enum PathDirection {
133 #[default]
135 Out,
136 In,
138 Both,
140}
141
142#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
144#[serde(untagged)]
145pub enum Scalar {
146 Bool(bool),
148 Int(i64),
150 Float(f64),
152 String(String),
154}
155
156impl Scalar {
157 pub(crate) fn as_value(&self) -> Value {
158 match self {
159 Self::Bool(value) => Value::from(*value),
160 Self::Int(value) => Value::from(*value),
161 Self::Float(value) => Value::from(*value),
162 Self::String(value) => Value::from(value),
163 }
164 }
165}