use async_trait::async_trait;
use aws_sdk_secretsmanager::Client;
use super::types::map_aws_error;
use crate::common::{Error, Result};
#[cfg_attr(test, mockall::automock)]
#[async_trait]
pub trait AwsSmOps: Send + Sync {
fn display_name(&self) -> String;
fn debug_info(&self) -> String;
async fn get(&self, name: &str) -> Result<String>;
async fn create(&self, name: &str, value: &str) -> Result<()>;
async fn put(&self, name: &str, value: &str) -> Result<()>;
async fn delete(&self, name: &str) -> Result<()>;
async fn list(&self, prefix: Option<String>) -> Result<Vec<String>>;
}
pub(super) struct AwsSdkClient {
pub client: Client,
}
#[async_trait]
impl AwsSmOps for AwsSdkClient {
fn display_name(&self) -> String {
let region = self
.client
.config()
.region()
.map(|r| r.as_ref().to_owned())
.unwrap_or_else(|| "unknown".to_owned());
format!("AwsSecretsManager(region={})", region)
}
fn debug_info(&self) -> String {
let cfg = self.client.config();
let region = cfg.region().map(|r| r.as_ref()).unwrap_or("unknown");
format!("region={region}, provider=AwsSecretsManager")
}
async fn get(&self, name: &str) -> Result<String> {
self.client
.get_secret_value()
.secret_id(name)
.send()
.await
.map_err(|e| map_aws_error(name, e.into_service_error()))
.map(|r| r.secret_string().unwrap_or_default().to_owned())
}
async fn create(&self, name: &str, value: &str) -> Result<()> {
self.client
.create_secret()
.name(name)
.secret_string(value)
.send()
.await
.map(|_| ())
.map_err(|e| map_aws_error(name, e.into_service_error()))
}
async fn put(&self, name: &str, value: &str) -> Result<()> {
self.client
.put_secret_value()
.secret_id(name)
.secret_string(value)
.send()
.await
.map(|_| ())
.map_err(|e| map_aws_error(name, e.into_service_error()))
}
async fn delete(&self, name: &str) -> Result<()> {
self.client
.delete_secret()
.secret_id(name)
.send()
.await
.map(|_| ())
.map_err(|e| map_aws_error(name, e.into_service_error()))
}
async fn list(&self, prefix: Option<String>) -> Result<Vec<String>> {
let mut names = Vec::new();
let mut paginator = self.client.list_secrets().into_paginator().send();
while let Some(page) = paginator.next().await {
let page = page.map_err(|e| Error::Generic {
store: "AwsSecretsManager",
source: Box::new(e.into_service_error()),
})?;
for entry in page.secret_list() {
if let Some(n) = entry.name() {
if prefix.as_deref().is_none_or(|p| n.starts_with(p)) {
names.push(n.to_owned());
}
}
}
}
Ok(names)
}
}