use serde::{Deserialize, Serialize};
use zeroize::Zeroizing;
use crate::domain::{
HostPattern, SecretEntry, SecretSubstitution, SecretViolationAction, SecretsConfig,
};
use crate::modify::SecretSource;
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
pub struct CloudSecretsConfig {
#[serde(default)]
pub entries: Vec<CloudSecretEntry>,
#[serde(default)]
pub violation_action: CloudViolationAction,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
pub struct CloudSecretEntry {
pub env_var: String,
#[serde(default)]
pub value: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub source: Option<CloudSecretSource>,
pub placeholder: String,
#[serde(default)]
pub allowed_hosts: Vec<CloudHostPattern>,
#[serde(default)]
pub substitution: SecretSubstitution,
#[serde(default)]
pub passthrough_hosts: Vec<CloudHostPattern>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub violation_action: Option<CloudViolationAction>,
#[serde(default = "cloud_default_true")]
pub require_tls_identity: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum CloudSecretSource {
Env {
var: String,
},
Store {
reference: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum CloudHostPattern {
Exact {
value: String,
},
Wildcard {
value: String,
},
Any,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum CloudViolationAction {
Block,
#[default]
BlockAndLog,
BlockAndTerminate,
}
fn cloud_default_true() -> bool {
true
}
impl From<HostPattern> for CloudHostPattern {
fn from(pattern: HostPattern) -> Self {
match pattern {
HostPattern::Exact(value) => Self::Exact { value },
HostPattern::Wildcard(value) => Self::Wildcard { value },
HostPattern::Any => Self::Any,
}
}
}
impl From<CloudHostPattern> for HostPattern {
fn from(pattern: CloudHostPattern) -> Self {
match pattern {
CloudHostPattern::Exact { value } => Self::Exact(value),
CloudHostPattern::Wildcard { value } => Self::Wildcard(value),
CloudHostPattern::Any => Self::Any,
}
}
}
impl From<SecretViolationAction> for CloudViolationAction {
fn from(action: SecretViolationAction) -> Self {
match action {
SecretViolationAction::Block => Self::Block,
SecretViolationAction::BlockAndLog => Self::BlockAndLog,
SecretViolationAction::BlockAndTerminate => Self::BlockAndTerminate,
}
}
}
impl From<CloudViolationAction> for SecretViolationAction {
fn from(action: CloudViolationAction) -> Self {
match action {
CloudViolationAction::Block => Self::Block,
CloudViolationAction::BlockAndLog => Self::BlockAndLog,
CloudViolationAction::BlockAndTerminate => Self::BlockAndTerminate,
}
}
}
impl From<SecretSource> for CloudSecretSource {
fn from(source: SecretSource) -> Self {
match source {
SecretSource::Env { var } => Self::Env { var },
SecretSource::Store { reference } => Self::Store { reference },
}
}
}
impl From<CloudSecretSource> for SecretSource {
fn from(source: CloudSecretSource) -> Self {
match source {
CloudSecretSource::Env { var } => Self::Env { var },
CloudSecretSource::Store { reference } => Self::Store { reference },
}
}
}
impl From<SecretEntry> for CloudSecretEntry {
fn from(entry: SecretEntry) -> Self {
Self {
env_var: entry.env_var,
value: entry.value.to_string(),
source: entry.source.map(Into::into),
placeholder: entry.placeholder,
allowed_hosts: entry.allowed_hosts.into_iter().map(Into::into).collect(),
substitution: entry.substitution,
passthrough_hosts: entry
.passthrough_hosts
.into_iter()
.map(Into::into)
.collect(),
violation_action: entry.violation_action.map(Into::into),
require_tls_identity: entry.require_tls_identity,
}
}
}
impl From<CloudSecretEntry> for SecretEntry {
fn from(entry: CloudSecretEntry) -> Self {
Self {
env_var: entry.env_var,
value: Zeroizing::new(entry.value),
source: entry.source.map(Into::into),
placeholder: entry.placeholder,
allowed_hosts: entry.allowed_hosts.into_iter().map(Into::into).collect(),
substitution: entry.substitution,
passthrough_hosts: entry
.passthrough_hosts
.into_iter()
.map(Into::into)
.collect(),
violation_action: entry.violation_action.map(Into::into),
require_tls_identity: entry.require_tls_identity,
}
}
}
impl From<SecretsConfig> for CloudSecretsConfig {
fn from(config: SecretsConfig) -> Self {
Self {
entries: config.secrets.into_iter().map(Into::into).collect(),
violation_action: config.violation_action.into(),
}
}
}
impl From<CloudSecretsConfig> for SecretsConfig {
fn from(config: CloudSecretsConfig) -> Self {
Self {
secrets: config.entries.into_iter().map(Into::into).collect(),
violation_action: config.violation_action.into(),
}
}
}