From 18cbd7fb5009888e5226ef0d3544db02604fa304 Mon Sep 17 00:00:00 2001 From: MickLesk Date: Wed, 29 Jul 2026 08:10:57 +0200 Subject: [PATCH] Harden remote func bootstrapping Replace bare `source <(curl ...)` calls with a `_bootstrap_source` helper that validates both the download exit code and the presence of a probe function after sourcing. This prevents silent failures when DNS is not yet available in a freshly booted container or when a download fails mid-stream. Applies to build.func, install.func, and alpine-install.func. Also adds retry flags and a connect timeout to curl/wget. --- misc/alpine-install.func | 20 ++++++++++++++++++-- misc/build.func | 40 ++++++++++++++++++++++++++++------------ misc/install.func | 20 ++++++++++++++++++-- 3 files changed, 64 insertions(+), 16 deletions(-) diff --git a/misc/alpine-install.func b/misc/alpine-install.func index 695a55b1d..8b05cd5b5 100644 --- a/misc/alpine-install.func +++ b/misc/alpine-install.func @@ -10,8 +10,24 @@ fi # must write local failure artifacts instead of talking to the telemetry API # (the host is the single telemetry reporter). export TELEMETRY_CONTEXT="container" -source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) -source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) +# A freshly booted container may not have DNS up yet. `source <(curl ...)` hides +# curl's exit code, so a failed download would silently source an empty stream. +_bootstrap_source() { + local url="$1" probe="$2" content + content=$(curl -fsSL --connect-timeout 10 --retry 5 --retry-connrefused --retry-delay 2 "$url") || { + echo "FATAL: failed to download ${url##*/}" >&2 + exit 115 + } + source /dev/stdin <<<"$content" + declare -f "$probe" >/dev/null 2>&1 || { + echo "FATAL: ${url##*/} loaded but incomplete (missing ${probe})" >&2 + exit 115 + } +} + +_FUNC_BASE="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc" +_bootstrap_source "$_FUNC_BASE/core.func" load_functions +_bootstrap_source "$_FUNC_BASE/error_handler.func" catch_errors load_functions catch_errors diff --git a/misc/build.func b/misc/build.func index 8246da3f8..07b0b2186 100644 --- a/misc/build.func +++ b/misc/build.func @@ -88,19 +88,35 @@ variables() { fi } -source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func) +# `source <(curl ...)` hides the download exit code, so a failed fetch would +# silently source an empty stream and leave the helpers undefined. +_bootstrap_source() { + local url="$1" probe="$2" content="" + if command -v curl >/dev/null 2>&1; then + content=$(curl -fsSL --connect-timeout 10 --retry 5 --retry-connrefused --retry-delay 2 "$url") || content="" + elif command -v wget >/dev/null 2>&1; then + content=$(wget -qO- --tries=5 --timeout=10 "$url") || content="" + else + echo "FATAL: neither curl nor wget available" >&2 + exit 115 + fi + if [[ -z "$content" ]]; then + echo "FATAL: failed to download ${url##*/}" >&2 + exit 115 + fi + source /dev/stdin <<<"$content" + if ! declare -f "$probe" >/dev/null 2>&1; then + echo "FATAL: ${url##*/} loaded but incomplete (missing ${probe})" >&2 + exit 115 + fi +} -if command -v curl >/dev/null 2>&1; then - source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) - source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) - load_functions - catch_errors -elif command -v wget >/dev/null 2>&1; then - source <(wget -qO- https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) - source <(wget -qO- https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) - load_functions - catch_errors -fi +_FUNC_BASE="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc" +_bootstrap_source "$_FUNC_BASE/api.func" post_to_api +_bootstrap_source "$_FUNC_BASE/core.func" load_functions +_bootstrap_source "$_FUNC_BASE/error_handler.func" catch_errors +load_functions +catch_errors # ============================================================================== # SECTION 2: PRE-FLIGHT CHECKS & SYSTEM VALIDATION diff --git a/misc/install.func b/misc/install.func index 48d8b07be..a3bfa231d 100644 --- a/misc/install.func +++ b/misc/install.func @@ -37,8 +37,24 @@ fi # (the host is the single telemetry reporter). export TELEMETRY_CONTEXT="container" -source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/core.func) -source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/error_handler.func) +# A freshly booted container may not have DNS up yet. `source <(curl ...)` hides +# curl's exit code, so a failed download would silently source an empty stream. +_bootstrap_source() { + local url="$1" probe="$2" content + content=$(curl -fsSL --connect-timeout 10 --retry 5 --retry-connrefused --retry-delay 2 "$url") || { + echo "FATAL: failed to download ${url##*/}" >&2 + exit 115 + } + source /dev/stdin <<<"$content" + declare -f "$probe" >/dev/null 2>&1 || { + echo "FATAL: ${url##*/} loaded but incomplete (missing ${probe})" >&2 + exit 115 + } +} + +_FUNC_BASE="https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc" +_bootstrap_source "$_FUNC_BASE/core.func" load_functions +_bootstrap_source "$_FUNC_BASE/error_handler.func" catch_errors load_functions catch_errors