v0.1.4-pre.013

This commit is contained in:
2026-08-16 16:51:11 +02:00
parent 2b343c25de
commit e0f2586400
16 changed files with 549 additions and 20 deletions

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-config-desk/src/constants.rs
// version: 5
// version: 6
//! Application-owned tracing targets and domains.
@@ -23,3 +23,5 @@ pub(crate) const TRACING_DOMAIN_DOCUMENTS: &str = "config.documents";
pub(crate) const TRACING_DOMAIN_PROFILES: &str = "config.profiles";
/// Structured domain for safe Config environment reports.
pub(crate) const TRACING_DOMAIN_ENVIRONMENT: &str = "config.environment";
/// Structured domain for explicit privileged Secret reveal operations.
pub(crate) const TRACING_DOMAIN_SECRETS: &str = "config.secrets";

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-config-desk/src/errors.rs
// version: 6
// version: 7
//! Application-local error codes for the configuration desktop shell.
@@ -32,3 +32,8 @@ pub(crate) const ERROR_CODE_TAURI_WINDOW_OPERATION_FAILED: ksp_core_lib::ErrorCo
/// A Documents command requested a registered file that is not a Config-kind document.
pub(crate) const ERROR_CODE_DOCUMENT_KIND_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("config_desk", "document_kind_invalid");
/// Privileged reveal was requested for a non-Secret KSP/KSPB namespace.
pub(crate) const ERROR_CODE_SECRET_REVEAL_REQUIRES_SECRET: ksp_core_lib::ErrorCode =
ksp_core_lib::ErrorCode::new("config_desk", "secret_reveal_requires_secret");
/// Privileged reveal requested an unsupported source selector.
pub(crate) const ERROR_CODE_SECRET_REVEAL_SOURCE_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("config_desk", "secret_reveal_source_invalid");

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-config-desk/src/lib.rs
// version: 9
// version: 10
//! Tauri desktop application for managing and validating KSP configuration.
@@ -16,6 +16,7 @@ mod environment;
mod errors;
mod frontend_logging;
mod profiles;
mod secrets;
mod splash;
mod tauri;
mod tw_main;
@@ -32,6 +33,7 @@ pub(crate) use self::constants::TRACING_DOMAIN_DOCUMENTS;
pub(crate) use self::constants::TRACING_DOMAIN_ENVIRONMENT;
pub(crate) use self::constants::TRACING_DOMAIN_FRONTEND;
pub(crate) use self::constants::TRACING_DOMAIN_PROFILES;
pub(crate) use self::constants::TRACING_DOMAIN_SECRETS;
pub(crate) use self::constants::TRACING_DOMAIN_WINDOWS;
pub(crate) use self::constants::TRACING_TARGET;
pub(crate) use self::constants::TRACING_TARGET_FRONTEND;
@@ -53,6 +55,8 @@ pub(crate) use self::errors::ERROR_CODE_FRONTEND_LOG_TARGET_INVALID;
pub(crate) use self::errors::ERROR_CODE_LOGGING_BOOTSTRAP_FAILED;
pub(crate) use self::errors::ERROR_CODE_PROFILE_CONTRACT_MISSING;
pub(crate) use self::errors::ERROR_CODE_PROFILE_PROJECTION_FAILED;
pub(crate) use self::errors::ERROR_CODE_SECRET_REVEAL_REQUIRES_SECRET;
pub(crate) use self::errors::ERROR_CODE_SECRET_REVEAL_SOURCE_INVALID;
pub(crate) use self::errors::ERROR_CODE_SPLASH_ORIGIN_INVALID;
pub(crate) use self::errors::ERROR_CODE_SPLASH_SETTING_INVALID;
pub(crate) use self::errors::ERROR_CODE_TAURI_RUNTIME_FAILED;
@@ -62,6 +66,8 @@ pub(crate) use self::frontend_logging::FrontendLogPayloadDto;
pub(crate) use self::frontend_logging::emit_frontend_log_event;
pub(crate) use self::profiles::ConfigProfileDetailDto;
pub(crate) use self::profiles::ConfigProfileDocumentDto;
pub(crate) use self::secrets::SecretRevealRequestDto;
pub(crate) use self::secrets::SecretRevealResponseDto;
pub(crate) use self::splash::SplashOrderDto;
pub(crate) use self::splash::SplashSettings;
pub(crate) use self::tw_main::show_and_focus as show_main_window;

View File

@@ -0,0 +1,105 @@
// file: crates/ksp-app-config-desk/src/secrets.rs
// version: 1
//! Privileged, explicitly requested Config Secret reveal boundary for Config Desk.
use ts_rs::TS; // rust-rules: derive-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(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;

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-config-desk/src/tauri.rs
// version: 10
// version: 11
//! Tauri runtime assembly for the KSP configuration desktop application.
@@ -47,6 +47,7 @@ fn configure_commands(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tau
get_environment_report,
set_environment_value,
remove_environment_value,
reveal_environment_value,
emit_frontend_log,
splash_frontend_ready
]);
@@ -157,6 +158,18 @@ fn remove_environment_value(
};
}
#[tauri::command]
fn reveal_environment_value(
request: crate::SecretRevealRequestDto,
state: tauri::State<'_, crate::AppState>,
) -> std::result::Result<crate::SecretRevealResponseDto, crate::CommandErrorDto> {
let result = crate::secrets::reveal(&state, request);
return match result {
std::result::Result::Ok(value) => std::result::Result::Ok(value),
std::result::Result::Err(error) => std::result::Result::Err(crate::CommandErrorDto::from_error(&error)),
};
}
#[tauri::command]
fn emit_frontend_log(payload: crate::FrontendLogPayloadDto) -> std::result::Result<(), crate::CommandErrorDto> {
let result = crate::emit_frontend_log_event(payload);