use serde::{Deserialize, Serialize};
use zeroize::Zeroize;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case", tag = "shape")]
pub enum InjectionShape {
EnvVar { name: String },
Header { name: String },
Arg { position: usize },
}
#[derive(Clone, Zeroize)]
#[zeroize(drop)]
pub struct CredentialValue(String);
impl CredentialValue {
pub fn new(value: String) -> Self {
Self(value)
}
pub fn as_str(&self) -> &str {
&self.0
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl std::fmt::Debug for CredentialValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "CredentialValue(<redacted, {} bytes>)", self.0.len())
}
}
impl From<String> for CredentialValue {
fn from(value: String) -> Self {
Self(value)
}
}
#[derive(Debug, Clone)]
pub struct InjectedCredential {
pub shape: InjectionShape,
pub value: CredentialValue,
}
impl InjectedCredential {
pub fn env(name: impl Into<String>, value: impl Into<CredentialValue>) -> Self {
Self {
shape: InjectionShape::EnvVar { name: name.into() },
value: value.into(),
}
}
pub fn header(name: impl Into<String>, value: impl Into<CredentialValue>) -> Self {
Self {
shape: InjectionShape::Header { name: name.into() },
value: value.into(),
}
}
pub fn arg(position: usize, value: impl Into<CredentialValue>) -> Self {
Self {
shape: InjectionShape::Arg { position },
value: value.into(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct CredentialMetadata {
pub tool: String,
pub key: String,
pub backend: String, pub created_at: String,
pub last_used_at: Option<String>,
pub shape: InjectionShape,
}