use bon::Builder;
use google_cloud_secretmanager_v1::client::SecretManagerService;
use huskarl_core::secrets::{DecodingError, Secret, SecretDecoder, SecretOutput};
use snafu::prelude::*;
pub use versions::ActiveSecretVersions;
pub use versions::SecretVersions;
pub use versions::SecretVersionsError;
mod versions;
#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum SecretError {
AccessSecret {
source: google_cloud_secretmanager_v1::Error,
},
MissingPayload,
Decode {
source: DecodingError,
},
}
impl huskarl_core::Error for SecretError {
fn is_retryable(&self) -> bool {
match self {
Self::AccessSecret { source } => source.is_exhausted() || source.is_timeout(),
Self::MissingPayload | Self::Decode { .. } => false,
}
}
}
#[derive(Debug, Clone, Builder)]
pub struct SecretVersion<D: SecretDecoder> {
decoder: D,
client: SecretManagerService,
#[builder(into)]
resource_name: String,
}
impl<D: SecretDecoder> Secret for SecretVersion<D> {
type Error = SecretError;
type Output = D::Output;
async fn get_secret_value(&self) -> Result<SecretOutput<Self::Output>, Self::Error> {
let response = self
.client
.access_secret_version()
.set_name(&self.resource_name)
.send()
.await
.context(AccessSecretSnafu)?;
let payload = response.payload.context(MissingPayloadSnafu)?;
let secret_value = self.decoder.decode(&payload.data).context(DecodeSnafu)?;
Ok(SecretOutput {
value: secret_value,
identity: response.name.rsplit('/').next().map(String::from),
})
}
}