Files
khadhroony-solana-project/crates/ksp-app-config-desk/src/secrets.rs

106 lines
4.3 KiB
Rust

// file: crates/ksp-app-config-desk/src/secrets.rs
// version: 2
//! Privileged, explicitly requested Config Secret reveal boundary for Config Desk.
use ts_rs::TS; // rust-rules: trait-import
/// Privileged reveal request kept separate from ordinary environment-report DTOs.
#[derive(serde::Deserialize, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_config_desk/secrets/SecretRevealRequestDto.ts")]
pub(crate) struct SecretRevealRequestDto {
/// Secret KSP/KSPB variable to reveal.
pub(crate) variable_name: String,
/// Requested source: `effective` or `dotenv`.
pub(crate) source: String,
}
/// Privileged reveal response. This type deliberately does not derive `Clone` or `Debug`.
#[derive(serde::Serialize, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_config_desk/secrets/SecretRevealResponseDto.ts")]
pub(crate) struct SecretRevealResponseDto {
/// Secret variable that was explicitly requested.
pub(crate) variable_name: String,
/// Source that was explicitly requested.
pub(crate) source: String,
/// Real value when the requested source contains one; never include this field in logs or ordinary application state.
pub(crate) value: std::option::Option<String>,
}
#[derive(Clone, Copy, Eq, PartialEq)]
enum SecretRevealSource {
Effective,
DotEnv,
}
impl SecretRevealSource {
fn parse(value: &str) -> ksp_core_lib::Result<Self> {
return match value {
"effective" => std::result::Result::Ok(Self::Effective),
"dotenv" => std::result::Result::Ok(Self::DotEnv),
_ => std::result::Result::Err(ksp_core_lib::Error::new(
crate::ERROR_CODE_SECRET_REVEAL_SOURCE_INVALID,
"Secret reveal source must be effective or dotenv",
)),
};
}
const fn label(self) -> &'static str {
return match self {
Self::Effective => "effective",
Self::DotEnv => "dotenv",
};
}
}
/// Reveals one real Secret value only after the dedicated Tauri command has been explicitly invoked.
pub(crate) fn reveal_secret(state: &crate::AppState, request: SecretRevealRequestDto) -> ksp_core_lib::Result<SecretRevealResponseDto> {
return reveal_from_management(state.config_management(), request);
}
fn reveal_from_management(management: &ksp_config_lib::ConfigManagement, request: SecretRevealRequestDto) -> ksp_core_lib::Result<SecretRevealResponseDto> {
let source = validate_request(request.variable_name.as_str(), request.source.as_str());
let source = match source {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let value = match source {
SecretRevealSource::Effective => management.reveal_effective_environment_value(request.variable_name.as_str()),
SecretRevealSource::DotEnv => management.reveal_dotenv_value(request.variable_name.as_str()),
};
let value = match value {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
ksp_logging_lib::debug!(
target: crate::TRACING_TARGET,
domain = crate::TRACING_DOMAIN_SECRETS,
variable_name = request.variable_name.as_str(),
source = source.label(),
value_present = value.is_some(),
"privileged Config Secret reveal completed"
);
return std::result::Result::Ok(SecretRevealResponseDto { variable_name: request.variable_name, source: source.label().to_owned(), value });
}
fn validate_request(variable_name: &str, source: &str) -> ksp_core_lib::Result<SecretRevealSource> {
let sensitivity = ksp_config_lib::ConfigSensitivity::from_variable_name(variable_name);
let sensitivity = match sensitivity {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
if sensitivity != ksp_config_lib::ConfigSensitivity::Secret {
return std::result::Result::Err(ksp_core_lib::Error::new(
crate::ERROR_CODE_SECRET_REVEAL_REQUIRES_SECRET,
"Privileged reveal is restricted to KSP/KSPB Secret namespaces",
));
}
return SecretRevealSource::parse(source);
}
#[cfg(test)]
#[path = "../unit_tests/secrets.rs"]
mod tests;