Bring script headers onto the template and close safeguard gaps

Headers claimed protections the code never had, and several destructive paths had no
guard against a collapsed config value.
This commit is contained in:
Gmer4Lfe
2026-08-01 20:37:59 -04:00
parent cdce877601
commit e8b114094a
78 changed files with 3301 additions and 277 deletions
+38 -8
View File
@@ -74,6 +74,28 @@
# Root Enforcement
# Docker operations require root privileges.
#
# Docker Presence Check
# Verifies the docker binary exists before execution.
#
# Docker Daemon Check
# Verifies the daemon is responsive before container discovery. Remainder mode
# derives its entire target list from docker ps — against a hung daemon that
# returns empty and the run silently reports "no containers to update".
#
# Timeout Protection
# Inspect, discovery and image-query commands are wrapped in a timeout so a
# hung daemon cannot stall the maintenance window. docker pull is deliberately
# NOT wrapped — a large image legitimately takes longer than any sane timeout,
# and killing it mid-layer wastes the transfer.
#
# Empty List Guards
# Each mode exits cleanly with a pointer to the relevant conf key when its
# container list is unconfigured for this host.
#
# Rebuild Failure Fallback
# A container that fails to rebuild is excluded from the rebuilt-list handoff
# file, so the follow-up restart script still gives it a normal restart pass.
#
# DAILY_CONTAINER_UPDATES / WEEKLY_CONTAINER_UPDATES Toggles
# Each mode exits cleanly when disabled. Restart scripts run regardless —
# update and restart are independent operations.
@@ -192,6 +214,14 @@ fi
detect_hosts
# Remainder mode builds its whole target list from docker ps — a hung daemon returns
# empty and the run would report "no containers to update" instead of failing.
if ! timeout "$DOCKER_TIMEOUT" docker info >/dev/null 2>&1; then
error "Docker daemon not responding — skipping image updates"
notify "Docker update skipped on $(hostname) — Docker daemon not responding" "Docker Update" "warning"
exit 1
fi
# ==============================================================================================
# ━━━ Container Discovery ━━━
# ==============================================================================================
@@ -234,7 +264,7 @@ if [[ "$REMAINDER_MODE" == true ]]; then
done
unset _tier _tier_var _tier_arr _c
mapfile -t _all_running < <(docker ps --format '{{.Names}}' | sort)
mapfile -t _all_running < <(timeout "$DOCKER_TIMEOUT" docker ps --format '{{.Names}}' | sort)
TARGET_CONTAINERS=()
for _c in "${_all_running[@]}"; do
[[ -z "${_exclude[$_c]+x}" ]] && TARGET_CONTAINERS+=("$_c")
@@ -328,13 +358,13 @@ for container in "${TARGET_CONTAINERS[@]}"; do
[[ -z "$container" ]] && continue
log "━━━ $ICON_CONTAINERS $container ━━━"
if ! docker inspect "$container" &>/dev/null; then
if ! timeout "$DOCKER_TIMEOUT" docker inspect "$container" &>/dev/null; then
warn "$container — not found, skipping"
SKIPPED+=("$container")
continue
fi
IMAGE=$(docker inspect --format='{{.Config.Image}}' "$container" 2>/dev/null)
IMAGE=$(timeout "$DOCKER_TIMEOUT" docker inspect --format='{{.Config.Image}}' "$container" 2>/dev/null)
if [[ -z "$IMAGE" ]]; then
warn "$container — could not determine image, skipping"
SKIPPED+=("$container")
@@ -352,8 +382,8 @@ for container in "${TARGET_CONTAINERS[@]}"; do
# Capture the image ID the container is currently running on, and the
# image ID :latest points to before the pull. After pulling, we rebuild if
# either a new digest landed OR the container is behind what :latest is now.
CONTAINER_IMAGE_ID=$(docker inspect "$container" --format='{{.Image}}' 2>/dev/null || echo "")
OLD_ID=$(docker image inspect "$IMAGE" --format='{{.Id}}' 2>/dev/null || echo "")
CONTAINER_IMAGE_ID=$(timeout "$DOCKER_TIMEOUT" docker inspect "$container" --format='{{.Image}}' 2>/dev/null || echo "")
OLD_ID=$(timeout "$DOCKER_TIMEOUT" docker image inspect "$IMAGE" --format='{{.Id}}' 2>/dev/null || echo "")
log "$ICON_SYNC Pulling $IMAGE..."
if [[ "$ENABLE_LOGGING" == "true" ]]; then
@@ -363,7 +393,7 @@ for container in "${TARGET_CONTAINERS[@]}"; do
docker pull "$IMAGE" >/dev/null 2>&1
_pull_rc=$?
fi
NEW_ID=$(docker image inspect "$IMAGE" --format='{{.Id}}' 2>/dev/null || echo "")
NEW_ID=$(timeout "$DOCKER_TIMEOUT" docker image inspect "$IMAGE" --format='{{.Id}}' 2>/dev/null || echo "")
if [[ $_pull_rc -eq 0 ]]; then
_pull_new=$( [[ -n "$OLD_ID" && "$OLD_ID" != "$NEW_ID" ]] && echo true || echo false)
@@ -436,9 +466,9 @@ if [[ "$DRY_RUN" == true ]]; then
PRUNED_SUMMARY="(dry run)"
else
for _old_id in "${OLD_IMAGE_IDS[@]}"; do
docker rmi "$_old_id" >/dev/null 2>&1 || true
timeout "$DOCKER_TIMEOUT" docker rmi "$_old_id" >/dev/null 2>&1 || true
done
PRUNED_OUTPUT=$(docker image prune -f 2>&1)
PRUNED_OUTPUT=$(timeout "$DOCKER_TIMEOUT" docker image prune -f 2>&1)
[[ "$ENABLE_LOGGING" == "true" ]] && echo "$PRUNED_OUTPUT" | sed 's/^/ /'
PRUNED_SUMMARY=$(echo "$PRUNED_OUTPUT" | grep -E "^Total reclaimed" || echo "nothing reclaimed")
fi