1use indexmap::IndexMap;
4use serde::{Deserialize, Serialize};
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
8#[serde(rename_all = "camelCase", deny_unknown_fields)]
9pub struct PermissionGrant {
10 #[serde(skip_serializing_if = "Option::is_none")]
12 pub actions: Option<Vec<String>>,
13 #[serde(skip_serializing_if = "Option::is_none")]
15 pub permissions: Option<Vec<String>>,
16 #[serde(skip_serializing_if = "Option::is_none")]
18 pub data_actions: Option<Vec<String>>,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
23#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
24#[serde(rename_all = "camelCase", deny_unknown_fields)]
25pub struct AwsBindingSpec {
26 pub resources: Vec<String>,
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub condition: Option<IndexMap<String, IndexMap<String, String>>>,
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
35#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
36#[serde(rename_all = "camelCase", deny_unknown_fields)]
37pub struct GcpBindingSpec {
38 pub scope: String,
40 #[serde(skip_serializing_if = "Option::is_none")]
42 pub condition: Option<GcpCondition>,
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
47#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
48#[serde(rename_all = "camelCase", deny_unknown_fields)]
49pub struct AzureBindingSpec {
50 pub scope: String,
52}
53
54#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
56#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
57#[serde(rename_all = "camelCase", deny_unknown_fields)]
58pub struct BindingConfiguration<T> {
59 #[serde(skip_serializing_if = "Option::is_none")]
61 pub stack: Option<T>,
62 #[serde(skip_serializing_if = "Option::is_none")]
64 pub resource: Option<T>,
65}
66
67impl<T> BindingConfiguration<T> {
68 pub fn is_empty(&self) -> bool {
70 self.stack.is_none() && self.resource.is_none()
71 }
72}
73
74#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
76#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
77#[serde(rename_all = "camelCase", deny_unknown_fields)]
78pub struct GcpCondition {
79 pub title: String,
80 pub expression: String,
81}
82
83#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
85#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
86#[serde(rename_all = "camelCase", deny_unknown_fields)]
87pub struct AwsPlatformPermission {
88 pub grant: PermissionGrant,
90 pub binding: BindingConfiguration<AwsBindingSpec>,
92}
93
94#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
96#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
97#[serde(rename_all = "camelCase", deny_unknown_fields)]
98pub struct GcpPlatformPermission {
99 pub grant: PermissionGrant,
101 pub binding: BindingConfiguration<GcpBindingSpec>,
103}
104
105#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
107#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
108#[serde(rename_all = "camelCase", deny_unknown_fields)]
109pub struct AzurePlatformPermission {
110 pub grant: PermissionGrant,
112 pub binding: BindingConfiguration<AzureBindingSpec>,
114}
115
116#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
118#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
119#[serde(rename_all = "camelCase", deny_unknown_fields)]
120pub struct PlatformPermissions {
121 #[serde(skip_serializing_if = "Option::is_none")]
123 pub aws: Option<Vec<AwsPlatformPermission>>,
124 #[serde(skip_serializing_if = "Option::is_none")]
126 pub gcp: Option<Vec<GcpPlatformPermission>>,
127 #[serde(skip_serializing_if = "Option::is_none")]
129 pub azure: Option<Vec<AzurePlatformPermission>>,
130}
131
132#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
134#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
135#[serde(rename_all = "camelCase", deny_unknown_fields)]
136pub struct PermissionSet {
137 pub id: String,
139 pub description: String,
141 pub platforms: PlatformPermissions,
143}
144
145#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
147#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
148#[serde(untagged)]
149pub enum PermissionSetReference {
150 Name(String),
152 Inline(PermissionSet),
154}
155
156impl PermissionSetReference {
157 pub fn id(&self) -> &str {
159 match self {
160 PermissionSetReference::Name(name) => name,
161 PermissionSetReference::Inline(permission_set) => &permission_set.id,
162 }
163 }
164
165 pub fn from_name(name: impl Into<String>) -> Self {
167 PermissionSetReference::Name(name.into())
168 }
169
170 pub fn from_inline(permission_set: PermissionSet) -> Self {
172 PermissionSetReference::Inline(permission_set)
173 }
174
175 pub fn resolve(
178 &self,
179 resolver: impl Fn(&str) -> Option<PermissionSet>,
180 ) -> Option<PermissionSet> {
181 match self {
182 PermissionSetReference::Name(name) => resolver(name),
183 PermissionSetReference::Inline(permission_set) => Some(permission_set.clone()),
184 }
185 }
186}
187
188#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
191#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
192#[serde(transparent)]
193pub struct PermissionProfile(pub IndexMap<String, Vec<PermissionSetReference>>);
194
195impl PermissionProfile {
196 pub fn new() -> Self {
198 Self(IndexMap::new())
199 }
200
201 pub fn global<I>(mut self, permission_sets: I) -> Self
203 where
204 I: IntoIterator,
205 I::Item: Into<PermissionSetReference>,
206 {
207 let permission_list: Vec<PermissionSetReference> =
208 permission_sets.into_iter().map(|s| s.into()).collect();
209 self.0.insert("*".to_string(), permission_list);
210 self
211 }
212
213 pub fn resource<I>(mut self, resource_name: impl Into<String>, permission_sets: I) -> Self
215 where
216 I: IntoIterator,
217 I::Item: Into<PermissionSetReference>,
218 {
219 let permission_list: Vec<PermissionSetReference> =
220 permission_sets.into_iter().map(|s| s.into()).collect();
221 self.0.insert(resource_name.into(), permission_list);
222 self
223 }
224}
225
226impl Default for PermissionProfile {
227 fn default() -> Self {
228 Self::new()
229 }
230}
231
232impl From<String> for PermissionSetReference {
233 fn from(name: String) -> Self {
234 PermissionSetReference::Name(name)
235 }
236}
237
238impl From<&str> for PermissionSetReference {
239 fn from(name: &str) -> Self {
240 PermissionSetReference::Name(name.to_string())
241 }
242}
243
244impl From<PermissionSet> for PermissionSetReference {
245 fn from(permission_set: PermissionSet) -> Self {
246 PermissionSetReference::Inline(permission_set)
247 }
248}
249
250#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
252#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
253#[serde(rename_all = "camelCase", deny_unknown_fields)]
254pub enum ManagementPermissions {
255 Auto,
260
261 Extend(PermissionProfile),
263
264 Override(PermissionProfile),
266}
267
268impl Default for ManagementPermissions {
269 fn default() -> Self {
270 ManagementPermissions::Auto
271 }
272}
273
274#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
276#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
277#[serde(rename_all = "camelCase", deny_unknown_fields)]
278pub struct PermissionsConfig {
279 pub profiles: IndexMap<String, PermissionProfile>,
282 #[serde(default)]
284 pub management: ManagementPermissions,
285}
286
287impl PermissionsConfig {
288 pub fn new() -> Self {
290 Self {
291 profiles: IndexMap::new(),
292 management: ManagementPermissions::Auto,
293 }
294 }
295
296 pub fn with_profile(mut self, name: impl Into<String>, profile: PermissionProfile) -> Self {
298 self.profiles.insert(name.into(), profile);
299 self
300 }
301
302 pub fn with_management(mut self, management: ManagementPermissions) -> Self {
304 self.management = management;
305 self
306 }
307}
308
309impl Default for PermissionsConfig {
310 fn default() -> Self {
311 Self::new()
312 }
313}
314
315impl ManagementPermissions {
316 pub fn auto() -> Self {
318 ManagementPermissions::Auto
319 }
320
321 pub fn extend(profile: PermissionProfile) -> Self {
323 ManagementPermissions::Extend(profile)
324 }
325
326 pub fn override_(profile: PermissionProfile) -> Self {
328 ManagementPermissions::Override(profile)
329 }
330
331 pub fn profile(&self) -> Option<&PermissionProfile> {
333 match self {
334 ManagementPermissions::Auto => None,
335 ManagementPermissions::Extend(profile) => Some(profile),
336 ManagementPermissions::Override(profile) => Some(profile),
337 }
338 }
339
340 pub fn is_auto(&self) -> bool {
342 matches!(self, ManagementPermissions::Auto)
343 }
344
345 pub fn is_extend(&self) -> bool {
347 matches!(self, ManagementPermissions::Extend(_))
348 }
349
350 pub fn is_override(&self) -> bool {
352 matches!(self, ManagementPermissions::Override(_))
353 }
354}