diff --git a/Cargo.lock b/Cargo.lock index 694602972..aed402634 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1208,9 +1208,9 @@ checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "daytona-api-client" version = "0.1.0" -source = "git+https://github.com/brynary/daytona-sdk-rust?rev=cf4e3d5#cf4e3d5d7ef759fc10bd194f3a72130c0d92fb7d" +source = "git+https://github.com/brynary/daytona-sdk-rust?rev=314ffd9#314ffd9a8057bd82d3496f2ed5aa29d0832d0bb0" dependencies = [ - "reqwest 0.12.28", + "reqwest 0.13.2", "reqwest-middleware", "serde", "serde_json", @@ -1222,12 +1222,12 @@ dependencies = [ [[package]] name = "daytona-sdk" version = "0.1.0" -source = "git+https://github.com/brynary/daytona-sdk-rust?rev=cf4e3d5#cf4e3d5d7ef759fc10bd194f3a72130c0d92fb7d" +source = "git+https://github.com/brynary/daytona-sdk-rust?rev=314ffd9#314ffd9a8057bd82d3496f2ed5aa29d0832d0bb0" dependencies = [ "daytona-api-client", "daytona-toolbox-client", "futures-util", - "reqwest 0.12.28", + "reqwest 0.13.2", "reqwest-middleware", "rustls", "serde", @@ -1242,9 +1242,9 @@ dependencies = [ [[package]] name = "daytona-toolbox-client" version = "0.1.0" -source = "git+https://github.com/brynary/daytona-sdk-rust?rev=cf4e3d5#cf4e3d5d7ef759fc10bd194f3a72130c0d92fb7d" +source = "git+https://github.com/brynary/daytona-sdk-rust?rev=314ffd9#314ffd9a8057bd82d3496f2ed5aa29d0832d0bb0" dependencies = [ - "reqwest 0.12.28", + "reqwest 0.13.2", "reqwest-middleware", "serde", "serde_json", @@ -2109,9 +2109,11 @@ dependencies = [ "daytona-sdk", "fabro-config", "fabro-github", + "fabro-http", "fabro-proc", "fabro-redact", "fabro-static", + "fabro-test", "fabro-types", "fabro-util", "futures", @@ -2119,6 +2121,7 @@ dependencies = [ "glob", "httpmock", "rand 0.9.4", + "reqwest-middleware", "serde", "serde_json", "shlex", @@ -3291,22 +3294,6 @@ dependencies = [ "webpki-roots 1.0.6", ] -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - [[package]] name = "hyper-util" version = "0.1.20" @@ -4205,23 +4192,6 @@ dependencies = [ "getrandom 0.2.17", ] -[[package]] -name = "native-tls" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe 0.2.1", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "new_debug_unreachable" version = "1.0.6" @@ -5500,7 +5470,6 @@ checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64", "bytes", - "encoding_rs", "futures-channel", "futures-core", "futures-util", @@ -5510,13 +5479,9 @@ dependencies = [ "http-body-util", "hyper", "hyper-rustls", - "hyper-tls", "hyper-util", "js-sys", "log", - "mime", - "mime_guess", - "native-tls", "percent-encoding", "pin-project-lite", "quinn", @@ -5528,7 +5493,6 @@ dependencies = [ "serde_urlencoded", "sync_wrapper", "tokio", - "tokio-native-tls", "tokio-rustls", "tokio-util", "tower", @@ -5552,9 +5516,11 @@ dependencies = [ "bytes", "cookie", "cookie_store", + "encoding_rs", "futures-channel", "futures-core", "futures-util", + "h2", "http", "http-body", "http-body-util", @@ -5563,6 +5529,7 @@ dependencies = [ "hyper-util", "js-sys", "log", + "mime", "mime_guess", "percent-encoding", "pin-project-lite", @@ -5589,16 +5556,16 @@ dependencies = [ [[package]] name = "reqwest-middleware" -version = "0.4.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57f17d28a6e6acfe1733fe24bcd30774d13bffa4b8a22535b4c8c98423088d4e" +checksum = "199dda04a536b532d0cc04d7979e39b1c763ea749bf91507017069c00b96056f" dependencies = [ "anyhow", "async-trait", "http", - "reqwest 0.12.28", + "reqwest 0.13.2", "serde", - "thiserror 1.0.69", + "thiserror 2.0.18", "tower-service", ] @@ -6872,16 +6839,6 @@ dependencies = [ "syn 2.0.117", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.4" diff --git a/Cargo.toml b/Cargo.toml index 0292374e6..b1a5723a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,8 +68,8 @@ twin-openai = { path = "test/twin/openai" } twin-github = { path = "test/twin/github" } tokio-tungstenite = { version = "0.26", features = ["rustls-tls-webpki-roots"] } futures-util = "0.3" -daytona-sdk = { git = "https://github.com/brynary/daytona-sdk-rust", rev = "cf4e3d5", package = "daytona-sdk" } -daytona-api-client = { git = "https://github.com/brynary/daytona-sdk-rust", rev = "cf4e3d5", package = "daytona-api-client" } +daytona-sdk = { git = "https://github.com/brynary/daytona-sdk-rust", rev = "314ffd9", package = "daytona-sdk" } +daytona-api-client = { git = "https://github.com/brynary/daytona-sdk-rust", rev = "314ffd9", package = "daytona-api-client" } sentry = { version = "0.35", default-features = false, features = ["backtrace", "contexts", "ureq", "rustls"] } fork = "0.2" exec = "0.3" diff --git a/lib/crates/fabro-sandbox/Cargo.toml b/lib/crates/fabro-sandbox/Cargo.toml index 1f0498bf5..369dbc7ee 100644 --- a/lib/crates/fabro-sandbox/Cargo.toml +++ b/lib/crates/fabro-sandbox/Cargo.toml @@ -10,7 +10,7 @@ description = "Sandbox trait and implementations for Fabro agent execution envir default = ["local"] local = [] docker = ["dep:bollard", "dep:tar", "dep:futures", "dep:fabro-github"] -daytona = ["dep:daytona-sdk", "dep:daytona-api-client", "dep:git2", "dep:fabro-github", "dep:fabro-config", "dep:chrono", "dep:rand"] +daytona = ["dep:daytona-sdk", "dep:daytona-api-client", "dep:git2", "dep:fabro-github", "dep:fabro-config", "dep:fabro-http", "dep:reqwest-middleware", "dep:chrono", "dep:rand"] test-support = [] [lib] @@ -55,6 +55,8 @@ rand = { workspace = true, optional = true } daytona-sdk = { workspace = true, optional = true } daytona-api-client = { workspace = true, optional = true } git2 = { workspace = true, optional = true } +fabro-http = { workspace = true, optional = true } +reqwest-middleware = { version = "0.5", features = ["json", "multipart", "form", "query"], optional = true } [dev-dependencies] tokio = { workspace = true, features = ["test-util", "macros"] } @@ -63,3 +65,4 @@ uuid.workspace = true serde_json.workspace = true toml.workspace = true httpmock = "0.8" +fabro-test.workspace = true diff --git a/lib/crates/fabro-sandbox/src/daytona/mod.rs b/lib/crates/fabro-sandbox/src/daytona/mod.rs index d4e1f4675..bcbcfc61e 100644 --- a/lib/crates/fabro-sandbox/src/daytona/mod.rs +++ b/lib/crates/fabro-sandbox/src/daytona/mod.rs @@ -105,18 +105,20 @@ fn perm_wire_str(permission: Permissions) -> &'static str { async fn build_daytona_client( api_key: Option, ) -> Result { - build_daytona_client_with(api_key, None, None).await + build_daytona_client_with(api_key, None, None, None).await } async fn build_daytona_client_with( api_key: Option, api_url: Option, organization_id: Option, + http_client: Option, ) -> Result { let sdk_config = daytona_sdk::DaytonaConfig { api_key, api_url, organization_id, + http_client, ..Default::default() }; daytona_sdk::Client::new_with_config(sdk_config).await @@ -131,19 +133,22 @@ pub async fn check_daytona_api_key(api_key: String) -> anyhow::Result, api_key: String, + http_client: fabro_http::HttpClient, ) -> anyhow::Result { let work = async { let client = build_daytona_client_with( Some(api_key.clone()), Some(base_url.to_string()), org_id.map(str::to_string), + Some(http_client.clone()), ) .await .map_err(anyhow::Error::new) @@ -154,7 +159,7 @@ pub async fn check_daytona_api_key_with( .map_err(anyhow::Error::new) .context("failed to authenticate with Daytona")?; - let api_config = build_api_keys_configuration(base_url, &api_key); + let api_config = build_api_keys_configuration(base_url, &api_key, http_client); let info = api_keys_api::get_current_api_key(&api_config, org_id) .await .map_err(anyhow::Error::new) @@ -180,11 +185,16 @@ pub async fn check_daytona_api_key_with( } } -fn build_api_keys_configuration(base_url: &str, api_key: &str) -> Configuration { +fn build_api_keys_configuration( + base_url: &str, + api_key: &str, + http_client: fabro_http::HttpClient, +) -> Configuration { let mut cfg = Configuration::new(); cfg.base_path = base_url.to_string(); cfg.bearer_access_token = Some(api_key.to_string()); cfg.user_agent = Some(FABRO_SANDBOX_USER_AGENT.to_string()); + cfg.client = reqwest_middleware::ClientBuilder::new(http_client).build(); cfg } @@ -1985,9 +1995,14 @@ mod tests { ]) .await; - let check = check_daytona_api_key_with(&server.base_url(), None, "dtn_test".to_string()) - .await - .expect("probe should succeed"); + let check = check_daytona_api_key_with( + &server.base_url(), + None, + "dtn_test".to_string(), + fabro_test::test_http_client(), + ) + .await + .expect("probe should succeed"); assert!(!check.ok()); assert_eq!(check.key_name, "delete-only"); @@ -2008,9 +2023,14 @@ mod tests { ]) .await; - let check = check_daytona_api_key_with(&server.base_url(), None, "dtn_test".to_string()) - .await - .expect("probe should succeed"); + let check = check_daytona_api_key_with( + &server.base_url(), + None, + "dtn_test".to_string(), + fabro_test::test_http_client(), + ) + .await + .expect("probe should succeed"); assert!(check.ok()); assert!(check.missing.is_empty()); @@ -2023,9 +2043,14 @@ mod tests { let server = MockServer::start_async().await; let auth = mock_auth_probe(&server, 401).await; - let err = check_daytona_api_key_with(&server.base_url(), None, "dtn_test".to_string()) - .await - .expect_err("auth probe should fail"); + let err = check_daytona_api_key_with( + &server.base_url(), + None, + "dtn_test".to_string(), + fabro_test::test_http_client(), + ) + .await + .expect_err("auth probe should fail"); let chain = err.chain().map(ToString::to_string).collect::>(); assert!( diff --git a/lib/crates/fabro-server/src/install.rs b/lib/crates/fabro-server/src/install.rs index e044f9cb4..d581d7762 100644 --- a/lib/crates/fabro-server/src/install.rs +++ b/lib/crates/fabro-server/src/install.rs @@ -971,7 +971,8 @@ async fn check_install_daytona_api_key( .as_deref() .unwrap_or(daytona::DEFAULT_DAYTONA_API_URL); let organization_id = state.upstreams.daytona_organization_id.as_deref(); - daytona::check_daytona_api_key_with(base_url, organization_id, api_key).await + let http_client = fabro_http::http_client().context("failed to build HTTP client")?; + daytona::check_daytona_api_key_with(base_url, organization_id, api_key, http_client).await } async fn put_install_sandbox( diff --git a/lib/crates/fabro-server/src/server.rs b/lib/crates/fabro-server/src/server.rs index 0fe52a578..eb35ef8b0 100644 --- a/lib/crates/fabro-server/src/server.rs +++ b/lib/crates/fabro-server/src/server.rs @@ -628,7 +628,9 @@ impl AppState { .unwrap_or_else(|| daytona::DEFAULT_DAYTONA_API_URL.to_string()); let org_id = self.env_lookup_or_vault_or_env(EnvVars::DAYTONA_ORGANIZATION_ID); - daytona::check_daytona_api_key_with(&base_url, org_id.as_deref(), api_key).await + let http_client = fabro_http::http_client().context("failed to build HTTP client")?; + daytona::check_daytona_api_key_with(&base_url, org_id.as_deref(), api_key, http_client) + .await } /// Public accessor used by `run_files` — mirrors `vault_or_env` without