seamless-glance 1.0.0

Fast, read-only AWS TUI for cloud infrastructure visibility and triage
use crate::aws::clients::AwsClients;
use crate::models::describable::{shell_quote, DescribableResource};
use anyhow::Result;
use async_trait::async_trait;

#[derive(Debug, Clone)]
pub struct SecurityGroupInfo {
    pub id: String,
    pub name: String,
    pub vpc_id: String,
    pub inbound_rules: usize,
    pub outbound_rules: usize,
    pub open_to_world: bool,
    pub sensitive_public_ports: Vec<i32>,
}

impl SecurityGroupInfo {
    pub fn sensitive_ports_label(&self) -> String {
        if self.sensitive_public_ports.is_empty() {
            "-".into()
        } else {
            self.sensitive_public_ports
                .iter()
                .map(|port| port.to_string())
                .collect::<Vec<_>>()
                .join(",")
        }
    }
}

#[async_trait]
impl DescribableResource for SecurityGroupInfo {
    fn resource_name(&self) -> String {
        format!("{} ({})", self.name, self.id)
    }

    async fn describe(&self, clients: &AwsClients) -> Result<String> {
        let resp = clients
            .ec2
            .describe_security_groups()
            .group_ids(&self.id)
            .send()
            .await?;

        Ok(format!("{:#?}", resp))
    }

    fn console_url(&self, region: &str) -> Option<String> {
        Some(format!(
            "https://console.aws.amazon.com/ec2/v2/home?region={region}#SecurityGroup:groupId={}",
            self.id
        ))
    }

    fn cli_command(&self, region: &str) -> Option<String> {
        Some(format!(
            "aws ec2 describe-security-groups --group-ids {} --region {}",
            shell_quote(&self.id),
            shell_quote(region)
        ))
    }
}