mirror of
https://github.com/OpenRouterTeam/spawn.git
synced 2026-05-22 11:24:18 +00:00
refactor: replace custom config loaders with shared helpers in 3 cloud libs (#445)
Migrate binarylane, northflank, and kamatera to use the shared ensure_api_token_with_provider, _load_json_config_fields, and _save_json_config helpers, removing ~120 lines of duplicated token loading/saving/validation logic. - binarylane: replace 50-line ensure_binarylane_token with ensure_api_token_with_provider + test_binarylane_token - northflank: remove _load_northflank_config, _save_northflank_token, _northflank_login; consolidate into ensure_api_token_with_provider with test_northflank_token doing login + validation - kamatera: replace inline python3 config loader with _load_json_config_fields, replace manual JSON save with _save_json_config Agent: complexity-hunter Co-authored-by: A <6723574+louisgv@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c1e009a66e
commit
f79de27bc7
3 changed files with 36 additions and 157 deletions
|
|
@ -35,55 +35,30 @@ binarylane_api() {
|
|||
generic_cloud_api "$BINARYLANE_API_BASE" "$BINARYLANE_API_TOKEN" "$method" "$endpoint" "$body"
|
||||
}
|
||||
|
||||
ensure_binarylane_token() {
|
||||
# Check Python 3 is available (required for JSON parsing)
|
||||
check_python_available || return 1
|
||||
|
||||
if [[ -n "${BINARYLANE_API_TOKEN:-}" ]]; then
|
||||
log_info "Using BinaryLane API token from environment"
|
||||
return 0
|
||||
fi
|
||||
local config_dir="$HOME/.config/spawn"
|
||||
local config_file="$config_dir/binarylane.json"
|
||||
if [[ -f "$config_file" ]]; then
|
||||
local saved_key
|
||||
saved_key=$(python3 -c "import json, sys; print(json.load(open(sys.argv[1])).get('api_token',''))" "$config_file" 2>/dev/null)
|
||||
if [[ -n "$saved_key" ]]; then
|
||||
export BINARYLANE_API_TOKEN="$saved_key"
|
||||
log_info "Using BinaryLane API token from $config_file"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
log_warn "BinaryLane API Token Required"
|
||||
log_warn "Get your API token from: https://home.binarylane.com.au/api-info"
|
||||
echo ""
|
||||
local api_token
|
||||
api_token=$(validated_read "Enter your BinaryLane API token: " validate_api_token) || return 1
|
||||
export BINARYLANE_API_TOKEN="$api_token"
|
||||
test_binarylane_token() {
|
||||
local response
|
||||
response=$(binarylane_api GET "/account")
|
||||
if echo "$response" | grep -q '"account"'; then
|
||||
log_info "API token validated"
|
||||
else
|
||||
log_error "Authentication failed: Invalid BinaryLane API token"
|
||||
|
||||
# Parse error details
|
||||
local error_msg
|
||||
error_msg=$(echo "$response" | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('message','No details available'))" 2>/dev/null || echo "Unable to parse error")
|
||||
log_error "API Error: $error_msg"
|
||||
|
||||
log_warn "Remediation steps:"
|
||||
log_warn " 1. Verify API token at: https://home.binarylane.com.au/api-info"
|
||||
log_warn " 2. Ensure the token has read/write permissions"
|
||||
log_warn " 3. Check token hasn't been revoked"
|
||||
unset BINARYLANE_API_TOKEN
|
||||
return 1
|
||||
return 0
|
||||
fi
|
||||
mkdir -p "$config_dir"
|
||||
printf '{\n "api_token": %s\n}\n' "$(json_escape "$api_token")" > "$config_file"
|
||||
chmod 600 "$config_file"
|
||||
log_info "API token saved to $config_file"
|
||||
local error_msg
|
||||
error_msg=$(echo "$response" | python3 -c "import json,sys; d=json.loads(sys.stdin.read()); print(d.get('message','No details available'))" 2>/dev/null || echo "Unable to parse error")
|
||||
log_error "API Error: $error_msg"
|
||||
log_error ""
|
||||
log_error "How to fix:"
|
||||
log_error " 1. Verify API token at: https://home.binarylane.com.au/api-info"
|
||||
log_error " 2. Ensure the token has read/write permissions"
|
||||
log_error " 3. Check token hasn't been revoked"
|
||||
return 1
|
||||
}
|
||||
|
||||
ensure_binarylane_token() {
|
||||
ensure_api_token_with_provider \
|
||||
"BinaryLane" \
|
||||
"BINARYLANE_API_TOKEN" \
|
||||
"$HOME/.config/spawn/binarylane.json" \
|
||||
"https://home.binarylane.com.au/api-info" \
|
||||
"test_binarylane_token"
|
||||
}
|
||||
|
||||
# Check if SSH key is registered with BinaryLane
|
||||
|
|
|
|||
|
|
@ -44,17 +44,8 @@ kamatera_api() {
|
|||
# Returns 0 if loaded, 1 otherwise
|
||||
_load_kamatera_config() {
|
||||
local config_file="$1"
|
||||
[[ -f "$config_file" ]] || return 1
|
||||
|
||||
local creds
|
||||
creds=$(python3 -c "
|
||||
import json, sys
|
||||
d = json.load(open(sys.argv[1]))
|
||||
print(d.get('api_client_id', ''))
|
||||
print(d.get('api_secret', ''))
|
||||
" "$config_file" 2>/dev/null) || return 1
|
||||
|
||||
[[ -n "${creds}" ]] || return 1
|
||||
creds=$(_load_json_config_fields "$config_file" api_client_id api_secret) || return 1
|
||||
|
||||
local saved_client_id saved_secret
|
||||
{ read -r saved_client_id; read -r saved_secret; } <<< "${creds}"
|
||||
|
|
@ -115,12 +106,7 @@ ensure_kamatera_token() {
|
|||
_validate_kamatera_credentials || return 1
|
||||
log_info "API credentials validated"
|
||||
|
||||
local config_dir
|
||||
config_dir=$(dirname "$config_file")
|
||||
mkdir -p "$config_dir"
|
||||
printf '{\n "api_client_id": %s,\n "api_secret": %s\n}\n' "$(json_escape "$client_id")" "$(json_escape "$secret")" > "$config_file"
|
||||
chmod 600 "$config_file"
|
||||
log_info "API credentials saved to $config_file"
|
||||
_save_json_config "$config_file" api_client_id "$client_id" api_secret "$secret"
|
||||
}
|
||||
|
||||
get_server_name() {
|
||||
|
|
|
|||
|
|
@ -37,108 +37,26 @@ ensure_northflank_cli() {
|
|||
}
|
||||
|
||||
test_northflank_token() {
|
||||
local test_response
|
||||
# Test token by listing projects (lightweight API call)
|
||||
test_response=$(northflank list projects 2>&1)
|
||||
local exit_code=$?
|
||||
|
||||
if [[ ${exit_code} -ne 0 ]]; then
|
||||
if echo "${test_response}" | grep -qi "unauthorized\|invalid.*token\|authentication"; then
|
||||
log_error "Invalid API token"
|
||||
log_warn "Remediation steps:"
|
||||
log_warn " 1. Verify API token at: https://northflank.com/account/settings/api/tokens"
|
||||
log_warn " 2. Ensure the token has appropriate permissions"
|
||||
log_warn " 3. Check token hasn't expired (90 day limit)"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Authenticate with Northflank CLI using a token
|
||||
# Returns 0 on success, 1 on invalid token
|
||||
_northflank_login() {
|
||||
local token="$1"
|
||||
if ! northflank login -t "${token}" &>/dev/null; then
|
||||
# Login with the token and validate by listing projects
|
||||
if ! northflank login -t "${NORTHFLANK_TOKEN}" &>/dev/null; then
|
||||
log_error "Failed to authenticate with Northflank CLI"
|
||||
log_error ""
|
||||
log_error "How to fix:"
|
||||
log_error " 1. Verify API token at: https://northflank.com/account/settings/api/tokens"
|
||||
log_error " 2. Ensure the token has appropriate permissions"
|
||||
log_error " 3. Check token hasn't expired (90 day limit)"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Try to load Northflank token from config file and authenticate
|
||||
# Returns 0 if loaded and valid, 1 otherwise
|
||||
_load_northflank_config() {
|
||||
local config_file="$1"
|
||||
[[ -f "${config_file}" ]] || return 1
|
||||
|
||||
local saved_token
|
||||
saved_token=$(python3 -c "import json, sys; print(json.load(open(sys.argv[1])).get('token',''))" "${config_file}" 2>/dev/null)
|
||||
if [[ -n "${saved_token}" ]]; then
|
||||
export NORTHFLANK_TOKEN="${saved_token}"
|
||||
log_info "Using Northflank token from ${config_file}"
|
||||
if _northflank_login "${saved_token}"; then
|
||||
return 0
|
||||
fi
|
||||
log_warn "Saved Northflank token is invalid, prompting for new one"
|
||||
unset NORTHFLANK_TOKEN
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Save Northflank token to config file
|
||||
_save_northflank_token() {
|
||||
local token="$1"
|
||||
local config_file="$2"
|
||||
local config_dir
|
||||
config_dir=$(dirname "${config_file}")
|
||||
mkdir -p "${config_dir}"
|
||||
printf '{\n "token": "%s"\n}\n' "$(json_escape "${token}")" > "${config_file}"
|
||||
chmod 600 "${config_file}"
|
||||
log_info "Northflank token saved to ${config_file}"
|
||||
}
|
||||
|
||||
ensure_northflank_token() {
|
||||
check_python_available || return 1
|
||||
|
||||
# 1. Check environment variable
|
||||
if [[ -n "${NORTHFLANK_TOKEN:-}" ]]; then
|
||||
log_info "Using Northflank token from environment"
|
||||
if ! _northflank_login "${NORTHFLANK_TOKEN}"; then
|
||||
log_error "Northflank token in environment is invalid"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
local config_file="${HOME}/.config/spawn/northflank.json"
|
||||
|
||||
# 2. Check config file
|
||||
if _load_northflank_config "${config_file}"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 3. Prompt and validate
|
||||
echo ""
|
||||
log_warn "Northflank API Token Required"
|
||||
printf '%b\n' "${YELLOW}Get your token at: https://northflank.com/account/settings/api/tokens${NC}"
|
||||
echo ""
|
||||
|
||||
local token
|
||||
token=$(safe_read "Enter your Northflank token: ") || return 1
|
||||
if [[ -z "${token}" ]]; then
|
||||
log_error "Northflank token cannot be empty"
|
||||
log_warn "For non-interactive usage, set: NORTHFLANK_TOKEN=your-token"
|
||||
return 1
|
||||
fi
|
||||
|
||||
export NORTHFLANK_TOKEN="${token}"
|
||||
if ! _northflank_login "${token}"; then
|
||||
log_error "Invalid Northflank token"
|
||||
unset NORTHFLANK_TOKEN
|
||||
return 1
|
||||
fi
|
||||
|
||||
_save_northflank_token "${token}" "${config_file}"
|
||||
ensure_api_token_with_provider \
|
||||
"Northflank" \
|
||||
"NORTHFLANK_TOKEN" \
|
||||
"$HOME/.config/spawn/northflank.json" \
|
||||
"https://northflank.com/account/settings/api/tokens" \
|
||||
"test_northflank_token"
|
||||
}
|
||||
|
||||
get_server_name() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue