#!/usr/bin/env bash # tools/cmd/railiance-backup — backup custodian state to Nextcloud file drop set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" source "${ROOT}/lib/railiance-print.sh" # ── Configuration ───────────────────────────────────────────────────────────── AGE_PUBLIC_KEY="age1zvryunvjhvpkmasskauga2heeg0ztnte9ymgppvjge36ekumk50syr3tsz" BAO_PATH="platform/workloads/railiance/backup/offsite-lane" NC_WEBDAV_URL="${RAILIANCE_BACKUP_NC_WEBDAV_URL:-}" NC_TOKEN="${RAILIANCE_BACKUP_NC_TOKEN:-}" if [[ -z "${NC_TOKEN}" || -z "${NC_WEBDAV_URL}" ]] && command -v bao >/dev/null 2>&1; then if bao kv metadata get "${BAO_PATH}" >/dev/null 2>&1; then NC_TOKEN="$(bao kv get -field=NC_WEBDAV_TOKEN "${BAO_PATH}")" NC_WEBDAV_URL="$(bao kv get -field=NC_WEBDAV_URL "${BAO_PATH}")" fi fi : "${NC_WEBDAV_URL:=https://nx4069.your-storageshare.de/public.php/webdav}" if [[ -z "${NC_TOKEN}" ]]; then bad "credentials" "set RAILIANCE_BACKUP_NC_TOKEN or: bao login -method=oidc -path=netkingdom role=railiance-backup-workload-kv-read" exit 1 fi PG_CONTAINER="infra-postgres-1" PG_USER="custodian" PG_DB="custodian" BACKUP_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/railiance/backups" TS="$(date -u +%Y%m%dT%H%M%SZ)" # ── Helpers ─────────────────────────────────────────────────────────────────── nc_upload() { local file="$1" name="$2" curl -sf -u "${NC_TOKEN}:" -T "$file" "${NC_WEBDAV_URL}/${name}" \ || { bad "upload" "failed to upload ${name}"; exit 1; } } # ── Main ────────────────────────────────────────────────────────────────────── mkdir -p "$BACKUP_DIR" print_hdr "Railiance Backup — ${TS}" # 1. PostgreSQL ok "postgres" "dumping ${PG_DB}…" TMP_DB="${BACKUP_DIR}/db-${TS}.sql.age" docker exec "${PG_CONTAINER}" pg_dump -U "${PG_USER}" "${PG_DB}" \ | age -r "${AGE_PUBLIC_KEY}" -o "${TMP_DB}" ok "postgres" "encrypted → $(basename "$TMP_DB")" nc_upload "${TMP_DB}" "db-${TS}.sql.age" ok "postgres" "uploaded to Nextcloud" # 2. Config snapshot ok "config" "snapshotting ~/.claude/ ~/.claude.json .gitconfig…" TMP_CFG_TAR="${BACKUP_DIR}/config-${TS}.tar.gz" TMP_CFG="${BACKUP_DIR}/config-${TS}.tar.gz.age" tar -czf "${TMP_CFG_TAR}" \ -C "$HOME" \ --ignore-failed-read \ .claude \ .claude.json \ .gitconfig \ 2>/dev/null || true age -r "${AGE_PUBLIC_KEY}" -o "${TMP_CFG}" "${TMP_CFG_TAR}" rm -f "${TMP_CFG_TAR}" ok "config" "encrypted → $(basename "$TMP_CFG")" nc_upload "${TMP_CFG}" "config-${TS}.tar.gz.age" ok "config" "uploaded to Nextcloud" # 3. Prune local cache (keep last 7 of each type) find "${BACKUP_DIR}" -name "db-*.sql.age" | sort -r | tail -n +8 | xargs -r rm -f find "${BACKUP_DIR}" -name "config-*.tar.gz.age" | sort -r | tail -n +8 | xargs -r rm -f ok "cache" "local copies pruned (keep last 7)" # 4. Write stamp (preflight reads this) echo "${TS}" > "${BACKUP_DIR}/.last-backup" echo ok "done" "Backup complete — ${TS}" echo " DB: db-${TS}.sql.age" echo " Config: config-${TS}.tar.gz.age" echo echo " ⚠️ The age private key at ~/.config/age/railiance-backup.key" echo " MUST also be stored in your password manager or written down." echo " Without it you cannot decrypt these backups."