Skip to main content

vantage_aws/models/iam/
role.rs

1use serde::{Deserialize, Serialize};
2use vantage_table::table::Table;
3
4use crate::types::{Arn, AwsDateTime};
5use crate::{AwsAccount, eq};
6
7use super::attached_policy::{AttachedPolicy, attached_role_policies_table};
8use super::instance_profile::{InstanceProfile, instance_profiles_for_role_table};
9
10/// One IAM role from `ListRoles`. The trust policy
11/// (`AssumeRolePolicyDocument`) is URL-encoded JSON when AWS returns
12/// it — we surface it raw; decoding is the caller's call.
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct Role {
15    #[serde(rename = "RoleName")]
16    pub role_name: String,
17    #[serde(rename = "RoleId", default)]
18    pub role_id: String,
19    #[serde(rename = "Arn", default)]
20    pub arn: String,
21    #[serde(rename = "Path", default)]
22    pub path: String,
23    #[serde(rename = "CreateDate", default)]
24    pub create_date: String,
25    #[serde(rename = "Description", default)]
26    pub description: String,
27    #[serde(rename = "AssumeRolePolicyDocument", default)]
28    pub assume_role_policy_document: String,
29    #[serde(rename = "MaxSessionDuration", default)]
30    pub max_session_duration: String,
31}
32
33/// `ListRoles` table — every IAM role in the account. Optional
34/// filter: `PathPrefix`.
35///
36/// Two relations:
37///   - `attached_policies` → `ListAttachedRolePolicies` for this role
38///   - `instance_profiles` → `ListInstanceProfilesForRole` for this role
39///
40/// ```no_run
41/// # use vantage_aws::{AwsAccount, eq};
42/// # use vantage_aws::models::iam::roles_table;
43/// # async fn run() -> vantage_core::Result<()> {
44/// # let aws = AwsAccount::from_default()?;
45/// let mut roles = roles_table(aws);
46/// roles.add_condition(eq("PathPrefix", "/service-role/"));
47/// # Ok(()) }
48/// ```
49pub fn roles_table(aws: AwsAccount) -> Table<AwsAccount, Role> {
50    Table::new("query/Roles:iam/2010-05-08.ListRoles", aws)
51        .with_id_column("RoleName")
52        .with_column_of::<String>("RoleId")
53        .with_column_of::<Arn>("Arn")
54        .with_title_column_of::<String>("Path")
55        .with_title_column_of::<AwsDateTime>("CreateDate")
56        .with_column_of::<String>("Description")
57        .with_column_of::<String>("AssumeRolePolicyDocument")
58        .with_column_of::<String>("MaxSessionDuration")
59        .with_many(
60            "attached_policies",
61            "RoleName",
62            attached_role_policies_table,
63        )
64        .with_many(
65            "instance_profiles",
66            "RoleName",
67            instance_profiles_for_role_table,
68        )
69}
70
71impl Role {
72    /// Build a [`roles_table`] narrowed to the role named in `arn`.
73    ///
74    /// Accepts ARNs of the shape
75    /// `arn:aws:iam::<account>:role/<path/>?<name>`. Returns `None` if
76    /// `arn` isn't an IAM-role ARN.
77    pub fn from_arn(arn: &str, aws: AwsAccount) -> Option<Table<AwsAccount, Role>> {
78        // Role names can sit under a path: arn:aws:iam::123:role/some/path/MyRole
79        // — strip back to the trailing component for the IAM filter.
80        let after = arn.strip_prefix("arn:aws:iam::")?.split(":role/").nth(1)?;
81        let name = after.rsplit('/').next()?;
82        if name.is_empty() {
83            return None;
84        }
85        let mut t = roles_table(aws);
86        t.add_condition(eq("RoleName", name.to_string()));
87        Some(t)
88    }
89
90    /// Attached managed policies for *this* role.
91    pub fn ref_attached_policies(&self, aws: AwsAccount) -> Table<AwsAccount, AttachedPolicy> {
92        let mut t = attached_role_policies_table(aws);
93        t.add_condition(eq("RoleName", self.role_name.clone()));
94        t
95    }
96
97    /// Instance profiles wrapping *this* role.
98    pub fn ref_instance_profiles(&self, aws: AwsAccount) -> Table<AwsAccount, InstanceProfile> {
99        let mut t = instance_profiles_for_role_table(aws);
100        t.add_condition(eq("RoleName", self.role_name.clone()));
101        t
102    }
103}