Refuse a conf_upgrade that would keep nothing
Merging the raw host.conf.template against a live host conf matched HOSTN_ against HOST1_, classified all 140 real keys as deprecated and would have removed every credential on the host. Also points the Ollama model default at a tag that still exists.
This commit is contained in:
@@ -69,6 +69,22 @@
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
# ==============================================================================================
|
||||
#
|
||||
# Unsubstituted HOSTN Placeholders Are Refused
|
||||
# host.conf.template ships HOSTN_ placeholders; a live host conf uses HOST1_ / HOST2_. Key
|
||||
# matching is literal, so merging the raw template against a real host conf classifies every
|
||||
# existing key as deprecated — KEPT 0 — and the install drops every credential in the file.
|
||||
# Verified on HOST1 2026-08-02: it would have removed HOST1_RADARR_API_KEY,
|
||||
# HOST1_EMBY_API_KEY, HOST1_NPM_PASS and 137 others. The template is checked for HOSTN and
|
||||
# the target for a HOST<n> slot; if both are present the run aborts and prints the exact sed
|
||||
# command to substitute. Refused rather than auto-substituted — this rewrites the file holding
|
||||
# every secret on the host, and inferring the slot is not worth being wrong about.
|
||||
#
|
||||
# Total Mismatch Is Refused
|
||||
# Keeping nothing from a populated conf is never a real upgrade; it means the two files do
|
||||
# not describe the same thing. KEPT 0 with a non-empty REMOVED list aborts. This is the
|
||||
# general net behind the HOSTN check — the failure mode is silent and total, so it fires in
|
||||
# --dry-run as well, putting the warning in the report itself.
|
||||
#
|
||||
# Root Required to Write
|
||||
# Installing over the target requires root. --dry-run deliberately does not, so the
|
||||
# change report can be previewed by anyone.
|
||||
@@ -148,6 +164,30 @@ done
|
||||
[[ -f "$TEMPLATE" ]] || { echo "Error: template not found: $TEMPLATE" >&2; exit 1; }
|
||||
[[ -f "$TARGET" ]] || { echo "Error: target not found: $TARGET" >&2; exit 1; }
|
||||
|
||||
# ── Guard: unsubstituted HOSTN placeholders ──────────────────────────────────────────────────
|
||||
#
|
||||
# host.conf.template ships HOSTN_ placeholders; a live host conf uses HOST1_ / HOST2_. Key
|
||||
# matching below is literal, so merging the raw template against a real host conf classifies
|
||||
# EVERY existing key as deprecated and every template key as new — KEPT 0, and the install
|
||||
# would drop every credential in the file. api/setup.php substitutes before writing; a direct
|
||||
# invocation has no such step. Refused rather than auto-substituted: this rewrites the file
|
||||
# that holds every secret on the host, and guessing the slot is not worth being wrong about.
|
||||
if grep -q 'HOSTN' "$TEMPLATE" 2>/dev/null; then
|
||||
_slot=$(grep -oEm1 '^[[:space:]]*(HOST[0-9]+)_' "$TARGET" 2>/dev/null | grep -oE 'HOST[0-9]+')
|
||||
if [[ -n "$_slot" ]]; then
|
||||
_lower=$(echo "$_slot" | tr '[:upper:]' '[:lower:]')
|
||||
echo "Error: template still contains HOSTN placeholders, but the target uses ${_slot}_." >&2
|
||||
echo " Merging as-is would classify all ${_slot}_ keys as deprecated and remove" >&2
|
||||
echo " them — including every credential. Substitute the slot first:" >&2
|
||||
echo "" >&2
|
||||
echo " sed -e 's/HOSTN/${_slot}/g' -e 's/hostn/${_lower}/g' \\" >&2
|
||||
echo " $TEMPLATE > /tmp/${_lower}.conf.template" >&2
|
||||
echo " $0 --template /tmp/${_lower}.conf.template --target $TARGET --dry-run" >&2
|
||||
echo "" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# ── Parse target → KEY → full definition block ───────────────────────────────────────────────
|
||||
|
||||
declare -A HOST_MAP # KEY → complete definition line(s) from user's conf
|
||||
@@ -268,6 +308,24 @@ fi
|
||||
|
||||
echo " KEPT ${#KEPT[@]} existing vars — your values preserved"
|
||||
|
||||
# ── Guard: total mismatch ────────────────────────────────────────────────────────────────────
|
||||
#
|
||||
# Keeping nothing from a populated conf is never a real upgrade — it is the signature of the
|
||||
# two files not describing the same thing (wrong template, wrong target, unsubstituted
|
||||
# placeholders). The HOSTN check above catches the known cause; this catches the rest, because
|
||||
# the failure mode is silent and total: every value in the file is replaced by a default.
|
||||
# Deliberately fires in --dry-run too, so the report itself carries the warning.
|
||||
if [[ ${#KEPT[@]} -eq 0 && ${#REMOVED[@]} -gt 0 ]]; then
|
||||
echo "────────────────────────────────────────────────────────────────────────"
|
||||
echo ""
|
||||
echo "Error: refusing — this would keep NOTHING and remove all ${#REMOVED[@]} existing keys." >&2
|
||||
echo " A genuine upgrade preserves values; keeping zero means the template and the" >&2
|
||||
echo " target do not describe the same conf. Check that --template matches --target" >&2
|
||||
echo " and that any HOSTN placeholders were substituted for this host's slot." >&2
|
||||
echo "" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ${#ADDED[@]} -eq 0 && ${#REMOVED[@]} -eq 0 ]]; then
|
||||
echo " Already up to date — no changes needed."
|
||||
echo "────────────────────────────────────────────────────────────────────────"
|
||||
|
||||
@@ -580,7 +580,7 @@
|
||||
HOSTN_OLLAMA_URL="" # e.g. http://localhost:11434 — empty if no local Ollama
|
||||
HOSTN_OLLAMA_CONTAINER="Ollama" # for watchdog / restart lists
|
||||
HOSTN_OLLAMA_GPU_UUID="" # pins Ollama to one card on multi-GPU hosts
|
||||
HOSTN_OLLAMA_MODEL="qwen2.5-coder:14b" # generation
|
||||
HOSTN_OLLAMA_MODEL="hf.co/unsloth/Qwen3-14B-GGUF:IQ4_XS" # generation — must fully offload; see README-AI.md
|
||||
HOSTN_OLLAMA_EMBED_MODEL="nomic-embed-text" # embeddings — the generation model cannot embed
|
||||
|
||||
# ━━━ Authelia ━━━
|
||||
|
||||
Reference in New Issue
Block a user