106 lines
4.3 KiB
Rust
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;
|