From 32db000ca4e4cb6dafe1bfca6efc72d37ce94285 Mon Sep 17 00:00:00 2001 From: A <258483684+la14-1@users.noreply.github.com> Date: Fri, 20 Feb 2026 01:55:35 -0800 Subject: [PATCH] fix: validate env-var tokens and align cloud_authenticate patterns (#1516) - ensure_api_token_with_provider now validates env-var tokens with the provider test function, matching config-file token behavior. Previously, stale env-var tokens silently passed auth and failed at server creation with cryptic API errors. - Add prompt_spawn_name to Hetzner and Daytona cloud_authenticate, matching the pattern used by AWS, Fly, GCP, DigitalOcean, and Sprite. Without this, SPAWN_NAME_KEBAB is never set and server name prompts have no pre-filled default on these two providers. - Remove redundant register_cleanup_trap from DigitalOcean cloud_authenticate. shared/common.sh auto-registers the trap at source time (line 3696), making the explicit call dead code. Agent: code-health Co-authored-by: B <6723574+louisgv@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.5 --- daytona/lib/common.sh | 2 +- digitalocean/lib/common.sh | 2 +- hetzner/lib/common.sh | 2 +- shared/common.sh | 8 ++++++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/daytona/lib/common.sh b/daytona/lib/common.sh index ad56bca2..6679ac67 100644 --- a/daytona/lib/common.sh +++ b/daytona/lib/common.sh @@ -266,7 +266,7 @@ except Exception as e: # Cloud adapter interface # ============================================================ -cloud_authenticate() { ensure_daytona_token; } +cloud_authenticate() { prompt_spawn_name; ensure_daytona_token; } cloud_provision() { create_server "$1"; } cloud_wait_ready() { wait_for_cloud_init; } cloud_run() { run_server "$1"; } diff --git a/digitalocean/lib/common.sh b/digitalocean/lib/common.sh index 9f134b84..979fa7d9 100755 --- a/digitalocean/lib/common.sh +++ b/digitalocean/lib/common.sh @@ -259,7 +259,7 @@ for d in droplets: # Cloud adapter interface # ============================================================ -cloud_authenticate() { prompt_spawn_name; register_cleanup_trap; ensure_do_token; ensure_ssh_key; } +cloud_authenticate() { prompt_spawn_name; ensure_do_token; ensure_ssh_key; } cloud_provision() { create_server "$1"; } cloud_wait_ready() { verify_server_connectivity "${DO_SERVER_IP}"; wait_for_cloud_init "${DO_SERVER_IP}" 60; } cloud_run() { run_server "${DO_SERVER_IP}" "$1"; } diff --git a/hetzner/lib/common.sh b/hetzner/lib/common.sh index d12e1fc8..03515ad6 100755 --- a/hetzner/lib/common.sh +++ b/hetzner/lib/common.sh @@ -214,7 +214,7 @@ list_servers() { # Cloud adapter interface # ============================================================ -cloud_authenticate() { ensure_hcloud_token; ensure_ssh_key; } +cloud_authenticate() { prompt_spawn_name; ensure_hcloud_token; ensure_ssh_key; } cloud_provision() { create_server "$1"; } cloud_wait_ready() { verify_server_connectivity "${HETZNER_SERVER_IP}"; wait_for_cloud_init "${HETZNER_SERVER_IP}" 60; } cloud_run() { run_server "${HETZNER_SERVER_IP}" "$1"; } diff --git a/shared/common.sh b/shared/common.sh index b7941ccf..bf1d00af 100644 --- a/shared/common.sh +++ b/shared/common.sh @@ -2802,9 +2802,13 @@ ensure_api_token_with_provider() { check_python_available || return 1 - # Try environment variable + # Try environment variable (validate if test function provided) if _load_token_from_env "${env_var_name}" "${provider_name}"; then - return 0 + if [[ -z "${test_func}" ]] || "${test_func}" 2>/dev/null; then + return 0 + fi + log_warn "${provider_name} token from environment is invalid or expired" + unset "${env_var_name}" fi # Try config file (validate if test function provided, fall through to prompt on failure)