Skip to main content

alien_permissions/
lib.rs

1pub mod error;
2pub mod generators;
3pub mod registry;
4pub mod variables;
5
6pub use error::*;
7pub use registry::{get_permission_set, has_permission_set, list_permission_set_ids};
8pub use variables::VariableInterpolator;
9
10// Core types are re-exported by the generators that need them
11
12/// Context for generating permissions with type-safe variables
13#[derive(Debug, Clone)]
14pub struct PermissionContext {
15    // AWS variables
16    pub aws_account_id: Option<String>,
17    pub aws_region: Option<String>,
18
19    // GCP variables
20    pub project_name: Option<String>,
21    pub region: Option<String>,
22
23    // Azure variables
24    pub subscription_id: Option<String>,
25    pub resource_group: Option<String>,
26    pub storage_account_name: Option<String>,
27
28    // Common variables
29    pub stack_prefix: Option<String>,
30    pub resource_name: Option<String>,
31    pub service_account_name: Option<String>,
32    pub principal_id: Option<String>,
33    pub external_id: Option<String>,
34    pub managing_role_arn: Option<String>,
35    pub managing_account_id: Option<String>,
36}
37
38impl PermissionContext {
39    /// Create a new permission context
40    pub fn new() -> Self {
41        Self {
42            aws_account_id: None,
43            aws_region: None,
44            project_name: None,
45            region: None,
46            subscription_id: None,
47            resource_group: None,
48            storage_account_name: None,
49            stack_prefix: None,
50            resource_name: None,
51            service_account_name: None,
52            principal_id: None,
53            external_id: None,
54            managing_role_arn: None,
55            managing_account_id: None,
56        }
57    }
58
59    /// Builder pattern for AWS account ID
60    pub fn with_aws_account_id(mut self, aws_account_id: impl Into<String>) -> Self {
61        self.aws_account_id = Some(aws_account_id.into());
62        self
63    }
64
65    /// Builder pattern for AWS region
66    pub fn with_aws_region(mut self, aws_region: impl Into<String>) -> Self {
67        self.aws_region = Some(aws_region.into());
68        self
69    }
70
71    /// Builder pattern for GCP project name
72    pub fn with_project_name(mut self, project_name: impl Into<String>) -> Self {
73        self.project_name = Some(project_name.into());
74        self
75    }
76
77    /// Builder pattern for GCP region (used in artifact-registry, function, network permission sets)
78    pub fn with_region(mut self, region: impl Into<String>) -> Self {
79        self.region = Some(region.into());
80        self
81    }
82
83    /// Builder pattern for Azure subscription ID
84    pub fn with_subscription_id(mut self, subscription_id: impl Into<String>) -> Self {
85        self.subscription_id = Some(subscription_id.into());
86        self
87    }
88
89    /// Builder pattern for Azure resource group
90    pub fn with_resource_group(mut self, resource_group: impl Into<String>) -> Self {
91        self.resource_group = Some(resource_group.into());
92        self
93    }
94
95    /// Builder pattern for Azure storage account name
96    pub fn with_storage_account_name(mut self, storage_account_name: impl Into<String>) -> Self {
97        self.storage_account_name = Some(storage_account_name.into());
98        self
99    }
100
101    /// Builder pattern for stack prefix
102    pub fn with_stack_prefix(mut self, stack_prefix: impl Into<String>) -> Self {
103        self.stack_prefix = Some(stack_prefix.into());
104        self
105    }
106
107    /// Builder pattern for resource name
108    pub fn with_resource_name(mut self, resource_name: impl Into<String>) -> Self {
109        self.resource_name = Some(resource_name.into());
110        self
111    }
112
113    /// Builder pattern for service account name
114    pub fn with_service_account_name(mut self, service_account_name: impl Into<String>) -> Self {
115        self.service_account_name = Some(service_account_name.into());
116        self
117    }
118
119    /// Builder pattern for principal ID
120    pub fn with_principal_id(mut self, principal_id: impl Into<String>) -> Self {
121        self.principal_id = Some(principal_id.into());
122        self
123    }
124
125    /// Builder pattern for external ID
126    pub fn with_external_id(mut self, external_id: impl Into<String>) -> Self {
127        self.external_id = Some(external_id.into());
128        self
129    }
130
131    /// Builder pattern for managing role ARN
132    pub fn with_managing_role_arn(mut self, managing_role_arn: impl Into<String>) -> Self {
133        self.managing_role_arn = Some(managing_role_arn.into());
134        self
135    }
136
137    /// Builder pattern for managing account ID
138    pub fn with_managing_account_id(mut self, managing_account_id: impl Into<String>) -> Self {
139        self.managing_account_id = Some(managing_account_id.into());
140        self
141    }
142
143    /// Extract AWS account ID from an IAM role ARN
144    /// Format: arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME
145    pub fn extract_account_id_from_role_arn(role_arn: &str) -> Option<String> {
146        let parts: Vec<&str> = role_arn.split(':').collect();
147        if parts.len() >= 5 && parts[0] == "arn" && parts[2] == "iam" {
148            Some(parts[4].to_string())
149        } else {
150            None
151        }
152    }
153
154    /// Get a variable by name (for backward compatibility with interpolation)
155    pub fn get_variable(&self, key: &str) -> Option<&str> {
156        match key {
157            "awsAccountId" => self.aws_account_id.as_deref(),
158            "awsRegion" => self.aws_region.as_deref(),
159            "projectName" => self.project_name.as_deref(),
160            "region" => self.region.as_deref(),
161            "subscriptionId" => self.subscription_id.as_deref(),
162            "resourceGroup" => self.resource_group.as_deref(),
163            "storageAccountName" => self.storage_account_name.as_deref(),
164            "stackPrefix" => self.stack_prefix.as_deref(),
165            "resourceName" => self.resource_name.as_deref(),
166            "serviceAccountName" => self.service_account_name.as_deref(),
167            "principalId" => self.principal_id.as_deref(),
168            "externalId" => self.external_id.as_deref(),
169            "managingRoleArn" => self.managing_role_arn.as_deref(),
170            "managingAccountId" => self.managing_account_id.as_deref(),
171            _ => None,
172        }
173    }
174}
175
176impl Default for PermissionContext {
177    fn default() -> Self {
178        Self::new()
179    }
180}
181
182/// Binding target type for permissions
183#[derive(Debug, Clone, Copy, PartialEq, Eq)]
184pub enum BindingTarget {
185    /// Stack-level binding
186    Stack,
187    /// Resource-level binding  
188    Resource,
189}
190
191impl std::fmt::Display for BindingTarget {
192    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
193        match self {
194            BindingTarget::Stack => write!(f, "stack"),
195            BindingTarget::Resource => write!(f, "resource"),
196        }
197    }
198}