alien_bindings/providers/vault/
azure_key_vault.rs1use crate::error::{ErrorData, Result};
2use alien_azure_clients::keyvault::{AzureKeyVaultSecretsClient, KeyVaultSecretsApi};
3use alien_azure_clients::models::secrets::SecretSetParameters;
4use alien_error::{Context, ContextError};
5use async_trait::async_trait;
6use std::sync::Arc;
7
8#[derive(Debug)]
10pub struct AzureKeyVault {
11 client: Arc<AzureKeyVaultSecretsClient>,
12 vault_base_url: String,
13}
14
15impl AzureKeyVault {
16 pub fn new(client: Arc<AzureKeyVaultSecretsClient>, vault_base_url: String) -> Self {
18 Self {
19 client,
20 vault_base_url,
21 }
22 }
23
24 fn sanitize_secret_name(name: &str) -> String {
27 name.replace('_', "-")
28 }
29}
30
31#[async_trait]
32impl crate::traits::Binding for AzureKeyVault {}
33
34#[async_trait]
35impl crate::traits::Vault for AzureKeyVault {
36 async fn get_secret(&self, secret_name: &str) -> Result<String> {
38 let sanitized = Self::sanitize_secret_name(secret_name);
39 let response = self
40 .client
41 .get_secret(self.vault_base_url.clone(), sanitized, None)
42 .await
43 .context(ErrorData::CloudPlatformError {
44 message: format!(
45 "Failed to get secret '{}' from vault '{}'",
46 secret_name, self.vault_base_url
47 ),
48 resource_id: None,
49 })?;
50
51 response.value.ok_or_else(|| {
52 alien_error::AlienError::new(ErrorData::CloudPlatformError {
53 message: format!("Secret '{}' has no value", secret_name),
54 resource_id: None,
55 })
56 })
57 }
58
59 async fn set_secret(&self, secret_name: &str, value: &str) -> Result<()> {
61 let sanitized = Self::sanitize_secret_name(secret_name);
62 let parameters = SecretSetParameters {
63 value: value.to_string(),
64 content_type: None,
65 attributes: None,
66 tags: std::collections::HashMap::new(),
67 };
68
69 self.client
70 .set_secret(self.vault_base_url.clone(), sanitized, parameters)
71 .await
72 .context(ErrorData::CloudPlatformError {
73 message: format!(
74 "Failed to set secret '{}' in vault '{}'",
75 secret_name, self.vault_base_url
76 ),
77 resource_id: None,
78 })?;
79
80 Ok(())
81 }
82
83 async fn delete_secret(&self, secret_name: &str) -> Result<()> {
85 let sanitized = Self::sanitize_secret_name(secret_name);
86 match self
87 .client
88 .delete_secret(self.vault_base_url.clone(), sanitized)
89 .await
90 {
91 Ok(_) => Ok(()),
92 Err(error)
93 if matches!(
94 error.error,
95 Some(alien_client_core::ErrorData::RemoteResourceNotFound { .. })
96 ) =>
97 {
98 Ok(())
99 }
100 Err(error) => Err(error.context(ErrorData::CloudPlatformError {
101 message: format!(
102 "Failed to delete secret '{}' from vault '{}'",
103 secret_name, self.vault_base_url
104 ),
105 resource_id: None,
106 })),
107 }
108 }
109
110 async fn list_secrets(&self) -> Result<Vec<String>> {
111 Err(alien_error::AlienError::new(
115 ErrorData::OperationNotSupported {
116 operation: "vault.list_secrets".to_string(),
117 reason: "Azure Key Vault list is not exposed by the Key Vault secrets client"
118 .to_string(),
119 },
120 ))
121 }
122}