v0.3.7-pre.004

This commit is contained in:
2026-09-02 11:00:20 +02:00
parent 03a94f4fb6
commit 46a4ad7487
17 changed files with 630 additions and 60 deletions

View File

@@ -1,5 +1,5 @@
# file: crates/ksp-app-backfill-desk/Cargo.toml
# version: 1
# version: 2
[package]
name = "ksp-app-backfill-desk"
@@ -27,6 +27,7 @@ fs2.workspace = true
ksp-config-lib = { path = "../ksp-config-lib" }
ksp-core-lib = { path = "../ksp-core-lib" }
ksp-logging-lib = { path = "../ksp-logging-lib" }
ksp-onchain-transport-lib = { path = "../ksp-onchain-transport-lib" }
serde = { workspace = true, features = ["derive"] }
tauri.workspace = true
tauri-plugin-tracing.workspace = true

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-backfill-desk/src/app_state.rs
// version: 1
// version: 2
//! Shared backend state owned by the Backfill Desk Tauri application.
@@ -9,6 +9,8 @@ pub(crate) struct AppState {
logging_runtime: std::sync::Mutex<LoggingRuntimeState>,
splash_settings: crate::SplashSettings,
splash_sequence_started: std::sync::atomic::AtomicBool,
transport_runtime: std::option::Option<crate::TransportRuntime>,
transport_startup_diagnostic: std::option::Option<crate::CommandErrorDto>,
}
impl crate::AppState {
@@ -29,6 +31,21 @@ impl crate::AppState {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let transport_startup = crate::initialize_transport(&config_management);
let (transport_runtime, transport_startup_diagnostic) = match transport_startup {
std::result::Result::Ok(value) => (std::option::Option::Some(value), std::option::Option::None),
std::result::Result::Err(error) => {
let diagnostic = crate::CommandErrorDto::from_error(&error);
ksp_logging_lib::warn!(
target: crate::TRACING_TARGET,
domain = crate::TRACING_DOMAIN_TRANSPORT,
error_domain = diagnostic.domain.as_str(),
error_code = diagnostic.code.as_str(),
"Backfill Desk Transport readiness is unavailable; keeping desktop shell available"
);
(std::option::Option::None, std::option::Option::Some(diagnostic))
},
};
let splash_settings = crate::SplashSettings::load();
let splash_settings = match splash_settings {
std::result::Result::Ok(value) => value,
@@ -65,6 +82,8 @@ impl crate::AppState {
}),
splash_settings,
splash_sequence_started: std::sync::atomic::AtomicBool::new(false),
transport_runtime,
transport_startup_diagnostic,
});
}
@@ -97,11 +116,25 @@ impl crate::AppState {
application_version: env!("CARGO_PKG_VERSION").to_owned(),
config_document_count: document_count,
fallback_logging_active: runtime.fallback_active,
shell_phase: "pre.002-desktop-scaffold".to_owned(),
shell_phase: "pre.004-transport-readiness".to_owned(),
startup_diagnostic: runtime.startup_diagnostic.clone(),
});
}
/// Builds the safe Transport-readiness subset of Backfill Desk options.
pub(crate) fn backfill_options(&self) -> ksp_core_lib::Result<crate::BackfillDeskOptionsDto> {
let runtime = self.transport_runtime.as_ref();
return match runtime {
std::option::Option::Some(value) => value.options(),
std::option::Option::None => std::result::Result::Ok(crate::BackfillDeskOptionsDto {
compatible_roles: std::vec::Vec::new(),
configured_networks: std::vec::Vec::new(),
transport_diagnostic: self.transport_startup_diagnostic.clone(),
transport_ready: false,
}),
};
}
/// Returns the resolved splash timings captured during application bootstrap.
#[must_use]
pub(crate) const fn splash_settings(&self) -> crate::SplashSettings {

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-backfill-desk/src/constants.rs
// version: 2
// version: 3
//! Application-owned tracing targets and domains.
@@ -15,6 +15,8 @@ pub(crate) const TRACING_DOMAIN_BOOTSTRAP: &str = "backfill.bootstrap";
pub(crate) const TRACING_DOMAIN_FRONTEND: &str = "frontend";
/// Structured domain used by the Backfill Desk shell.
pub(crate) const TRACING_DOMAIN_SHELL: &str = "backfill.shell";
/// Structured domain used by Transport readiness and role inventory operations.
pub(crate) const TRACING_DOMAIN_TRANSPORT: &str = "backfill.transport";
/// Structured domain used by Tauri window lifecycle operations.
pub(crate) const TRACING_DOMAIN_WINDOWS: &str = "desktop.window";
/// Owning target for backend events emitted by Backfill Desk.

View File

@@ -1,10 +1,28 @@
// file: crates/ksp-app-backfill-desk/src/dto_common.rs
// version: 1
// version: 2
//! Common Tauri DTOs shared by the Backfill Desk shell.
use ts_rs::TS; // rust-rules: trait-import
/// Safe Transport-readiness subset of the Backfill Desk options contract.
///
/// Campaign scopes, commitments and backend-owned bounds are added in the dedicated request/DTO slice. Endpoint URLs, provider identities and credentials
/// are intentionally absent.
#[derive(Clone, Debug, serde::Serialize, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_backfill_desk/dto_common/BackfillDeskOptionsDto.ts")]
pub(crate) struct BackfillDeskOptionsDto {
/// Logical roles that can route both RPC methods required by the Backfill runtime.
pub(crate) compatible_roles: std::vec::Vec<String>,
/// Distinct enabled HTTP cluster labels selected by the active Transport profile.
pub(crate) configured_networks: std::vec::Vec<String>,
/// Safe startup diagnostic when Transport configuration could not be resolved or constructed.
pub(crate) transport_diagnostic: std::option::Option<CommandErrorDto>,
/// Whether Transport currently has one coherent network and at least one compatible available role.
pub(crate) transport_ready: bool,
}
/// Safe command error projection that never serializes arbitrary KSP error context or source values.
#[derive(Clone, Debug, serde::Serialize, TS)]
#[serde(rename_all = "camelCase")]

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-backfill-desk/src/errors.rs
// version: 3
// version: 4
//! Application-local error codes for Backfill Desk composition and desktop runtime surfaces.
@@ -8,17 +8,13 @@ pub(crate) const ERROR_CODE_APP_STATE_INVALID: ksp_core_lib::ErrorCode = ksp_cor
/// Shared Backfill Desk runtime state cannot be locked safely.
pub(crate) const ERROR_CODE_APP_STATE_LOCK_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("backfill_desk", "app_state_lock_failed");
/// Backfill Desk composite configuration is missing or references an unexpected document.
pub(crate) const ERROR_CODE_CONFIG_COMPOSITE_INVALID: ksp_core_lib::ErrorCode =
ksp_core_lib::ErrorCode::new("backfill_desk", "config_composite_invalid");
pub(crate) const ERROR_CODE_CONFIG_COMPOSITE_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("backfill_desk", "config_composite_invalid");
/// Frontend logging requested an unsupported level.
pub(crate) const ERROR_CODE_FRONTEND_LOG_LEVEL_INVALID: ksp_core_lib::ErrorCode =
ksp_core_lib::ErrorCode::new("backfill_desk", "frontend_log_level_invalid");
pub(crate) const ERROR_CODE_FRONTEND_LOG_LEVEL_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("backfill_desk", "frontend_log_level_invalid");
/// Frontend logging requested a target outside the application whitelist.
pub(crate) const ERROR_CODE_FRONTEND_LOG_TARGET_INVALID: ksp_core_lib::ErrorCode =
ksp_core_lib::ErrorCode::new("backfill_desk", "frontend_log_target_invalid");
pub(crate) const ERROR_CODE_FRONTEND_LOG_TARGET_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("backfill_desk", "frontend_log_target_invalid");
/// Backfill Desk could not install the managed Logging runtime or its safe fallback.
pub(crate) const ERROR_CODE_LOGGING_BOOTSTRAP_FAILED: ksp_core_lib::ErrorCode =
ksp_core_lib::ErrorCode::new("backfill_desk", "logging_bootstrap_failed");
pub(crate) const ERROR_CODE_LOGGING_BOOTSTRAP_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("backfill_desk", "logging_bootstrap_failed");
/// Splash readiness was invoked from a window other than the splash window.
pub(crate) const ERROR_CODE_SPLASH_ORIGIN_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("backfill_desk", "splash_origin_invalid");
/// A KSP desk splash environment duration is malformed or exceeds its safety bound.
@@ -30,3 +26,5 @@ pub(crate) const ERROR_CODE_TAURI_WINDOW_MISSING: ksp_core_lib::ErrorCode = ksp_
/// A Tauri window show/focus/destroy/event operation failed.
pub(crate) const ERROR_CODE_TAURI_WINDOW_OPERATION_FAILED: ksp_core_lib::ErrorCode =
ksp_core_lib::ErrorCode::new("backfill_desk", "tauri_window_operation_failed");
/// Backfill Desk cannot derive a safe Transport readiness contract from the Transport registry.
pub(crate) const ERROR_CODE_TRANSPORT_READINESS_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("backfill_desk", "transport_readiness_invalid");

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-backfill-desk/src/lib.rs
// version: 2
// version: 3
//! Tauri desktop application scaffold for controlling and inspecting KSP RAW backfill jobs.
@@ -16,6 +16,7 @@ mod frontend_logging;
mod logging_runtime;
mod splash;
mod tauri;
mod transport_runtime;
mod tw_main;
mod tw_splash;
@@ -46,6 +47,8 @@ pub(crate) use self::constants::TRACING_DOMAIN_BOOTSTRAP;
pub(crate) use self::constants::TRACING_DOMAIN_FRONTEND;
/// Structured domain used by the Backfill Desk shell.
pub(crate) use self::constants::TRACING_DOMAIN_SHELL;
/// Structured domain used by Transport readiness and role inventory operations.
pub(crate) use self::constants::TRACING_DOMAIN_TRANSPORT;
/// Structured domain used by Tauri window lifecycle operations.
pub(crate) use self::constants::TRACING_DOMAIN_WINDOWS;
/// Owning target for backend events emitted by Backfill Desk.
@@ -56,6 +59,8 @@ pub(crate) use self::constants::TRACING_TARGET_FRONTEND;
pub(crate) use self::constants::TRACING_TARGET_FRONTEND_MAIN;
/// Owning target for splash-window frontend events.
pub(crate) use self::constants::TRACING_TARGET_FRONTEND_SPLASH;
/// Safe Transport-readiness subset of the Backfill Desk options contract.
pub(crate) use self::dto_common::BackfillDeskOptionsDto;
/// Safe command error projection exposed to Tauri commands.
pub(crate) use self::dto_common::CommandErrorDto;
/// Safe scaffold/runtime snapshot exposed to the shell.
@@ -82,6 +87,8 @@ pub(crate) use self::errors::ERROR_CODE_TAURI_RUNTIME_FAILED;
pub(crate) use self::errors::ERROR_CODE_TAURI_WINDOW_MISSING;
/// A Tauri window show/focus/destroy/event operation failed.
pub(crate) use self::errors::ERROR_CODE_TAURI_WINDOW_OPERATION_FAILED;
/// Backfill Desk cannot derive a safe Transport readiness contract.
pub(crate) use self::errors::ERROR_CODE_TRANSPORT_READINESS_INVALID;
/// Log payload sent by Backfill Desk frontend scripts.
pub(crate) use self::frontend_logging::FrontendLogPayloadDto;
/// Emits one validated frontend event through the KSP Logging facade.
@@ -92,6 +99,10 @@ pub(crate) use self::logging_runtime::launch_identity;
pub(crate) use self::splash::SplashOrderDto;
/// Runtime timings used by the common desk splash lifecycle.
pub(crate) use self::splash::SplashSettings;
/// Safe and executable Transport runtime retained by application state.
pub(crate) use self::transport_runtime::TransportRuntime;
/// Initializes the composite-selected HTTP Transport runtime.
pub(crate) use self::transport_runtime::initialize_transport;
/// Resolves the required main window or returns a typed error.
pub(crate) use self::tw_main::require_main_window;
/// Shows and focuses the main Backfill Desk window.

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-backfill-desk/src/tauri.rs
// version: 2
// version: 3
//! Tauri runtime assembly for the KSP Backfill desktop application.
@@ -72,7 +72,7 @@ fn configure_plugins(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<taur
#[allow(clippy::question_mark_used)] // Tauri generates the question-mark operator internally for async command dispatch.
fn configure_commands(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
return builder.invoke_handler(tauri::generate_handler![emit_frontend_log, get_runtime_status, splash_frontend_ready]);
return builder.invoke_handler(tauri::generate_handler![backfill_options, emit_frontend_log, get_runtime_status, splash_frontend_ready]);
}
fn configure_setup(builder: tauri::Builder<tauri::Wry>) -> tauri::Builder<tauri::Wry> {
@@ -102,6 +102,15 @@ fn project_command_error(command: &'static str, domain: &'static str, error: &ks
return crate::CommandErrorDto::from_error(error);
}
#[tauri::command]
fn backfill_options(state: tauri::State<'_, crate::AppState>) -> std::result::Result<crate::BackfillDeskOptionsDto, crate::CommandErrorDto> {
let result = state.backfill_options();
return match result {
std::result::Result::Ok(value) => std::result::Result::Ok(value),
std::result::Result::Err(error) => std::result::Result::Err(project_command_error("backfill_options", crate::TRACING_DOMAIN_TRANSPORT, &error)),
};
}
#[tauri::command]
fn emit_frontend_log(payload: crate::FrontendLogPayloadDto) -> std::result::Result<(), crate::CommandErrorDto> {
let result = crate::emit_frontend_log_event(payload);

View File

@@ -0,0 +1,148 @@
// file: crates/ksp-app-backfill-desk/src/transport_runtime.rs
// version: 1
//! Composite-selected HTTP Transport readiness owned by Backfill Desk.
/// Safe and executable Transport runtime retained by the application state.
pub(crate) struct TransportRuntime {
pool: ksp_onchain_transport_lib::HttpTransportPool,
profile_id: String,
}
impl TransportRuntime {
/// Returns the composite-selected Transport profile identifier.
#[must_use]
pub(crate) fn profile_id(&self) -> &str {
return self.profile_id.as_str();
}
/// Builds the current safe Transport-only projection for the Backfill options surface.
pub(crate) fn options(&self) -> ksp_core_lib::Result<crate::BackfillDeskOptionsDto> {
let snapshot = self.pool.snapshot();
let configured_networks = configured_networks(&snapshot);
let compatible_roles = compatible_backfill_roles(&self.pool, &snapshot);
let compatible_roles = match compatible_roles {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let transport_ready = configured_networks.len() == 1 && !compatible_roles.is_empty() && snapshot.available_endpoint_count() > 0;
return std::result::Result::Ok(crate::BackfillDeskOptionsDto {
compatible_roles,
configured_networks,
transport_diagnostic: std::option::Option::None,
transport_ready,
});
}
}
/// Resolves the composite-selected Transport profile and builds the executable HTTP pool.
pub(crate) fn initialize_transport(management: &ksp_config_lib::ConfigManagement) -> ksp_core_lib::Result<TransportRuntime> {
let environment = ksp_config_lib::ConfigEnvironment::load();
let environment = match environment {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let composite = crate::load_backfill_desk_composite(management);
let composite = match composite {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let profile = crate::required_composite_component_profile(&composite, crate::COMPOSITE_COMPONENT_ID_TRANSPORT, ksp_config_lib::FILE_ID_STD_TRANSPORT);
let profile = match profile {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let resolved = management.engine().resolve_transport_config_profile(&profile, &environment);
let resolved = match resolved {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let profile_id = resolved.profile_id().to_owned();
let pool = ksp_onchain_transport_lib::HttpTransportPool::new(resolved.into_settings());
let pool = match pool {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let runtime = TransportRuntime { pool, profile_id };
let options = runtime.options();
let options = match options {
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_TRANSPORT,
transport_profile = runtime.profile_id(),
network_count = options.configured_networks.len(),
compatible_role_count = options.compatible_roles.len(),
transport_ready = options.transport_ready,
"initialized Backfill Desk HTTP Transport readiness from composite-managed configuration"
);
return std::result::Result::Ok(runtime);
}
fn compatible_backfill_roles(
pool: &ksp_onchain_transport_lib::HttpTransportPool,
snapshot: &ksp_onchain_transport_lib::HttpTransportPoolSnapshot,
) -> ksp_core_lib::Result<std::vec::Vec<String>> {
let signatures = required_http_rpc_method("getSignaturesForAddress");
let signatures = match signatures {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let transaction = required_http_rpc_method("getTransaction");
let transaction = match transaction {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let mut candidates = std::collections::BTreeSet::new();
for endpoint in snapshot.endpoints() {
if !endpoint.enabled() {
continue;
}
for role in endpoint.roles() {
if role.enabled() {
candidates.insert(role.role().to_owned());
}
}
}
let mut compatible = std::vec::Vec::new();
for candidate in candidates {
let role = ksp_onchain_transport_lib::HttpRoleName::new(candidate.clone());
if pool.select_for_method(&role, signatures).is_ok() && pool.select_for_method(&role, transaction).is_ok() {
compatible.push(candidate);
}
}
return std::result::Result::Ok(compatible);
}
fn configured_networks(snapshot: &ksp_onchain_transport_lib::HttpTransportPoolSnapshot) -> std::vec::Vec<String> {
let mut values = snapshot
.endpoints()
.iter()
.filter_map(|endpoint| {
if endpoint.enabled() {
return std::option::Option::Some(endpoint.cluster().to_owned());
}
return std::option::Option::None;
})
.collect::<std::vec::Vec<_>>();
values.sort();
values.dedup();
return values;
}
fn required_http_rpc_method(method: &'static str) -> ksp_core_lib::Result<&'static ksp_onchain_transport_lib::HttpRpcMethodDescriptor> {
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method);
return match descriptor {
std::option::Option::Some(value) => std::result::Result::Ok(value),
std::option::Option::None => std::result::Result::Err(
ksp_core_lib::Error::new(crate::ERROR_CODE_TRANSPORT_READINESS_INVALID, "Backfill Desk Transport registry is missing a required HTTP RPC method")
.with_context("rpc_method", method),
),
};
}
#[cfg(test)]
#[path = "../unit_tests/transport_runtime.rs"]
mod tests;

View File

@@ -1,7 +1,7 @@
// file: crates/ksp-app-backfill-desk/tests/config_composition.rs
// version: 1
// version: 2
//! Config composite contracts for Backfill Desk pre.003.
//! Config composite and Transport-readiness contracts for Backfill Desk through pre.004.
#![forbid(unsafe_code)]
#![deny(unreachable_pub)]
@@ -86,3 +86,73 @@ fn pre_003_named_profiles_keep_transport_and_store_network_selection_paired() {
}
}
}
#[test]
fn pre_004_default_composite_builds_http_pool_for_both_backfill_rpc_methods() {
let engine = workspace_engine();
assert!(engine.is_ok(), "workspace Config engine should be constructible: {engine:?}");
let engine = match engine {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let file_id = ksp_config_lib::ConfigFileId::new(ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_BACKFILL_DESK);
let file_id = match file_id {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let composite = engine.load_resolved_composite(&file_id, std::option::Option::None);
assert!(composite.is_ok(), "committed Backfill Desk composite should resolve: {composite:?}");
let composite = match composite {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let transport = composite.component("transport");
assert!(transport.is_some(), "Backfill Desk composite should expose Transport");
let transport = match transport {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let environment = ksp_config_lib::ConfigEnvironment::load();
assert!(environment.is_ok(), "Config environment should load for committed public devnet profile");
let environment = match environment {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let resolved = engine.resolve_transport_config_profile(transport.resolved(), &environment);
assert!(resolved.is_ok(), "composite-selected Transport should map: {resolved:?}");
let resolved = match resolved {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
assert_eq!(resolved.profile_id(), "devnet_public");
assert_eq!(resolved.selection_source(), ksp_config_lib::ConfigProfileSelectionSource::Composite);
let pool = ksp_onchain_transport_lib::HttpTransportPool::new(resolved.into_settings());
assert!(pool.is_ok(), "composite-selected Transport settings should construct an HTTP pool");
let pool = match pool {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let snapshot = pool.snapshot();
let mut clusters = snapshot
.endpoints()
.iter()
.filter_map(|endpoint| {
if endpoint.enabled() {
return std::option::Option::Some(endpoint.cluster().to_owned());
}
return std::option::Option::None;
})
.collect::<std::vec::Vec<_>>();
clusters.sort();
clusters.dedup();
assert_eq!(clusters, vec!["devnet".to_owned()]);
let role = ksp_onchain_transport_lib::HttpRoleName::new("default");
for method in ["getSignaturesForAddress", "getTransaction"] {
let descriptor = ksp_onchain_transport_lib::find_http_rpc_method(method);
assert!(descriptor.is_some(), "required Transport method {method} should exist");
if let std::option::Option::Some(descriptor) = descriptor {
let selection = pool.select_for_method(&role, descriptor);
assert!(selection.is_ok(), "role default should route {method}: {selection:?}");
}
}
}

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-backfill-desk/tests/desktop_contract.rs
// version: 3
// version: 4
//! Structural desktop contract checks for the Backfill Desk scaffold.
@@ -99,13 +99,7 @@ fn pre_002_package_dependencies_match_desk_baseline() {
fn pre_002_splash_assets_and_styles_match_existing_desk_template() {
let root = app_root();
let reference = workspace_root().join("crates/ksp-app-solprices-desk");
for relative in [
"frontend/fonts/DOS_Amazigh.ttf",
"frontend/imgs/logo.png",
"frontend/imgs/splash.png",
"icons/favicon.png",
"icons/favicon.ico",
] {
for relative in ["frontend/fonts/DOS_Amazigh.ttf", "frontend/imgs/logo.png", "frontend/imgs/splash.png", "icons/favicon.png", "icons/favicon.ico"] {
assert_eq!(read_bytes(root.join(relative).as_path()), read_bytes(reference.join(relative).as_path()), "Desk asset differs: {relative}");
}
let splash = read_text(root.join("frontend/splash.html").as_path());
@@ -113,9 +107,7 @@ fn pre_002_splash_assets_and_styles_match_existing_desk_template() {
assert!(splash.contains("Backfill Desk"));
let splash_style = read_text(root.join("frontend/sass/splash.scss").as_path());
let reference_style = read_text(reference.join("frontend/sass/splash.scss").as_path());
let normalized = splash_style
.replace("crates/ksp-app-backfill-desk", "crates/ksp-app-solprices-desk")
.replace("// version: 1", "// version: 2");
let normalized = splash_style.replace("crates/ksp-app-backfill-desk", "crates/ksp-app-solprices-desk").replace("// version: 1", "// version: 2");
assert_eq!(normalized, reference_style);
}
@@ -179,7 +171,7 @@ fn pre_003_composite_packaging_follows_atomic_config_registry_contract() {
}
#[test]
fn pre_003_bootstrap_uses_composite_logging_without_opening_transport_or_store() {
fn pre_003_bootstrap_keeps_logging_composition_separate_from_transport_runtime() {
let root = app_root();
let bootstrap = read_text(root.join("src/bootstrap.rs").as_path());
assert!(bootstrap.contains("FILE_ID_COMPOSITE_KSP_APP_BACKFILL_DESK"));
@@ -188,6 +180,23 @@ fn pre_003_bootstrap_uses_composite_logging_without_opening_transport_or_store()
assert!(bootstrap.contains("COMPOSITE_COMPONENT_ID_STORE"));
assert!(bootstrap.contains("LogFilterLevel::Trace"));
for forbidden in ["HttpTransportPool", "Store::open", "BackfillJobRuntime", "BackfillRequest"] {
assert!(!bootstrap.contains(forbidden), "pre.003 opens later runtime surface {forbidden}");
assert!(!bootstrap.contains(forbidden), "bootstrap.rs absorbs another runtime responsibility: {forbidden}");
}
}
#[test]
fn pre_004_transport_runtime_builds_pool_and_validates_both_required_rpc_methods() {
let root = app_root();
let transport = read_text(root.join("src/transport_runtime.rs").as_path());
assert!(transport.contains("HttpTransportPool::new"));
assert!(transport.contains("getSignaturesForAddress"));
assert!(transport.contains("getTransaction"));
assert!(transport.contains("select_for_method"));
assert!(transport.contains("configured_networks"));
assert!(transport.contains("compatible_backfill_roles"));
for forbidden in ["provider()", "url()", "Store::open", "BackfillJobRuntime", "BackfillRequest"] {
assert!(!transport.contains(forbidden), "pre.004 opens or projects forbidden surface {forbidden}");
}
let tauri = read_text(root.join("src/tauri.rs").as_path());
assert!(tauri.contains("backfill_options"));
}

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-backfill-desk/tests/desktop_security.rs
// version: 3
// version: 4
//! Security and dependency-boundary checks for the Backfill Desk scaffold.
@@ -43,7 +43,7 @@ fn read_text(path: &std::path::Path) -> String {
}
#[test]
fn pre_002_capability_surface_is_core_plus_tracing_only() {
fn capability_surface_remains_core_plus_tracing_while_transport_is_backend_only() {
let root = app_root();
let capability = read_text(root.join("capabilities/default.json").as_path());
assert!(capability.contains("\"core:default\""));
@@ -53,16 +53,9 @@ fn pre_002_capability_surface_is_core_plus_tracing_only() {
}
let manifest = read_text(root.join("Cargo.toml").as_path());
assert!(manifest.contains("tauri-plugin-tracing.workspace = true"));
for forbidden in [
"ksp-job-backfill-lib",
"ksp-onchain-transport-lib",
"ksp-store-lib",
"ksp-store-api",
"ksp-store-postgres-lib",
"reqwest",
"tokio-postgres",
] {
assert!(!manifest.contains(forbidden), "pre.002 opens a later-layer dependency: {forbidden}");
assert!(manifest.contains("ksp-onchain-transport-lib = { path = \"../ksp-onchain-transport-lib\" }"));
for forbidden in ["ksp-job-backfill-lib", "ksp-store-lib", "ksp-store-api", "ksp-store-postgres-lib", "reqwest", "tokio-postgres"] {
assert!(!manifest.contains(forbidden), "current Backfill Desk opens a forbidden dependency: {forbidden}");
}
}
@@ -95,7 +88,7 @@ fn pre_002_tauri_commands_remain_centralized() {
assert_eq!(count, 0, "{} declares a Tauri command outside tauri.rs", path.display());
}
}
assert_eq!(command_count, 3);
assert_eq!(command_count, 4);
}
#[test]
@@ -121,15 +114,21 @@ fn pre_002_frontend_instrumentation_avoids_business_or_secret_payloads() {
}
#[test]
fn pre_003_keeps_config_only_composition_boundary() {
fn pre_004_opens_only_config_logging_and_onchain_transport_dependencies() {
let root = app_root();
let manifest = read_text(root.join("Cargo.toml").as_path());
assert!(manifest.contains("ksp-config-lib = { path = \"../ksp-config-lib\" }"));
for forbidden in ["ksp-job-backfill-lib", "ksp-onchain-transport-lib", "ksp-store-lib", "ksp-store-api", "ksp-store-postgres-lib"] {
assert!(!manifest.contains(forbidden), "pre.003 opens a later-layer dependency: {forbidden}");
assert!(manifest.contains("ksp-onchain-transport-lib = { path = \"../ksp-onchain-transport-lib\" }"));
for forbidden in ["ksp-job-backfill-lib", "ksp-store-lib", "ksp-store-api", "ksp-store-postgres-lib"] {
assert!(!manifest.contains(forbidden), "pre.004 opens a later-layer dependency: {forbidden}");
}
let bootstrap = read_text(root.join("src/bootstrap.rs").as_path());
assert!(bootstrap.contains("LogFilterLevel::Trace"));
assert!(!bootstrap.contains("HttpTransportPool"));
assert!(!bootstrap.contains("Store::open"));
let dto = read_text(root.join("src/dto_common.rs").as_path());
assert!(dto.contains("BackfillDeskOptionsDto"));
for forbidden in ["pub(crate) provider", "endpoint_url", "pub(crate) url", "pub(crate) credential", "pub(crate) token"] {
assert!(!dto.contains(forbidden), "Transport options DTO source contains forbidden field marker {forbidden}");
}
}

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-app-backfill-desk/unit_tests/dto_common.rs
// version: 1
// version: 2
#[test]
fn command_error_projection_excludes_arbitrary_context_and_source_values() {
@@ -12,3 +12,23 @@ fn command_error_projection_excludes_arbitrary_context_and_source_values() {
assert_eq!(dto.code, "failed");
assert_eq!(dto.message, "safe message");
}
#[test]
fn transport_options_projection_contains_only_safe_transport_metadata() {
let dto = crate::BackfillDeskOptionsDto {
compatible_roles: vec!["default".to_owned()],
configured_networks: vec!["devnet".to_owned()],
transport_diagnostic: std::option::Option::None,
transport_ready: true,
};
let value = serde_json::to_value(dto);
assert!(value.is_ok());
if let std::result::Result::Ok(value) = value {
let serialized = value.to_string();
assert!(serialized.contains("default"));
assert!(serialized.contains("devnet"));
assert!(!serialized.contains("provider"));
assert!(!serialized.contains("url"));
assert!(!serialized.contains("endpoint"));
}
}

View File

@@ -0,0 +1,101 @@
// file: crates/ksp-app-backfill-desk/unit_tests/transport_runtime.rs
// version: 1
fn endpoint(
name: &str,
cluster: &str,
role_name: &str,
request_kinds: std::vec::Vec<ksp_onchain_transport_lib::HttpRequestKind>,
) -> ksp_core_lib::Result<ksp_onchain_transport_lib::HttpEndpointSettings> {
let url = ksp_onchain_transport_lib::HttpEndpointUrl::parse(format!("https://{name}.example.invalid"));
let url = match url {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let role = ksp_onchain_transport_lib::HttpEndpointRoleSettings::new(
ksp_onchain_transport_lib::HttpRoleName::new(role_name),
true,
request_kinds,
0,
ksp_onchain_transport_lib::HttpRoleLimits::new(
std::option::Option::None,
std::option::Option::None,
std::option::Option::None,
std::option::Option::None,
),
);
return std::result::Result::Ok(ksp_onchain_transport_lib::HttpEndpointSettings::new(
name,
true,
ksp_onchain_transport_lib::HttpProviderName::new("fixture"),
ksp_onchain_transport_lib::HttpClusterName::new(cluster),
url,
std::time::Duration::from_secs(1),
std::time::Duration::from_secs(2),
std::option::Option::Some(1),
vec![role],
));
}
fn pool(endpoints: std::vec::Vec<ksp_onchain_transport_lib::HttpEndpointSettings>) -> ksp_core_lib::Result<ksp_onchain_transport_lib::HttpTransportPool> {
let settings = ksp_onchain_transport_lib::HttpTransportSettings::new(
endpoints,
ksp_onchain_transport_lib::HttpRetrySettings::new(0, std::time::Duration::from_millis(10), std::time::Duration::from_millis(10)),
);
return ksp_onchain_transport_lib::HttpTransportPool::new(settings);
}
#[test]
fn compatible_roles_require_both_backfill_rpc_methods() {
let signatures = ksp_onchain_transport_lib::find_http_rpc_method("getSignaturesForAddress");
let transaction = ksp_onchain_transport_lib::find_http_rpc_method("getTransaction");
assert!(signatures.is_some());
assert!(transaction.is_some());
let signatures = match signatures {
std::option::Option::Some(value) => ksp_onchain_transport_lib::HttpRequestKind::new(value.request_kind()),
std::option::Option::None => return,
};
let transaction = match transaction {
std::option::Option::Some(value) => ksp_onchain_transport_lib::HttpRequestKind::new(value.request_kind()),
std::option::Option::None => return,
};
let complete = endpoint("complete", "devnet", "complete", vec![signatures.clone(), transaction]);
let complete = match complete {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let partial = endpoint("partial", "devnet", "partial", vec![signatures]);
let partial = match partial {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let runtime_pool = pool(vec![complete, partial]);
assert!(runtime_pool.is_ok());
let runtime_pool = match runtime_pool {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let snapshot = runtime_pool.snapshot();
let roles = super::compatible_backfill_roles(&runtime_pool, &snapshot);
assert!(roles.is_ok());
if let std::result::Result::Ok(roles) = roles {
assert_eq!(roles, vec!["complete".to_owned()]);
}
}
#[test]
fn configured_networks_are_safe_sorted_and_deduplicated() {
let one = endpoint("one", "testnet", "default", vec![ksp_onchain_transport_lib::HttpRequestKind::wildcard()]);
let two = endpoint("two", "devnet", "default", vec![ksp_onchain_transport_lib::HttpRequestKind::wildcard()]);
let three = endpoint("three", "devnet", "default", vec![ksp_onchain_transport_lib::HttpRequestKind::wildcard()]);
let (one, two, three) = match (one, two, three) {
(std::result::Result::Ok(one), std::result::Result::Ok(two), std::result::Result::Ok(three)) => (one, two, three),
_ => return,
};
let runtime_pool = pool(vec![one, two, three]);
assert!(runtime_pool.is_ok());
if let std::result::Result::Ok(runtime_pool) = runtime_pool {
let values = super::configured_networks(&runtime_pool.snapshot());
assert_eq!(values, vec!["devnet".to_owned(), "testnet".to_owned()]);
}
}