perf(sandbox): inject http client into Daytona credential probe

Routes the two reqwest clients in the Daytona credential probe through
fabro_http (system-proxy) in production and fabro_test::test_http_client
(no_proxy) in tests, by threading an http_client parameter through
check_daytona_api_key_with and build_api_keys_configuration. Bumps the
daytona-sdk-rust pin to 314ffd9, which exposes DaytonaConfig::http_client
and ships on reqwest 0.13.

Drops the three credential-probe unit tests from >1s SLOW to ~0.5s by
skipping macOS proxy discovery on the localhost httpmock requests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-05-04 12:39:46 -04:00
parent f1742d1ab2
commit 17f1d1dfeb
No known key found for this signature in database
6 changed files with 65 additions and 77 deletions

75
Cargo.lock generated
View file

@ -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"

View file

@ -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"

View file

@ -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

View file

@ -105,18 +105,20 @@ fn perm_wire_str(permission: Permissions) -> &'static str {
async fn build_daytona_client(
api_key: Option<String>,
) -> Result<daytona_sdk::Client, daytona_sdk::DaytonaError> {
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<String>,
api_url: Option<String>,
organization_id: Option<String>,
http_client: Option<fabro_http::HttpClient>,
) -> Result<daytona_sdk::Client, daytona_sdk::DaytonaError> {
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<DaytonaKey
.or_else(|_| std::env::var(EnvVars::DAYTONA_SERVER_URL))
.unwrap_or_else(|_| DEFAULT_DAYTONA_API_URL.to_string());
let org_id = std::env::var(EnvVars::DAYTONA_ORGANIZATION_ID).ok();
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")?;
check_daytona_api_key_with(&base_url, org_id.as_deref(), api_key, http_client).await
}
pub async fn check_daytona_api_key_with(
base_url: &str,
org_id: Option<&str>,
api_key: String,
http_client: fabro_http::HttpClient,
) -> anyhow::Result<DaytonaKeyCheck> {
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::<Vec<_>>();
assert!(

View file

@ -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(

View file

@ -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