mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-19 16:16:45 +00:00
@@ -9,6 +9,7 @@ mod web_mcp;
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::net::{IpAddr, SocketAddr};
|
||||
use std::process::ExitCode;
|
||||
use std::sync::Arc;
|
||||
|
||||
use argon2::password_hash::rand_core::OsRng;
|
||||
@@ -456,18 +457,28 @@ fn add_mq_routes(router: Router<Arc<WebState>>) -> Router<Arc<WebState>> {
|
||||
router
|
||||
}
|
||||
|
||||
fn main() {
|
||||
fn main() -> ExitCode {
|
||||
let args: Vec<String> = std::env::args().skip(1).collect();
|
||||
if help_requested(&args) {
|
||||
print!("{HELP_TEXT}");
|
||||
return;
|
||||
return ExitCode::SUCCESS;
|
||||
}
|
||||
|
||||
let runtime = dbx_core::scheduled_backup::worker_runtime().expect("Failed to build tokio runtime");
|
||||
runtime.block_on(serve());
|
||||
match runtime.block_on(serve()) {
|
||||
Ok(()) => ExitCode::SUCCESS,
|
||||
Err(error) => {
|
||||
eprintln!("{error}");
|
||||
ExitCode::FAILURE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn serve() {
|
||||
fn web_mcp_startup_error(error: String) -> String {
|
||||
format!("Failed to start DBX Web: invalid Web MCP configuration: {error}")
|
||||
}
|
||||
|
||||
async fn serve() -> Result<(), String> {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
@@ -542,7 +553,7 @@ async fn serve() {
|
||||
let web_mcp = Arc::new(if migration_ready {
|
||||
WebMcpRuntime::load(&app_state.storage, !password_disabled && password_hash.is_some())
|
||||
.await
|
||||
.expect("Invalid DBX Web MCP configuration")
|
||||
.map_err(web_mcp_startup_error)?
|
||||
} else {
|
||||
WebMcpRuntime::disabled()
|
||||
});
|
||||
@@ -1457,7 +1468,7 @@ async fn serve() {
|
||||
.layer(CompressionLayer::new().compress_when(web_compression_predicate()))
|
||||
.layer(tower_http::trace::TraceLayer::new_for_http());
|
||||
|
||||
let mcp_router = web_mcp_router(&web_state).expect("Invalid DBX Web MCP configuration");
|
||||
let mcp_router = web_mcp_router(&web_state).map_err(web_mcp_startup_error)?;
|
||||
app = app.merge(
|
||||
mcp_router
|
||||
.layer(middleware::from_fn_with_state(web_state.clone(), web_mcp_demo_gate))
|
||||
|
||||
@@ -318,6 +318,63 @@ mod tests {
|
||||
assert!(validate_token("token\n".to_string()).is_err());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn deployment_token_without_allowed_hosts_returns_error() {
|
||||
let (_dir, storage) = test_storage().await;
|
||||
let result = WebMcpRuntime::load_with_deployment(
|
||||
&storage,
|
||||
Some(DeploymentConfig {
|
||||
token: "deployment-secret".to_string(),
|
||||
source: TokenSource::Environment,
|
||||
allowed_hosts: vec![],
|
||||
allowed_origins: vec![],
|
||||
}),
|
||||
false,
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_eq!(result.err().as_deref(), Some("DBX_WEB_MCP_ALLOWED_HOSTS or a Web MCP allowed Host is required"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn page_managed_settings_without_allowed_hosts_returns_dual_path_error() {
|
||||
let (_dir, storage) = test_storage().await;
|
||||
let runtime = WebMcpRuntime::load_with_deployment(&storage, None, true).await.unwrap();
|
||||
|
||||
let result = runtime.update(&storage, request(true, &[], false)).await;
|
||||
|
||||
assert_eq!(result.err().as_deref(), Some("DBX_WEB_MCP_ALLOWED_HOSTS or a Web MCP allowed Host is required"));
|
||||
assert!(!runtime.auth.enabled());
|
||||
assert!(storage.get_secret(SECRET_NAMESPACE, SECRET_KEY).await.unwrap().is_none());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn valid_deployment_configuration_enables_mcp() {
|
||||
let (_dir, storage) = test_storage().await;
|
||||
let runtime = WebMcpRuntime::load_with_deployment(
|
||||
&storage,
|
||||
Some(DeploymentConfig {
|
||||
token: "deployment-secret".to_string(),
|
||||
source: TokenSource::Environment,
|
||||
allowed_hosts: vec!["dbx.example.test:4224".to_string()],
|
||||
allowed_origins: vec![],
|
||||
}),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(runtime.status("/mcp".to_string(), false).enabled);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn absent_deployment_configuration_leaves_mcp_disabled() {
|
||||
let (_dir, storage) = test_storage().await;
|
||||
let runtime = WebMcpRuntime::load_with_deployment(&storage, None, false).await.unwrap();
|
||||
|
||||
assert!(!runtime.status("/mcp".to_string(), false).enabled);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn managed_token_survives_restart_and_is_encrypted() {
|
||||
let (_dir, storage) = test_storage().await;
|
||||
|
||||
Reference in New Issue
Block a user