use adk_core::{AdkError, ErrorCategory, ErrorComponent};
use async_trait::async_trait;
use aws_sdk_secretsmanager::Client;
use super::provider::SecretProvider;
pub struct AwsSecretProvider {
client: Client,
}
impl AwsSecretProvider {
pub async fn new() -> Self {
let config = aws_config::load_defaults(aws_config::BehaviorVersion::latest()).await;
Self { client: Client::new(&config) }
}
pub fn from_client(client: Client) -> Self {
Self { client }
}
}
fn map_aws_error(err: aws_sdk_secretsmanager::error::SdkError<impl std::fmt::Debug>) -> AdkError {
use aws_sdk_secretsmanager::error::SdkError;
match &err {
SdkError::ServiceError(service_err) => {
let raw = service_err.raw();
let status = raw.status().as_u16();
match status {
401 | 403 => AdkError::new(
ErrorComponent::Auth,
ErrorCategory::Unauthorized,
"auth.aws_secrets.unauthorized",
format!("AWS Secrets Manager authentication failed: {err}"),
)
.with_provider("aws-secrets-manager")
.with_upstream_status(status),
404 => AdkError::new(
ErrorComponent::Auth,
ErrorCategory::NotFound,
"auth.aws_secrets.not_found",
format!("AWS secret not found: {err}"),
)
.with_provider("aws-secrets-manager")
.with_upstream_status(status),
_ => AdkError::new(
ErrorComponent::Auth,
ErrorCategory::Internal,
"auth.aws_secrets.service_error",
format!("AWS Secrets Manager service error: {err}"),
)
.with_provider("aws-secrets-manager")
.with_upstream_status(status),
}
}
SdkError::TimeoutError(_) => AdkError::new(
ErrorComponent::Auth,
ErrorCategory::Unavailable,
"auth.aws_secrets.timeout",
format!("AWS Secrets Manager request timed out: {err}"),
)
.with_provider("aws-secrets-manager"),
SdkError::DispatchFailure(_) => AdkError::new(
ErrorComponent::Auth,
ErrorCategory::Unavailable,
"auth.aws_secrets.network",
format!("AWS Secrets Manager network error: {err}"),
)
.with_provider("aws-secrets-manager"),
_ => AdkError::new(
ErrorComponent::Auth,
ErrorCategory::Internal,
"auth.aws_secrets.unknown",
format!("AWS Secrets Manager error: {err}"),
)
.with_provider("aws-secrets-manager"),
}
}
#[async_trait]
impl SecretProvider for AwsSecretProvider {
async fn get_secret(&self, name: &str) -> Result<String, AdkError> {
let response =
self.client.get_secret_value().secret_id(name).send().await.map_err(map_aws_error)?;
response.secret_string().map(|s| s.to_string()).ok_or_else(|| {
AdkError::new(
ErrorComponent::Auth,
ErrorCategory::Internal,
"auth.aws_secrets.no_string_value",
format!("AWS secret '{name}' exists but has no string value (it may be binary)"),
)
.with_provider("aws-secrets-manager")
})
}
}