From 83fea45d48db991575c24cef94a53fdfe1e1623a Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Fri, 9 Jan 2026 07:03:29 +0000 Subject: [PATCH] split oauth into separate crate --- backend/Cargo.lock | 26 +++++++++++++++- backend/Cargo.toml | 2 ++ backend/ee-repo-ref.txt | 2 +- backend/windmill-api/Cargo.toml | 4 +-- backend/windmill-api/src/oauth2_oss.rs | 2 +- backend/windmill-oauth | 1 + backend/windmill-worker/src/ai/utils.rs | 6 +--- backend/windmill-worker/src/ai_executor.rs | 35 ++++++++++++++-------- 8 files changed, 56 insertions(+), 22 deletions(-) create mode 120000 backend/windmill-oauth diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 017b01440e..fc4ebf86c7 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -15258,7 +15258,6 @@ dependencies = [ "argon2", "astral-tokio-tar", "async-nats", - "async-oauth2", "async-recursion", "async-stream", "async-trait", @@ -15364,6 +15363,7 @@ dependencies = [ "windmill-git-sync", "windmill-indexer", "windmill-mcp", + "windmill-oauth", "windmill-parser", "windmill-parser-py", "windmill-parser-py-imports", @@ -15577,6 +15577,30 @@ dependencies = [ "windmill-common", ] +[[package]] +name = "windmill-oauth" +version = "1.602.0" +dependencies = [ + "anyhow", + "async-oauth2", + "axum", + "base64 0.22.1", + "chrono", + "hex", + "hmac", + "itertools 0.14.0", + "lazy_static", + "reqwest 0.12.28", + "serde", + "serde_json", + "sha2 0.10.9", + "sqlx", + "tokio", + "tower-cookies", + "tracing", + "windmill-common", +] + [[package]] name = "windmill-parser" version = "1.602.0" diff --git a/backend/Cargo.toml b/backend/Cargo.toml index f7b79a75d0..006caae3c6 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -17,6 +17,7 @@ members = [ "./windmill-autoscaling", "./windmill-indexer", "./windmill-macros", + "./windmill-oauth", "./parsers/windmill-parser", "./parsers/windmill-parser-ts", "./parsers/windmill-parser-go", @@ -191,6 +192,7 @@ windmill-git-sync = { path = "./windmill-git-sync" } windmill-autoscaling = { path = "./windmill-autoscaling" } windmill-indexer = {path = "./windmill-indexer"} windmill-mcp = {path = "./windmill-mcp"} +windmill-oauth = {path = "./windmill-oauth"} windmill-macros = {path = "./windmill-macros"} windmill-parser = { path = "./parsers/windmill-parser" } windmill-parser-ts = { path = "./parsers/windmill-parser-ts" } diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 2c7140a0d1..d03b2537b8 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -cf96b45aa1183f15b3cc1b971035de5e37a68849 +c8e8a6df19203acc2cef1aebd1bd4157f2439cbf \ No newline at end of file diff --git a/backend/windmill-api/Cargo.toml b/backend/windmill-api/Cargo.toml index b584a5ae22..f2647f9481 100644 --- a/backend/windmill-api/Cargo.toml +++ b/backend/windmill-api/Cargo.toml @@ -27,7 +27,7 @@ websocket = ["dep:tokio-tungstenite"] smtp = ["dep:mail-parser", "dep:openssl", "windmill-common/smtp"] license = ["dep:rsa"] zip = ["dep:async_zip"] -oauth2 = ["dep:async-oauth2"] +oauth2 = ["dep:windmill-oauth"] http_trigger = ["dep:matchit", "dep:thiserror", "dep:sha1", "dep:constant_time_eq"] static_frontend = ["dep:rust-embed"] postgres_trigger = ["dep:rust-postgres", "dep:pg_escape", "dep:byteorder", "dep:thiserror", "dep:rust_decimal", "dep:rust-postgres-native-tls"] @@ -67,7 +67,7 @@ itertools.workspace = true reqwest.workspace = true serde.workspace = true sqlx.workspace = true -async-oauth2 = { workspace = true, optional = true } +windmill-oauth = { workspace = true, optional = true } tracing.workspace = true sql-builder.workspace = true serde_json.workspace = true diff --git a/backend/windmill-api/src/oauth2_oss.rs b/backend/windmill-api/src/oauth2_oss.rs index 04e0e1b202..fba65a11bd 100644 --- a/backend/windmill-api/src/oauth2_oss.rs +++ b/backend/windmill-api/src/oauth2_oss.rs @@ -21,7 +21,7 @@ use hmac::Mac; #[cfg(all(feature = "oauth2", not(feature = "private")))] use itertools::Itertools; #[cfg(all(feature = "oauth2", not(feature = "private")))] -use oauth2::{Client as OClient, *}; +use windmill_oauth::{OClient, AccessToken, RefreshToken, Scope, helpers}; #[cfg(not(feature = "private"))] use serde::{Deserialize, Serialize}; #[cfg(not(feature = "private"))] diff --git a/backend/windmill-oauth b/backend/windmill-oauth new file mode 120000 index 0000000000..5e3975c1e9 --- /dev/null +++ b/backend/windmill-oauth @@ -0,0 +1 @@ +/home/rfiszel/windmill-ee-private/windmill-oauth \ No newline at end of file diff --git a/backend/windmill-worker/src/ai/utils.rs b/backend/windmill-worker/src/ai/utils.rs index 2b1d652933..41da22c6a9 100644 --- a/backend/windmill-worker/src/ai/utils.rs +++ b/backend/windmill-worker/src/ai/utils.rs @@ -547,11 +547,7 @@ pub async fn execute_mcp_tool( // Stub implementations when mcp feature is not enabled #[cfg(not(feature = "mcp"))] -pub struct McpResourceConfig { - pub resource_path: String, - pub include_tools: Option>, - pub exclude_tools: Option>, -} +pub struct McpResourceConfig {} /// Stub for cleanup_mcp_clients when mcp is not enabled #[cfg(not(feature = "mcp"))] diff --git a/backend/windmill-worker/src/ai_executor.rs b/backend/windmill-worker/src/ai_executor.rs index 3d9f407e93..9e981556b1 100644 --- a/backend/windmill-worker/src/ai_executor.rs +++ b/backend/windmill-worker/src/ai_executor.rs @@ -153,24 +153,34 @@ pub async fn handle_ai_agent_job( // Separate Windmill tools from MCP tools, websearch, and extract MCP resource configs let mut windmill_modules: Vec = Vec::new(); + #[allow(unused_mut)] let mut mcp_configs: Vec = Vec::new(); let mut has_websearch = false; for tool in tools { match &tool.value { + #[allow(unused_variables)] ToolValue::Mcp(mcp_config) => { - // This is an MCP tool - extract config - tracing::debug!( - "MCP server module: path={}, include={:?}, exclude={:?}", - mcp_config.resource_path, - mcp_config.include_tools, - mcp_config.exclude_tools - ); - mcp_configs.push(crate::ai::utils::McpResourceConfig { - resource_path: mcp_config.resource_path.clone(), - include_tools: Some(mcp_config.include_tools.clone()), - exclude_tools: Some(mcp_config.exclude_tools.clone()), - }); + #[cfg(feature = "mcp")] + { + // This is an MCP tool - extract config + tracing::debug!( + "MCP server module: path={}, include={:?}, exclude={:?}", + mcp_config.resource_path, + mcp_config.include_tools, + mcp_config.exclude_tools + ); + mcp_configs.push(crate::ai::utils::McpResourceConfig { + resource_path: mcp_config.resource_path.clone(), + include_tools: Some(mcp_config.include_tools.clone()), + exclude_tools: Some(mcp_config.exclude_tools.clone()), + }); + } + + #[cfg(not(feature = "mcp"))] + { + tracing::warn!("MCP tool detected but MCP feature is not enabled"); + } } ToolValue::FlowModule(_) => { // Regular Windmill flow module (script, flow, etc.) - convert to FlowModule @@ -303,6 +313,7 @@ pub async fn handle_ai_agent_job( // Load MCP tools if configured let mut tools = tools; + let mcp_clients = if !mcp_configs.is_empty() { let (clients, mcp_tools) = load_mcp_tools(db, &job.workspace_id, mcp_configs).await?; tools.extend(mcp_tools);