← back to Dw Fleet Registry
rotate-and-deploy.sh
78 lines
#!/usr/bin/env bash
# rotate-and-deploy.sh — drives the dw_admin rotation finish + DW fleet rebuild deploy,
# doing EVERYTHING except the 2 human-locked steps:
# (H1) mint pw + `ALTER ROLE dw_admin` on Kamatera + Mac2 (you, in psql)
# (H2) the go/no-go to touch compromised Kamatera (you, via the phase flags)
#
# Phases are EXPLICIT and never auto-chain. Dry-run unless --run. Aborts on first error.
#
# Usage:
# DW_ADMIN_NEW_PW='…' ./rotate-and-deploy.sh route --run # after you ALTER ROLE: route-back + local restart + verify
# ./rotate-and-deploy.sh kamatera --run # restart Kamatera fleet (--update-env) + verify [needs H2]
# ./rotate-and-deploy.sh unfreeze --run # flip cncp prod flag compromised→ok [needs H2]
# ./rotate-and-deploy.sh deploy --canary --run # merge+deploy ONLY 1890swallpaper, smoke-test [needs H2]
# ./rotate-and-deploy.sh deploy --all --run # merge+deploy the other 64, smoke-test each [needs H2]
set -uo pipefail
PHASE="${1:-help}"; shift || true
RUN=0; SCOPE=""
for a in "$@"; do case "$a" in --run) RUN=1;; --canary) SCOPE=canary;; --all) SCOPE=all;; esac; done
KAMATERA="root@45.61.58.125"
SM="$HOME/Projects/secrets-manager/cli.js"
CNCP="$HOME/cncp-starter/server.js"
REG_DIR="$HOME/Projects/dw-fleet-registry"
TARGETS="/tmp/fleet-targets.txt"
BRANCH="style-rebuild-pilot"
say(){ printf '\033[36m▸ %s\033[0m\n' "$*"; }
do_(){ if [ "$RUN" = 1 ]; then echo " + $*"; eval "$@" || { echo " ✗ FAILED: $*"; exit 1; }; else echo " [dry] $*"; fi; }
case "$PHASE" in
route)
[ -n "${DW_ADMIN_NEW_PW:-}" ] || { echo "set DW_ADMIN_NEW_PW (the value you just ALTER ROLE'd to)"; exit 2; }
say "Phase ROUTE — fan new pw to env files + restart LOCAL consumers + verify"
do_ "printf 'DW_ADMIN_DB_PASSWORD=%s' \"\$DW_ADMIN_NEW_PW\" | node \"$SM\" import-paste"
do_ "pm2 restart wallco-ai-9905 --update-env"
do_ "node \"$SM\" check DW_ADMIN_DB_PASSWORD || true"
say "local routed. Kamatera fleet restart is the next phase (needs your go)."
;;
kamatera)
say "Phase KAMATERA — restart the prod fleet so it re-reads the rotated DSN [touches compromised host]"
do_ "ssh -o ConnectTimeout=8 $KAMATERA 'pm2 restart all --update-env'"
do_ "ssh -o ConnectTimeout=8 $KAMATERA 'pm2 ls | tail -40'"
;;
unfreeze)
say "Phase UNFREEZE — flip cncp prod flag compromised→ok (do ONLY after rotation verified)"
do_ "sed -i '' \"s/status: 'compromised', note: 'do-not-deploy — active incident'/status: 'ok', note: 'rotated $(date +%F)'/\" \"$CNCP\""
do_ "launchctl kickstart -k gui/\$(id -u)/com.user.cncp"
;;
deploy)
[ -n "$SCOPE" ] || { echo "specify --canary or --all"; exit 2; }
say "Phase DEPLOY ($SCOPE) — merge ${BRANCH} to main + push to Kamatera + smoke-test [touches prod]"
if [ "$SCOPE" = canary ]; then LIST="1890swallpaper"; else LIST=$(grep -v '^1890swallpaper$' "$TARGETS"); fi
for slug in $LIST; do
d="$HOME/Projects/$slug"; [ -d "$d/.git" ] || { echo " skip $slug (no repo)"; continue; }
say "deploy $slug"
do_ "git -C \"$d\" checkout main -q && git -C \"$d\" merge --no-edit $BRANCH -q"
# introspect Kamatera for this site's pm2 cwd, rsync public/+server.js, reload, smoke-test
do_ "bash \"$HOME/Projects/_shared/scripts/deploy.sh\" \"$d\""
done
say "DEPLOY $SCOPE complete."
;;
*)
cat <<EOF
rotate-and-deploy.sh — phases (each explicit, dry-run unless --run):
route route-back new pw + restart local + verify (needs DW_ADMIN_NEW_PW; after you ALTER ROLE)
kamatera restart prod fleet --update-env (needs your go — compromised host)
unfreeze flip cncp prod flag compromised→ok
deploy --canary merge+deploy 1890swallpaper, smoke-test
deploy --all merge+deploy the other 64
Human steps I can't do: (H1) ALTER ROLE dw_admin in psql, (H2) saying the box is safe.
EOF
;;
esac