// 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, } #[derive(Clone, Copy, Eq, PartialEq)] enum SecretRevealSource { Effective, DotEnv, } impl SecretRevealSource { fn parse(value: &str) -> ksp_core_lib::Result { 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 { return reveal_from_management(state.config_management(), request); } fn reveal_from_management(management: &ksp_config_lib::ConfigManagement, request: SecretRevealRequestDto) -> ksp_core_lib::Result { 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 { 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;