use super::{ArnTransformer, ProviderArnInfo};
use crate::arn::types::{Service, WamiArn};
use crate::error::{AmiError, Result};
pub struct GcpArnTransformer;
impl ArnTransformer for GcpArnTransformer {
fn to_provider_arn(&self, arn: &WamiArn) -> Result<String> {
let cloud_mapping =
arn.cloud_mapping
.as_ref()
.ok_or_else(|| AmiError::InvalidParameter {
message: "ARN is not cloud-synced".to_string(),
})?;
if cloud_mapping.provider != "gcp" {
return Err(AmiError::InvalidParameter {
message: format!(
"ARN provider is '{}', expected 'gcp'",
cloud_mapping.provider
),
});
}
let gcp_service = match &arn.service {
Service::Iam => "iam.googleapis.com",
Service::SsoAdmin => "cloudidentity.googleapis.com",
Service::Custom(s) => s.as_str(),
_ => "iam.googleapis.com", };
let base = format!(
"//{}/projects/{}/{}s/{}",
gcp_service,
cloud_mapping.account_id,
arn.resource.resource_type,
arn.resource.resource_id
);
Ok(base)
}
fn from_provider_arn(&self, provider_arn: &str) -> Result<ProviderArnInfo> {
if !provider_arn.starts_with("//") {
return Err(AmiError::InvalidParameter {
message: "Invalid GCP resource name: expected '//' prefix".to_string(),
});
}
let parts: Vec<&str> = provider_arn[2..].split('/').collect();
if parts.len() < 4 {
return Err(AmiError::InvalidParameter {
message: format!(
"Invalid GCP resource name format: expected at least 4 parts, got {}",
parts.len()
),
});
}
let service = parts[0].to_string();
if parts[1] != "projects" {
return Err(AmiError::InvalidParameter {
message: format!(
"Invalid GCP resource name: expected 'projects', got '{}'",
parts[1]
),
});
}
let account_id = parts[2].to_string();
let mut resource_type = parts[3].to_string();
if resource_type.ends_with('s') {
resource_type.pop();
}
let resource_id = parts[4..].join("/");
Ok(ProviderArnInfo {
provider: "gcp".to_string(),
account_id,
service,
resource_type,
resource_id,
region: None, })
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::arn::{Service, WamiArn};
#[test]
fn test_gcp_transformer() {
let arn = WamiArn::builder()
.service(Service::Iam)
.tenant(12345678)
.wami_instance("999888777")
.cloud_provider("gcp", "554433221")
.resource("serviceAccount", "77557755")
.build()
.unwrap();
let transformer = GcpArnTransformer;
let gcp_arn = transformer.to_provider_arn(&arn).unwrap();
assert_eq!(
gcp_arn,
"//iam.googleapis.com/projects/554433221/serviceAccounts/77557755"
);
}
#[test]
fn test_gcp_transformer_error_cases() {
let transformer = GcpArnTransformer;
let arn = WamiArn::builder()
.service(Service::Iam)
.tenant(12345678)
.wami_instance("999888777")
.resource("user", "alice")
.build()
.unwrap();
let result = transformer.to_provider_arn(&arn);
assert!(result.is_err());
let arn = WamiArn::builder()
.service(Service::Iam)
.tenant(12345678)
.wami_instance("999888777")
.cloud_provider("aws", "123456")
.resource("user", "alice")
.build()
.unwrap();
let result = transformer.to_provider_arn(&arn);
assert!(result.is_err());
}
}