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
|
# 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
|
# Root Required to Write
|
||||||
# Installing over the target requires root. --dry-run deliberately does not, so the
|
# Installing over the target requires root. --dry-run deliberately does not, so the
|
||||||
# change report can be previewed by anyone.
|
# change report can be previewed by anyone.
|
||||||
@@ -148,6 +164,30 @@ done
|
|||||||
[[ -f "$TEMPLATE" ]] || { echo "Error: template not found: $TEMPLATE" >&2; exit 1; }
|
[[ -f "$TEMPLATE" ]] || { echo "Error: template not found: $TEMPLATE" >&2; exit 1; }
|
||||||
[[ -f "$TARGET" ]] || { echo "Error: target not found: $TARGET" >&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 ───────────────────────────────────────────────
|
# ── Parse target → KEY → full definition block ───────────────────────────────────────────────
|
||||||
|
|
||||||
declare -A HOST_MAP # KEY → complete definition line(s) from user's conf
|
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"
|
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
|
if [[ ${#ADDED[@]} -eq 0 && ${#REMOVED[@]} -eq 0 ]]; then
|
||||||
echo " Already up to date — no changes needed."
|
echo " Already up to date — no changes needed."
|
||||||
echo "────────────────────────────────────────────────────────────────────────"
|
echo "────────────────────────────────────────────────────────────────────────"
|
||||||
|
|||||||
@@ -580,7 +580,7 @@
|
|||||||
HOSTN_OLLAMA_URL="" # e.g. http://localhost:11434 — empty if no local Ollama
|
HOSTN_OLLAMA_URL="" # e.g. http://localhost:11434 — empty if no local Ollama
|
||||||
HOSTN_OLLAMA_CONTAINER="Ollama" # for watchdog / restart lists
|
HOSTN_OLLAMA_CONTAINER="Ollama" # for watchdog / restart lists
|
||||||
HOSTN_OLLAMA_GPU_UUID="" # pins Ollama to one card on multi-GPU hosts
|
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
|
HOSTN_OLLAMA_EMBED_MODEL="nomic-embed-text" # embeddings — the generation model cannot embed
|
||||||
|
|
||||||
# ━━━ Authelia ━━━
|
# ━━━ Authelia ━━━
|
||||||
|
|||||||
+1
-21
@@ -1,26 +1,6 @@
|
|||||||
# Varaverk AI Integration — Design Notes
|
# Varaverk AI Integration — Design Notes
|
||||||
|
|
||||||
**Status: retrieval is built; integration is not.** As of 2026-08-02 the `AI_*` and
|
**Status
|
||||||
`HOST*_OLLAMA_*` variables exist in both confs and both templates, and `AI/` holds a working
|
|
||||||
index and query path — see the RAG section at the end of this document and `AI/README-AI.md`.
|
|
||||||
|
|
||||||
Everything else below remains design only. **No Varaverk script consults AI.** Every
|
|
||||||
`AI_ASSIST_*` toggle is false, `AI_CONF_WRITE_ENABLED` is false with an empty whitelist, and
|
|
||||||
host resolution across the mesh is specified but not implemented. Originally captured
|
|
||||||
2026-08-01 so the reasoning survives.
|
|
||||||
|
|
||||||
Ollama itself *is* installed, tuned and verified on HOST1 — `qwen2.5-coder:14b` for
|
|
||||||
generation, `nomic-embed-text` for embeddings, 16k context, pinned to the RTX 3080. See
|
|
||||||
Hardware Budget for measured numbers. That is the substrate, not the integration.
|
|
||||||
|
|
||||||
**Origin:** the RTX 3080 was freed when the Windows gaming VM was retired. It is bound to the
|
|
||||||
`nvidia` driver, not `vfio` — not reserved for passthrough, so there is no VM contention to
|
|
||||||
design around. Two goals at once: somewhere to learn local LLMs, and something Varaverk can
|
|
||||||
genuinely use.
|
|
||||||
|
|
||||||
**Build order** — deliberately lowest-risk first. Each stage must be boring before the next
|
|
||||||
one starts:
|
|
||||||
|
|
||||||
1. Chat assistant / settings helper / onboarding assistant — a wrong answer costs nothing
|
1. Chat assistant / settings helper / onboarding assistant — a wrong answer costs nothing
|
||||||
2. Watchdog and discovery context — a wrong answer costs a bad suggestion, still gated
|
2. Watchdog and discovery context — a wrong answer costs a bad suggestion, still gated
|
||||||
3. Cleanup and sync decision aid — closest to destructive, last to be trusted
|
3. Cleanup and sync decision aid — closest to destructive, last to be trusted
|
||||||
|
|||||||
Reference in New Issue
Block a user