← back to Nas Setup
scripts/install-root-daemon.sh
98 lines
#!/bin/bash
# install-root-daemon.sh — one-paste, run as root:
# sudo bash /Users/macstudio3/Projects/nas-setup/scripts/install-root-daemon.sh
#
# Converts the realestate on-prem dump mirror from a user LaunchAgent (which EPERM'd on
# /Volumes/Henry because macOS TCC won't honor Full Disk Access on the SIP bash responsible
# process for launchd) to a root LaunchDaemon (runs outside the per-user TCC consent domain).
#
# Self-diagnosing + idempotent:
# 1. PROBE — can root write to /Volumes/Henry? If NOT, root is TCC-gated too → bail, Option B
# doesn't help, no infra installed. If yes, continue.
# 2. SSH — give root its own copy of the Kamatera key (/var/root/.ssh) + config.
# 3. RUN — execute the pull once as root, end-to-end, and show the result.
# 4. INSTALL— drop the LaunchDaemon into /Library/LaunchDaemons, bootstrap it into system/.
# 5. RETIRE — bootout the old user LaunchAgent so the two don't both run.
# Re-running is safe (overwrites its own artifacts, re-bootstraps).
set -uo pipefail
USER_HOME=/Users/macstudio3
NAS=$USER_HOME/Projects/nas-setup
HENRY=/Volumes/Henry/dw-backups/realestate
KEY=id_ed25519_wallco_20260530
LABEL=com.steve.nas-realestate-dump-mirror
ROOT_LABEL=$LABEL-root
DAEMON_SRC=$NAS/launchd/$ROOT_LABEL.plist
DAEMON_DST=/Library/LaunchDaemons/$ROOT_LABEL.plist
say(){ printf '\n=== %s ===\n' "$1"; }
if [ "$(id -u)" -ne 0 ]; then echo "must run as root: sudo bash $0"; exit 1; fi
# ── 1. PROBE: can root write to the external volume? (the decisive TCC test) ──
say "1. probe: root write to /Volumes/Henry"
mkdir -p "$HENRY" 2>/dev/null
PROBE="$HENRY/.root-tcc-probe.$$"
if touch "$PROBE" 2>/tmp/root-probe.err; then
rm -f "$PROBE"
echo "OK — root CAN write to Henry. TCC does not gate the system LaunchDaemon domain here. Proceeding."
else
echo "BLOCKED — root is ALSO TCC-gated on /Volumes/Henry:"
cat /tmp/root-probe.err
echo
echo "=> Option B (root daemon) does NOT bypass TCC on this box. Nothing was installed."
echo " Fall back to Option A: grant Full Disk Access to /opt/homebrew/bin/bash in System Settings."
exit 2
fi
# ── 2. SSH: give root its own copy of the Kamatera key + config ──
say "2. root ssh setup (/var/root/.ssh)"
install -d -m 700 /var/root/.ssh
install -m 600 "$USER_HOME/.ssh/$KEY" /var/root/.ssh/$KEY
cat > /var/root/.ssh/config <<CFG
Host 45.61.58.125
HostName 45.61.58.125
User root
IdentityFile /var/root/.ssh/$KEY
IdentitiesOnly yes
StrictHostKeyChecking accept-new
UserKnownHostsFile /var/root/.ssh/known_hosts
CFG
chmod 600 /var/root/.ssh/config
if HOME=/var/root ssh -o BatchMode=yes -o ConnectTimeout=15 root@45.61.58.125 "echo ok" >/dev/null 2>&1; then
echo "OK — root authenticates to Kamatera."
else
echo "WARN — root ssh test to Kamatera failed; the daemon run below will surface the error."
fi
# ── 3. RUN once as root, end-to-end ──
say "3. run the pull once as root"
HOME=/var/root \
HENRY_BACKUP_DIR="$HENRY" \
NAS_BACKUP_DIR=/Volumes/DW-Backups/realestate \
PGDUMP_GLOB='/root/backups/db/realestate_*.dump' \
PGDUMP_FLOOR_MB=1 PGDUMP_TOC_FLOOR=5 \
PATH=/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin \
/opt/homebrew/bin/bash "$NAS/scripts/pull-dw-dump.sh"
RUN_RC=$?
echo "pull exit rc=$RUN_RC (0 = a destination verified)"
# ── 4. INSTALL the LaunchDaemon ──
say "4. install + bootstrap the root LaunchDaemon"
install -m 644 -o root -g wheel "$DAEMON_SRC" "$DAEMON_DST"
launchctl bootout system/$ROOT_LABEL 2>/dev/null
launchctl bootstrap system "$DAEMON_DST" && echo "bootstrapped $ROOT_LABEL into system/"
launchctl print system/$ROOT_LABEL >/dev/null 2>&1 && echo "loaded OK (runs daily 03:50 as root)"
# ── 5. RETIRE the old user LaunchAgent so both don't run ──
say "5. retire the old user LaunchAgent"
launchctl bootout gui/501/$LABEL 2>/dev/null && echo "booted out user agent gui/501/$LABEL"
# disable it from auto-reloading on next login (leave the plist file in place, just disabled)
launchctl disable gui/501/$LABEL 2>/dev/null || true
echo "user agent disabled (plist left on disk, no longer loads)"
say "DONE"
echo "Latest on Henry:"; ls -la "$HENRY"
echo
echo "If step 3 showed a PASS line and rc=0, the root daemon is the fix — realestate now mirrors nightly as root."