Skip to content

Commit 0d4d9f9

Browse files
committed
Fix admin token env-var fallback shadowed by empty default
The baked-in gateway.toml shipped `api_token = ""`, which figment merges into AdminConfig as `Some("")`. `AdminAuth::from_config` only triggered the `DSTACK_GATEWAY_ADMIN_TOKEN` env-var fallback when `api_token` was `None`, so the env var was never read and admin startup always bailed with "no API token is configured" even when the env var was set. Drop the empty default from the baked toml and treat blank api_token as unset so the env-var fallback fires. Add a regression test covering both empty-string and whitespace-only config values.
1 parent f60af33 commit 0d4d9f9

2 files changed

Lines changed: 30 additions & 1 deletion

File tree

gateway/gateway.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ timeout = "5s"
2525
enabled = false
2626
address = "127.0.0.1:8011"
2727
# Required when admin.enabled = true, unless DSTACK_GATEWAY_ADMIN_TOKEN is set.
28-
api_token = ""
28+
# Leave unset (do not assign ""): an empty string here would shadow the env-var
29+
# fallback in AdminAuth::from_config.
30+
# api_token = ""
2931
# Development/testing escape hatch only. Never enable this on a reachable admin interface.
3032
insecure_no_auth = false
3133

gateway/src/admin_auth.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ impl AdminAuth {
2727
let token = config
2828
.api_token
2929
.clone()
30+
.filter(|token| !token.trim().is_empty())
3031
.or_else(|| std::env::var(ENV_ADMIN_TOKEN).ok())
3132
.map(|token| token.trim().to_string())
3233
.filter(|token| !token.is_empty());
@@ -113,4 +114,30 @@ mod tests {
113114
assert!(auth.verify(None));
114115
assert!(auth.verify(Some("Bearer anything")));
115116
}
117+
118+
#[test]
119+
fn blank_config_token_falls_back_to_env() {
120+
// Single test exercising both empty and whitespace api_token to avoid
121+
// parallel tests racing on the process-wide DSTACK_GATEWAY_ADMIN_TOKEN.
122+
//
123+
// Reproduces the regression where api_token = "" in the baked default
124+
// gateway.toml shadowed the env-var fallback.
125+
for blank in ["", " "] {
126+
let token = "env-token-value";
127+
std::env::set_var(ENV_ADMIN_TOKEN, token);
128+
let auth = AdminAuth::from_config(&AdminConfig {
129+
enabled: true,
130+
api_token: Some(blank.to_string()),
131+
insecure_no_auth: false,
132+
})
133+
.expect("blank config token must defer to env-var");
134+
std::env::remove_var(ENV_ADMIN_TOKEN);
135+
136+
assert!(
137+
auth.verify(Some(&format!("Bearer {token}"))),
138+
"expected fallback to env-var when api_token={blank:?}"
139+
);
140+
assert!(!auth.verify(Some("Bearer wrong")));
141+
}
142+
}
116143
}

0 commit comments

Comments
 (0)