From cb1c27f9b583bef461fb36e7fd47d84ee9db7530 Mon Sep 17 00:00:00 2001 From: MickLesk <47820557+MickLesk@users.noreply.github.com> Date: Sun, 11 Oct 2026 14:44:17 +0200 Subject: [PATCH 1/2] Add confirm_external_installer Fifteen install and update paths across ProxmoxVE and Incus carry the same block that warns before running a third-party installer and reads a yes from the terminal. An unattended run had no way to answer it, and prompt_confirm would take its default without asking in every non-advanced mode. var_external_installer now answers it; unset still asks, no terminal declines with a hint. --- .github/workflows/verify-split-files.yml | 5 +++ core/core.func | 28 ++++++++++++++ tests/external-installer.sh | 48 ++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 tests/external-installer.sh diff --git a/.github/workflows/verify-split-files.yml b/.github/workflows/verify-split-files.yml index d6dfae7..91ad66f 100644 --- a/.github/workflows/verify-split-files.yml +++ b/.github/workflows/verify-split-files.yml @@ -28,6 +28,7 @@ on: - "tests/mongodb-upgrade.sh" - "tests/uv-required-version.sh" - "tests/docker-lxcfs.sh" + - "tests/external-installer.sh" - ".github/workflows/verify-split-files.yml" push: branches: [main] @@ -47,6 +48,7 @@ on: - "tests/mongodb-upgrade.sh" - "tests/uv-required-version.sh" - "tests/docker-lxcfs.sh" + - "tests/external-installer.sh" - ".github/workflows/verify-split-files.yml" workflow_dispatch: @@ -86,6 +88,9 @@ jobs: - name: Docker lxcfs visibility regression tests run: bash tests/docker-lxcfs.sh + - name: External installer confirmation tests + run: bash tests/external-installer.sh + - name: Prefetch lists cover every engine file run: | set -euo pipefail diff --git a/core/core.func b/core/core.func index 5be2adc..2afa60a 100644 --- a/core/core.func +++ b/core/core.func @@ -1836,6 +1836,34 @@ prompt_confirm() { fi } +# ------------------------------------------------------------------------------ +# confirm_external_installer() +# +# confirm_external_installer +# +# - Warns that a third-party installer is about to run and asks to continue +# - var_external_installer answers it, so unattended runs can say yes or no. +# prompt_confirm is no use here: it takes its default without asking in +# every non-advanced mode, and the default has to be no +# - Exits 10 when declined +# ------------------------------------------------------------------------------ +confirm_external_installer() { + local source="$1" installer="$2" answer="${var_external_installer:-}" + msg_warn "WARNING: This script will run an external installer from a third-party source (${source})." + msg_warn "The following code is NOT maintained or audited by our repository." + msg_warn "If you have any doubts or concerns, please review the installer code before proceeding:" + msg_custom "${TAB3}${GATEWAY}${BGN}${CL}" "\e[1;34m" "→ ${installer}" + echo + if [[ -z "$answer" ]] && ! read -r -p "${TAB3}Do you want to continue? [y/N]: " answer; then + msg_error "No terminal to confirm on. Set var_external_installer=yes to run it unattended." + exit 10 + fi + if [[ ! "${answer,,}" =~ ^(y|yes|true)$ ]]; then + msg_error "Aborted by user. No changes have been made." + exit 10 + fi +} + # ------------------------------------------------------------------------------ # prompt_input() # diff --git a/tests/external-installer.sh b/tests/external-installer.sh new file mode 100644 index 0000000..8a4d12e --- /dev/null +++ b/tests/external-installer.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +set -euo pipefail + +CORE_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" +eval "$(awk '/^confirm_external_installer\(\) \{/,/^}/' "$CORE_DIR/core/core.func")" + +msg_warn() { :; } +msg_custom() { :; } +msg_error() { echo "$*" >&2; } +# shellcheck disable=SC2034 # read by the eval'd helper +TAB3="" GATEWAY="" BGN="" CL="" +passed=0 failed=0 + +check() { + if [[ "$3" == "$2" ]]; then + echo "PASS $1" + passed=$((passed + 1)) + else + echo "FAIL $1: expected <$2>, got <$3>" >&2 + failed=$((failed + 1)) + fi +} +# exit code of one call; $1 is var_external_installer, $2 what the user types +run() { + local rc=0 + (var_external_installer="$1" confirm_external_installer src url) <<<"$2" >/dev/null 2>&1 || rc=$? + echo "$rc" +} +# no stdin at all, as in an unattended run without the variable +run_eof() { + local rc=0 + (var_external_installer="" confirm_external_installer src url) /dev/null 2>&1 || rc=$? + echo "$rc" +} + +check "var yes" 0 "$(run yes "")" +check "var YES" 0 "$(run YES "")" +check "var true" 0 "$(run true "")" +check "var no" 10 "$(run no "y")" +check "var wins over input" 10 "$(run no "yes")" +check "typed y" 0 "$(run "" y)" +check "typed Yes" 0 "$(run "" Yes)" +check "typed n" 10 "$(run "" n)" +check "just enter" 10 "$(run "" "")" +check "no stdin" 10 "$(run_eof)" + +printf '%s passed, %s failed\n' "$passed" "$failed" +((failed == 0)) From f8869ffbb961cf3dcfd56e0d1545ddc6dacb7e9c Mon Sep 17 00:00:00 2001 From: MickLesk <47820557+MickLesk@users.noreply.github.com> Date: Sun, 11 Oct 2026 14:57:16 +0200 Subject: [PATCH 2/2] List confirm_external_installer in ui/API.txt build-ui.func loads core.func, so its snapshot carries the new helper. --- ui/API.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/API.txt b/ui/API.txt index f78ee3f..49b694b 100644 --- a/ui/API.txt +++ b/ui/API.txt @@ -78,6 +78,7 @@ color color_spinner configure_http_proxy configure_ssh_settings +confirm_external_installer confirm_not_pve_host cs_testing_state default_var_settings