diff --git a/apps/desktop/src-tauri/src/commands/gateway.rs b/apps/desktop/src-tauri/src/commands/gateway.rs index 0f66f09b..d42e0c66 100644 --- a/apps/desktop/src-tauri/src/commands/gateway.rs +++ b/apps/desktop/src-tauri/src/commands/gateway.rs @@ -217,6 +217,22 @@ pub(crate) async fn load_network_access(app_state: &AppState) -> bool { load_network_access_from_repo(&app_state.settings_repository).await } +pub(crate) async fn load_gateway_auth_disabled_from_repo( + settings_repository: &Arc, +) -> bool { + settings_repository + .get(GATEWAY_AUTH_DISABLED_KEY) + .await + .ok() + .flatten() + .map(|value| value == "true") + .unwrap_or(false) +} + +pub(crate) async fn load_gateway_auth_disabled(app_state: &AppState) -> bool { + load_gateway_auth_disabled_from_repo(&app_state.settings_repository).await +} + pub(crate) fn advertised_base_url(public_base_url: Option<&str>, port: u16) -> String { public_base_url .map(str::trim) @@ -1037,18 +1053,8 @@ pub async fn start_gateway( // Seed the system-wide inbound-auth toggle into the running gateway from // persisted settings (default: auth required). Live changes go through // `set_gateway_auth_disabled`. - { - let disabled = app_state - .settings_repository - .get(GATEWAY_AUTH_DISABLED_KEY) - .await - .ok() - .flatten() - .map(|v| v == "true") - .unwrap_or(false); - if disabled { - gw_state.write().await.set_auth_disabled(true); - } + if load_gateway_auth_disabled(&app_state).await { + gw_state.write().await.set_auth_disabled(true); } // Subscribe to OAuth completions BEFORE spawn so we don't miss early @@ -2041,3 +2047,37 @@ mod public_base_url_tests { assert_eq!(super::bind_host_for(true), "0.0.0.0"); } } + +#[cfg(test)] +mod gateway_auth_settings_tests { + use super::{load_gateway_auth_disabled_from_repo, GATEWAY_AUTH_DISABLED_KEY}; + use mcpmux_core::AppSettingsRepository; + use mcpmux_storage::{Database, SqliteAppSettingsRepository}; + use std::sync::Arc; + use tokio::sync::Mutex; + + fn settings_repo() -> Arc { + let database = Database::open_in_memory().expect("create in-memory database"); + Arc::new(SqliteAppSettingsRepository::new(Arc::new(Mutex::new( + database, + )))) + } + + #[tokio::test] + async fn auth_remains_required_when_disable_setting_is_missing() { + let repository = settings_repo(); + + assert!(!load_gateway_auth_disabled_from_repo(&repository).await); + } + + #[tokio::test] + async fn persisted_disable_setting_is_restored_on_gateway_start() { + let repository = settings_repo(); + repository + .set(GATEWAY_AUTH_DISABLED_KEY, "true") + .await + .unwrap(); + + assert!(load_gateway_auth_disabled_from_repo(&repository).await); + } +} diff --git a/apps/desktop/src-tauri/src/lib.rs b/apps/desktop/src-tauri/src/lib.rs index 5cde1a72..ec6eee11 100644 --- a/apps/desktop/src-tauri/src/lib.rs +++ b/apps/desktop/src-tauri/src/lib.rs @@ -425,6 +425,9 @@ pub fn run() { // devices on the LAN can reach the gateway; loopback-only otherwise. let network_access = crate::commands::gateway::load_network_access_from_repo(&settings_repo).await; + let auth_disabled = + crate::commands::gateway::load_gateway_auth_disabled_from_repo(&settings_repo) + .await; let local_url = format!("http://localhost:{}", final_port); info!("Auto-starting gateway on {} (advertising {})", local_url, url); @@ -484,6 +487,10 @@ pub fn run() { let server = mcpmux_gateway::GatewayServer::new(config, dependencies); let gw_inner_state = server.state(); + if auth_disabled { + gw_inner_state.write().await.set_auth_disabled(true); + } + // Get services from gateway let pool_service = server.pool_service(); let feature_service = server.feature_service();