diff --git a/deploy/nixos/factory-reset-atm.sh b/deploy/nixos/factory-reset-atm.sh new file mode 100755 index 0000000..b46e7a3 --- /dev/null +++ b/deploy/nixos/factory-reset-atm.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +# Factory-reset a bitSpire ATM to a truly-fresh state — the deterministic way to +# reproduce a brand-new machine so tests aren't masked by leftover env/db values +# (aiolabs/bitspire#70 remnant hygiene). +# +# WIPES: +# - /var/lib/bitspire/state.db (bunker binding, fee config, cassettes, cashbox, +# transactions, operator commands, replay watermarks — recreated on next boot) +# - /var/lib/bitspire/.env (truncated to the minimal image-baked template: +# machine model + fiat + display; drops relay, server pubkey, operator pubkey +# and any stored spire seed) +# +# After this the ATM boots UNPAIRED into the pairing wizard, exactly like a fresh +# disk image — so a scanned seed is the sole source of truth. +# +# Usage: +# bash factory-reset-atm.sh # SSH to localhost:2222 (QEMU) +# bash factory-reset-atm.sh 192.168.1.50 # a real ATM on the LAN +# bash factory-reset-atm.sh 192.168.1.50 22 # custom SSH port +# FORCE=1 bash factory-reset-atm.sh … # skip the confirmation prompt +# ATM_USER=root bash factory-reset-atm.sh … # override SSH user (default: bitspire) +set -euo pipefail + +ATM_HOST="${1:-localhost}" +ATM_SSH_PORT="${2:-2222}" +ATM_USER="${ATM_USER:-bitspire}" + +echo "=== Factory-reset bitSpire ATM at $ATM_USER@$ATM_HOST:$ATM_SSH_PORT ===" +echo "This WIPES state.db and truncates .env to the minimal template (keeps only" +echo "machine model + fiat). ALL pairing, cash accounting, and transaction history" +echo "on the ATM will be lost." +if [ "${FORCE:-}" != "1" ]; then + read -r -p "Type 'yes' to proceed: " confirm + [ "$confirm" = "yes" ] || { echo "Aborted."; exit 1; } +fi + +ssh -o StrictHostKeyChecking=no -p "$ATM_SSH_PORT" "$ATM_USER@$ATM_HOST" 'sudo bash -s' <<'REMOTE' +set -euo pipefail +ENV=/var/lib/bitspire/.env +DB=/var/lib/bitspire/state.db + +# Preserve model + fiat from the existing .env (fall back to sintra/EUR). +model=$(grep -E '^VITE_LAMASSU_MACHINE_MODEL=' "$ENV" 2>/dev/null | cut -d= -f2- || true) +fiat=$(grep -E '^VITE_LAMASSU_FIAT_CODE=' "$ENV" 2>/dev/null | cut -d= -f2- || true) +model=${model:-sintra} +fiat=${fiat:-EUR} + +systemctl stop bitspire 2>/dev/null || true + +# Wipe persisted state (db + WAL/SHM sidecars). +rm -f "$DB" "$DB-wal" "$DB-shm" + +# Truncate .env to the minimal image-baked template. +cat > "$ENV" </dev/null || true + +systemctl start bitspire 2>/dev/null || true + +echo "--- .env is now (values blanked) ---" +sed -E 's/=.*/=/' "$ENV" +echo "--- state.db removed (recreated fresh on next boot) ---" +REMOTE + +echo "" +echo "=== ATM factory-reset. It boots UNPAIRED → the pairing wizard. ===" +echo "Watch: ssh -p $ATM_SSH_PORT $ATM_USER@$ATM_HOST 'sudo journalctl -u bitspire -f'"