← 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