mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-13 20:30:47 +01:00
Two of the seven modules invoked python_pkg/ paths that stopped existing when screen_locker and steam_backlog_enforcer were extracted into their own repos, so the first thing the installer did on a fresh machine was fail. Nothing installed guard-lib either, which meant the CORE "Midnight shutdown timer" module always died with "guardctl not found on PATH". Every module now resolves through install_module_from_repo, and require_extracted_repo clones a missing sibling instead of only printing instructions -- otherwise "clone it yourself" is not actionable on the bare machine this script exists to set up. The clone drops privileges to the invoking human via sudo -u, because an installer that re-execs under sudo would otherwise leave a root-owned checkout in the user's home; a sandbox cannot catch that, since the guest is root throughout. A clone that fails is still a loud, fatal module failure, never a silent skip. guard-lib is addressed as the "utils" repo: it is a subdirectory of github.com/kuhyx/utils, so asking for "guard-lib" would resolve to ~/guard-lib and derive a clone URL that does not exist. It installs first, before the modules that need guardctl. Separately, the security hardening suite's screen_locker section hardcoded $HOME/testsAndMisc/python_pkg/screen_locker/screen_lock.py. That path went away with the extraction, so all five checks silently SKIPPED -- reporting a clean run for tests that never executed, which is the exact failure mode lib/extracted_repos.sh was written to prevent. It resolves the repo properly now ($HOME is also wrong under sudo), and the assertions are rewritten against the current implementation: the four symbols they grepped for no longer exist anywhere, having been replaced by SPORT_CHOICES, SPORT_TABLE_TENNIS, _validate_table_tennis and MANUAL_WORKOUT_REFLECTION_MIN_CHARS. On this host that takes the suite from 18 passed / 1 failed / 5 skipped to 23 passed / 0 skipped. The task file's "18 passed / 6 skipped out of 17" target was stale -- the suite is 24 checks now -- so it could not be matched literally. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PJrqKERAo5QUeEHWS5Asgp
170 lines
5.4 KiB
Bash
Executable File
170 lines
5.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# The migration and rollback steps for hosts-guard, plus their validation and
|
|
# status reporting.
|
|
#
|
|
# Sourced by the entry script, which owns the CLI and the instance registry.
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Preconditions
|
|
# ----------------------------------------------------------------------------
|
|
validate_requirements() {
|
|
# SYSTEMD_UNIT_DIR and PACMAN_DB_LCK default to the real locations and
|
|
# are overridden only by the test harness, which runs un-jailed in
|
|
# ci_mirror.sh and in CI where a bind mount would protect nothing.
|
|
[[ -x $GUARDCTL ]] || {
|
|
err "guardctl not found at $GUARDCTL - run guard-lib's install.sh first"
|
|
exit 1
|
|
}
|
|
|
|
local unit
|
|
for unit in guard-file@.path guard-file@.service guard-bind-mount@.service; do
|
|
[[ -f "${SYSTEMD_UNIT_DIR:-/etc/systemd/system}/$unit" ]] || {
|
|
err "missing systemd template ${SYSTEMD_UNIT_DIR:-/etc/systemd/system}/$unit - run guard-lib's install.sh first"
|
|
exit 1
|
|
}
|
|
done
|
|
|
|
[[ -d $PLUGIN_SRC_DIR ]] || {
|
|
err "plugin sources not found at $PLUGIN_SRC_DIR"
|
|
exit 1
|
|
}
|
|
|
|
# A live transaction would race every chattr and umount below.
|
|
if [[ -e "${PACMAN_DB_LCK:-/var/lib/pacman/db.lck}" ]]; then
|
|
err "${PACMAN_DB_LCK:-/var/lib/pacman/db.lck} exists - a pacman transaction is in flight"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# NOTE: the fresh-install half of this migration (installing plugins and
|
|
# registering the three file-guard instances) now also lives in hosts-blocker's
|
|
# lib/hosts_guard_setup.sh, which install.sh calls, so a fresh machine no longer
|
|
# depends on anyone running this script by hand. What stays here is the part a
|
|
# fresh machine has no use for: retiring the LEGACY hosts-guard hooks and units,
|
|
# plus --rollback/--status. The two implementations must register the same three
|
|
# instances; instance_spec below is the shared contract.
|
|
install_plugins() {
|
|
run mkdir -p "$PLUGIN_INSTALL_DIR"
|
|
local src
|
|
for src in "$PLUGIN_SRC_DIR"/*.sh; do
|
|
[[ -e $src ]] || continue
|
|
run install -m 755 "$src" "$PLUGIN_INSTALL_DIR/$(basename "$src")"
|
|
done
|
|
msg "plugins installed to $PLUGIN_INSTALL_DIR"
|
|
}
|
|
|
|
# ----------------------------------------------------------------------------
|
|
# Migration
|
|
# ----------------------------------------------------------------------------
|
|
stop_legacy_units_for() { # <instance name>
|
|
local prefix="$1"
|
|
local unit
|
|
for unit in "${LEGACY_UNITS[@]}"; do
|
|
[[ $unit == "$prefix"-* ]] || continue
|
|
systemctl list-unit-files "$unit" &>/dev/null || continue
|
|
run systemctl disable --now "$unit" 2>/dev/null || true
|
|
done
|
|
}
|
|
|
|
# Unmount every stacked bind layer so chattr can reach the real inode. Mirrors
|
|
# the legacy pacman-pre-unlock-hosts.sh, which had to do exactly this.
|
|
# Every branch is a full `if` and the function ends in an explicit `return 0`.
|
|
# The obvious `((i > 20)) && break` form leaves the loop body's exit status at 1
|
|
# whenever the arithmetic is false, and under `set -e` that aborted the whole
|
|
# rollback silently — but ONLY when the loop actually ran, so --dry-run and an
|
|
# already-unmounted target both looked fine. It cost a live /etc/hosts left with
|
|
# neither the immutable flag nor its read-only mount to notice.
|
|
collapse_mounts() { # <path>
|
|
local target="$1" i=0
|
|
while mountpoint -q "$target"; do
|
|
if ! run umount -l "$target" 2>/dev/null; then
|
|
break
|
|
fi
|
|
i=$((i + 1))
|
|
if ((i > 20)); then
|
|
break
|
|
fi
|
|
# Nothing is really unmounted under --dry-run, so `mountpoint` stays
|
|
# true forever; report the intent once instead of 20 identical lines.
|
|
if ((DRY_RUN == 1)); then
|
|
break
|
|
fi
|
|
done
|
|
return 0
|
|
}
|
|
|
|
migrate_instance() { # <name>
|
|
local name="$1"
|
|
local spec target bind plugin also_watch
|
|
spec="$(instance_spec "$name")"
|
|
IFS='|' read -r target bind plugin also_watch <<<"$spec"
|
|
|
|
if instance_registered "$name"; then
|
|
msg "$name already registered - skipping"
|
|
return 0
|
|
fi
|
|
|
|
if [[ ! -e $target ]]; then
|
|
warn "$name: target $target does not exist - skipping"
|
|
return 0
|
|
fi
|
|
|
|
note "migrating $name ($target)"
|
|
|
|
stop_legacy_units_for "$name"
|
|
collapse_mounts "$target"
|
|
run chattr -i "$target" 2>/dev/null || true
|
|
|
|
local -a args=(file-guard install "$name" --target "$target")
|
|
[[ $bind == "yes" ]] && args+=(--bind-mount)
|
|
[[ -n $plugin ]] && args+=(--plugin "$PLUGIN_INSTALL_DIR/$plugin")
|
|
[[ -n $also_watch ]] && args+=(--also-watch "$also_watch")
|
|
|
|
run "$GUARDCTL" "${args[@]}"
|
|
msg "$name migrated"
|
|
}
|
|
|
|
retire_legacy_hooks() {
|
|
local hook removed=0
|
|
for hook in "${LEGACY_HOOKS[@]}"; do
|
|
if [[ -f "$HOOKS_DIR/$hook" ]]; then
|
|
run rm -f "$HOOKS_DIR/$hook"
|
|
msg "retired $hook"
|
|
removed=1
|
|
fi
|
|
done
|
|
((removed == 0)) && msg "legacy pacman hooks already retired"
|
|
return 0
|
|
}
|
|
|
|
do_migrate() {
|
|
validate_requirements
|
|
save_rollback_state
|
|
install_plugins
|
|
|
|
local name
|
|
for name in "${INSTANCES[@]}"; do
|
|
migrate_instance "$name"
|
|
done
|
|
|
|
# Only retire the legacy hooks once guard-lib actually owns something -
|
|
# otherwise a failed migration would leave the files with NO pacman
|
|
# unlock hook at all, and the next transaction would fight chattr +i.
|
|
local registered=0
|
|
for name in "${INSTANCES[@]}"; do
|
|
instance_registered "$name" && registered=$((registered + 1))
|
|
done
|
|
|
|
if ((registered == 0)) && ((DRY_RUN == 0)); then
|
|
err "no guard-lib instance registered - refusing to retire the legacy hooks"
|
|
exit 1
|
|
fi
|
|
|
|
retire_legacy_hooks
|
|
|
|
printf "\n"
|
|
msg "migration complete ($registered instance(s) registered)"
|
|
note "verify with: sudo $SCRIPT_NAME --status"
|
|
note "undo with: sudo $SCRIPT_NAME --rollback"
|
|
}
|