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>
9where
10 D: Deserializer<'de>,
11{
12 let value = serde_yaml::Value::deserialize(deserializer)?;
13 let yaml = serde_yaml::to_string(&value).map_err(serde::de::Error::custom)?;
14 Graph::from_yaml(&yaml).map_err(serde::de::Error::custom)
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct GraphRule {
19 #[serde(default = "allow_effect")]
20 pub effect: RuleEffect,
21 #[serde(default)]
22 pub subject: Option<String>,
23 #[serde(default)]
24 pub subject_has_role: Option<String>,
25 pub action: String,
26 pub resource: String,
27 #[serde(default, rename = "where")]
28 pub conditions: GraphConditions,
29}
30
31#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
32#[serde(rename_all = "snake_case")]
33pub enum RuleEffect {
34 Allow,
35 Deny,
36}
37
38fn allow_effect() -> RuleEffect {
39 RuleEffect::Allow
40}
41
42#[derive(Debug, Clone, Default, Serialize, Deserialize)]
43pub struct GraphConditions {
44 #[serde(default)]
45 pub target: Option<TargetCondition>,
46 #[serde(default)]
47 pub relationship: Option<RelationshipCondition>,
48 #[serde(default)]
49 pub path_exists: Option<PathCondition>,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct TargetCondition {
54 pub resource_prefix: String,
55 #[serde(default)]
56 pub label: Option<String>,
57 #[serde(default)]
58 pub property_equals: BTreeMap<String, Scalar>,
59 #[serde(default)]
60 pub property_not_equals: BTreeMap<String, Scalar>,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct RelationshipCondition {
65 pub resource_prefix: String,
66 pub edge_label: String,
67 #[serde(default)]
68 pub from_label: Option<String>,
69 #[serde(default)]
70 pub to_label: Option<String>,
71 #[serde(default)]
72 pub no_cycle: bool,
73 #[serde(default)]
74 pub from_property_equals: BTreeMap<String, Scalar>,
75 #[serde(default)]
76 pub to_property_equals: BTreeMap<String, Scalar>,
77 #[serde(default)]
78 pub from_property_not_equals: BTreeMap<String, Scalar>,
79 #[serde(default)]
80 pub to_property_not_equals: BTreeMap<String, Scalar>,
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct PathCondition {
85 pub from: String,
86 pub to: String,
87 pub edge: String,
88 #[serde(default)]
89 pub direction: PathDirection,
90}
91
92#[derive(Debug, Clone, Default, Serialize, Deserialize)]
93#[serde(rename_all = "snake_case")]
94pub enum PathDirection {
95 #[default]
96 Out,
97 In,
98 Both,
99}
100
101#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
102#[serde(untagged)]
103pub enum Scalar {
104 Bool(bool),
105 Int(i64),
106 Float(f64),
107 String(String),
108}
109
110impl Scalar {
111 pub(crate) fn as_value(&self) -> Value {
112 match self {
113 Self::Bool(value) => Value::from(*value),
114 Self::Int(value) => Value::from(*value),
115 Self::Float(value) => Value::from(*value),
116 Self::String(value) => Value::from(value),
117 }
118 }
119}