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:
@@ -25,6 +25,21 @@
|
||||
# works whether the remote is in internal or appdata storage mode.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# OPERATIONAL MODEL
|
||||
# ==============================================================================================
|
||||
#
|
||||
# 1. Gates — PARTNERSHIP_ENABLED, CONF_SYNC_ENABLED
|
||||
# 2. Cache own conf into the local RAM cache (skipped in --push-only / --pull-only)
|
||||
# 3. Per partner:
|
||||
# a. Resolve the partner's own SCRIPTS_DIR by reading their varaverk.cfg over SSH,
|
||||
# so a partner in appdata storage mode is still found
|
||||
# b. Pull — scp their host*.conf from their disk into our RAM cache
|
||||
# c. Push — scp our host*.conf into their RAM cache
|
||||
# A partner that fails SSH is counted and skipped; the others still sync.
|
||||
#
|
||||
# Every file written locally or remotely is restricted to 600, in a 700 directory.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# DESIGN PRINCIPLES
|
||||
# ==============================================================================================
|
||||
#
|
||||
@@ -42,10 +57,65 @@
|
||||
# OPERATIONAL SAFEGUARDS
|
||||
# ==============================================================================================
|
||||
#
|
||||
# require_partnership — exits early if PARTNERSHIP_ENABLED=false
|
||||
# detect_hosts() — partner list for push/pull routing
|
||||
# acquire_lock — prevents concurrent sync runs
|
||||
# SSH reachability — partners that fail SSH are skipped, not fatal
|
||||
# Root Enforcement
|
||||
# Reads the on-disk conf and writes the RAM cache; SSH/scp run as root.
|
||||
#
|
||||
# Lock Acquisition
|
||||
# acquire_lock prevents concurrent sync runs writing the same cache files.
|
||||
#
|
||||
# Partnership Gate
|
||||
# require_partnership exits early if PARTNERSHIP_ENABLED=false.
|
||||
#
|
||||
# CONF_SYNC_ENABLED Gate
|
||||
# Exits cleanly when disabled, without removing it from the schedule.
|
||||
#
|
||||
# Host Detection
|
||||
# detect_hosts() builds the partner list used for push/pull routing.
|
||||
#
|
||||
# SSH Reachability
|
||||
# Partners that fail SSH are counted and skipped, never fatal — one unreachable
|
||||
# partner does not prevent the others from syncing.
|
||||
#
|
||||
# SSH Timeouts
|
||||
# Every ssh and scp call is wrapped in timeout with ConnectTimeout and BatchMode,
|
||||
# so an unresponsive or password-prompting partner cannot stall the run.
|
||||
#
|
||||
# Remote Path Discovery
|
||||
# The partner's SCRIPTS_DIR is read from their own varaverk.cfg rather than assumed,
|
||||
# so a partner in appdata storage mode is still found. Falls back to the default
|
||||
# plugin path if the file cannot be read.
|
||||
#
|
||||
# Credential File Permissions
|
||||
# Cache directories are created 700 and every conf written 600 — on both ends. These
|
||||
# files carry NPM/lldap passwords and API keys, and the cache lives under a
|
||||
# world-readable /tmp path. The pushed copy is chmod'd on the partner too, since our
|
||||
# own credentials land on their disk.
|
||||
#
|
||||
# Dry Run Support
|
||||
# --dry-run reports every pull and push without transferring anything.
|
||||
#
|
||||
# ==============================================================================================
|
||||
# CONFIGURATION
|
||||
# ==============================================================================================
|
||||
#
|
||||
# master.conf
|
||||
#
|
||||
# CONF_SYNC_ENABLED
|
||||
# Master toggle for conf syncing (default: true)
|
||||
#
|
||||
# CONF_RAM_CACHE_DIR
|
||||
# tmpfs cache both ends read partner vars from (/tmp/.cache/vv/d). Cleared every
|
||||
# reboot, which is why conf_cache_save.sh / conf_cache_restore.sh exist.
|
||||
#
|
||||
# SSH_KEY
|
||||
# Key used for all partner ssh/scp operations
|
||||
#
|
||||
# PARTNERSHIP_ENABLED
|
||||
# Checked via require_partnership()
|
||||
#
|
||||
# host*.conf
|
||||
#
|
||||
# HOST* — hostnames used to build the partner list via detect_hosts()
|
||||
#
|
||||
# ==============================================================================================
|
||||
# RUNTIME MODES
|
||||
@@ -73,6 +143,14 @@ for arg in "$@"; do
|
||||
esac
|
||||
done
|
||||
parse_args "${FILTERED_ARGS[@]}"
|
||||
|
||||
if [[ "$EUID" -ne 0 ]]; then
|
||||
error "Must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
acquire_lock
|
||||
|
||||
detect_hosts
|
||||
require_partnership
|
||||
|
||||
@@ -105,7 +183,10 @@ _remote_scripts_dir() {
|
||||
|
||||
# ── Ensure cache dir exists ───────────────────────────────────────────────────
|
||||
if [[ "$DRY_RUN" == false ]]; then
|
||||
mkdir -p "$CACHE_DIR"
|
||||
# These conf files carry credentials (NPM/lldap passwords, API keys). The cache lives in
|
||||
# a world-readable /tmp path, so the directory and every file written into it below are
|
||||
# restricted explicitly rather than left at the default umask.
|
||||
mkdir -p "$CACHE_DIR" && chmod 700 "$CACHE_DIR"
|
||||
fi
|
||||
|
||||
# ── Copy own conf into local cache ───────────────────────────────────────────
|
||||
@@ -114,8 +195,12 @@ if [[ "$PUSH_ONLY" == false ]] && [[ "$PULL_ONLY" == false ]]; then
|
||||
if [[ "$DRY_RUN" == true ]]; then
|
||||
warn "DRY RUN — would copy $(basename "$MY_CONF") → $CACHE_DIR/"
|
||||
else
|
||||
cp "$MY_CONF" "$CACHE_DIR/${MY_ID,,}.conf" && \
|
||||
echo "Own conf cached ✅" || warn "Failed to cache own conf"
|
||||
if cp "$MY_CONF" "$CACHE_DIR/${MY_ID,,}.conf" && \
|
||||
chmod 600 "$CACHE_DIR/${MY_ID,,}.conf"; then
|
||||
echo "Own conf cached ✅"
|
||||
else
|
||||
warn "Failed to cache own conf"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
warn "Own conf not found: $MY_CONF"
|
||||
@@ -151,6 +236,7 @@ for host_var in $(compgen -v | grep -E '^HOST[0-9]+$' | sort); do
|
||||
-o ConnectTimeout="$SSH_TIMEOUT" -o BatchMode=yes -o StrictHostKeyChecking=no \
|
||||
"root@${partner_ip}:${remote_conf}" \
|
||||
"$CACHE_DIR/${partner_slot}.conf" 2>/dev/null; then
|
||||
chmod 600 "$CACHE_DIR/${partner_slot}.conf" 2>/dev/null
|
||||
echo "Pulled ${partner_slot}.conf from $partner_host ✅"
|
||||
(( PULLED++ ))
|
||||
else
|
||||
@@ -172,12 +258,16 @@ for host_var in $(compgen -v | grep -E '^HOST[0-9]+$' | sort); do
|
||||
# Ensure partner's cache dir exists, then SCP own conf into it
|
||||
timeout "$SSH_TIMEOUT" ssh -i "$SSH_KEY" \
|
||||
-o ConnectTimeout="$SSH_TIMEOUT" -o BatchMode=yes -o StrictHostKeyChecking=no \
|
||||
"root@${partner_ip}" "mkdir -p '$CACHE_DIR'" 2>/dev/null
|
||||
"root@${partner_ip}" "mkdir -p '$CACHE_DIR' && chmod 700 '$CACHE_DIR'" 2>/dev/null
|
||||
|
||||
if timeout "$SSH_TIMEOUT" scp -i "$SSH_KEY" \
|
||||
-o ConnectTimeout="$SSH_TIMEOUT" -o BatchMode=yes -o StrictHostKeyChecking=no \
|
||||
"$MY_CONF" \
|
||||
"root@${partner_ip}:${CACHE_DIR}/${MY_ID,,}.conf" 2>/dev/null; then
|
||||
# Our own conf lands on the partner carrying our credentials — restrict it there too.
|
||||
timeout "$SSH_TIMEOUT" ssh -i "$SSH_KEY" \
|
||||
-o ConnectTimeout="$SSH_TIMEOUT" -o BatchMode=yes -o StrictHostKeyChecking=no \
|
||||
"root@${partner_ip}" "chmod 600 '${CACHE_DIR}/${MY_ID,,}.conf'" 2>/dev/null
|
||||
echo "Pushed ${MY_ID,,}.conf to $partner_host ✅"
|
||||
(( PUSHED++ ))
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user