#!/usr/bin/env bash # tools/cmd/railiance-preflight — pre-migration safety gate # Exit 0 = safe to proceed. Exit 1 = do NOT touch infrastructure. set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" source "${ROOT}/lib/railiance-print.sh" # ── Configuration ───────────────────────────────────────────────────────────── BACKUP_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/railiance/backups" MAX_AGE_HOURS=24 REPOS=( # OAS Stack (S1–S5) — railiance-infra/docs/adr/ADR-003 /home/worsch/railiance-infra /home/worsch/railiance-cluster /home/worsch/railiance-platform /home/worsch/railiance-enablement /home/worsch/railiance-apps # Core infrastructure /home/worsch/the-custodian # Project repos /home/worsch/markitect_project /home/worsch/activity-core /home/worsch/net-kingdom /home/worsch/issue-facade /home/worsch/binect-js /home/worsch/kaizen-agentic ) # ── Helpers ─────────────────────────────────────────────────────────────────── fail=0 pass() { ok "$1" "$2"; } fail() { bad "$1" "$2"; fail=1; } backup_age_hours() { local file="$1" echo $(( ( $(date +%s) - $(stat -c %Y "$file") ) / 3600 )) } # ── Checks ──────────────────────────────────────────────────────────────────── print_hdr "Railiance Preflight Check" # 1. DB backup freshness latest_db="$(find "${BACKUP_DIR}" -name "db-*.sql.age" 2>/dev/null | sort -r | head -1)" if [[ -z "$latest_db" ]]; then fail "db-backup" "no backup found — run: bin/railiance backup" else h="$(backup_age_hours "$latest_db")" if [[ $h -lt $MAX_AGE_HOURS ]]; then pass "db-backup" "fresh (${h}h old) — $(basename "$latest_db")" else fail "db-backup" "stale (${h}h old) — run: bin/railiance backup" fi fi # 2. Config backup freshness latest_cfg="$(find "${BACKUP_DIR}" -name "config-*.tar.gz.age" 2>/dev/null | sort -r | head -1)" if [[ -z "$latest_cfg" ]]; then fail "cfg-backup" "no backup found — run: bin/railiance backup" else h="$(backup_age_hours "$latest_cfg")" if [[ $h -lt $MAX_AGE_HOURS ]]; then pass "cfg-backup" "fresh (${h}h old)" else fail "cfg-backup" "stale (${h}h old) — run: bin/railiance backup" fi fi # 3. Git repo state for repo in "${REPOS[@]}"; do name="$(basename "$repo")" if [[ ! -d "$repo/.git" ]]; then fail "git:${name}" "not a git repo at ${repo}" continue fi if ! git -C "$repo" diff --quiet 2>/dev/null || \ ! git -C "$repo" diff --cached --quiet 2>/dev/null; then fail "git:${name}" "uncommitted changes" elif [[ -n "$(git -C "$repo" log --oneline '@{u}..' 2>/dev/null || true)" ]]; then fail "git:${name}" "unpushed commits" else pass "git:${name}" "clean and pushed" fi done # 4. age key present if [[ -f "${HOME}/.config/age/railiance-backup.key" ]]; then pass "age-key" "present at ~/.config/age/railiance-backup.key" else fail "age-key" "missing — run: age-keygen -o ~/.config/age/railiance-backup.key" fi # ── Summary ─────────────────────────────────────────────────────────────────── echo if [[ $fail -eq 0 ]]; then ok "PREFLIGHT" "all checks passed — safe to proceed" exit 0 else bad "PREFLIGHT" "checks failed — do NOT proceed with infrastructure work" exit 1 fi