mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
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:
parent
f1742d1ab2
commit
17f1d1dfeb
6 changed files with 65 additions and 77 deletions
75
Cargo.lock
generated
75
Cargo.lock
generated
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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!(
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue