← back to Small Business Builder

scripts/deploy-kamatera.sh

86 lines

#!/usr/bin/env bash
# Deploy smb-builder to Kamatera at 45.61.58.125:9760 (IP:port, no public domain yet).
#
# REQUIRES EXPLICIT AUTH per Steve's standing rule for cncp-adjacent deploys.
# Run only after reading DEPLOY.md and confirming intent.
#
# Idempotent: re-running is safe — rsync syncs, psql migrations are guarded.
#
# Pre-reqs (set in this shell BEFORE running, do NOT inline as $VAR in bash):
#   set -a; source /tmp/.smb_admin_token_<pid> ; set +a   # exposes ADMIN_TOKEN
#   (or just `export ADMIN_TOKEN="$(cat <secret-file>)"`)
#
# What this does:
#   1. rsync code → kamatera:/root/Projects/small-business-builder
#   2. createdb on Kamatera (skipped if exists)
#   3. run migrations
#   4. write .env with the ADMIN_TOKEN from this shell (no argv leak)
#   5. pm2 start + pm2 save
#   6. test http://45.61.58.125:9760/

set -euo pipefail

REMOTE="root@45.61.58.125"
REMOTE_DIR="/root/Projects/small-business-builder"
LOCAL_DIR="$HOME/Projects/small-business-builder"

if [ -z "${ADMIN_TOKEN:-}" ]; then
  echo "FATAL: ADMIN_TOKEN env var not set in this shell." >&2
  echo "Run: set -a; source /tmp/.smb_admin_token_<pid>; set +a   then re-run this script." >&2
  exit 1
fi

echo "[1/6] rsync code → $REMOTE:$REMOTE_DIR"
rsync -av --delete \
  --exclude=node_modules --exclude=.git --exclude=logs --exclude='.env*' \
  --exclude='_yolo_patches' --exclude='*.bak.*' \
  "$LOCAL_DIR/" "$REMOTE:$REMOTE_DIR/"

echo "[2/6] ensure DB + role exist (sudo -u postgres for peer auth)"
# Pipe DB password via stdin so it never enters argv / ps / shell history.
DB_PW="${DB_PW:-$ADMIN_TOKEN}"   # reuse admin token as DB pw if not set
ssh "$REMOTE" "sudo -u postgres psql" <<EOF
DO \$\$
BEGIN
  IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname='smb_builder') THEN
    CREATE ROLE smb_builder WITH LOGIN PASSWORD '$DB_PW';
  ELSE
    ALTER ROLE smb_builder WITH PASSWORD '$DB_PW';
  END IF;
END
\$\$;
SELECT 'CREATE DATABASE small_business_directory OWNER smb_builder'
  WHERE NOT EXISTS (SELECT 1 FROM pg_database WHERE datname='small_business_directory')
\\gexec
GRANT ALL PRIVILEGES ON DATABASE small_business_directory TO smb_builder;
EOF

echo "[3/6] run migrations"
ssh "$REMOTE" "cd $REMOTE_DIR && for m in migrations/*.sql; do echo \"applying \$m\"; sudo -u postgres psql -d small_business_directory -f \"\$m\" || true; done"

echo "[4/6] write .env (token via stdin, never argv)"
# Pipe token via stdin so it never appears in argv / ps / shell history
ssh "$REMOTE" "cat > $REMOTE_DIR/.env" <<EOF
NODE_ENV=production
PORT=9760
DATABASE_URL=postgres://smb_builder:$DB_PW@localhost:5432/small_business_directory
ADMIN_TOKEN=$ADMIN_TOKEN
EOF
ssh "$REMOTE" "chmod 600 $REMOTE_DIR/.env"

echo "[5/6] npm install + pm2 start + save"
ssh "$REMOTE" "cd $REMOTE_DIR && npm install --omit=dev --no-audit --no-fund 2>&1 | tail -5"
ssh "$REMOTE" "cd $REMOTE_DIR && pm2 delete smb-builder 2>/dev/null; pm2 start ecosystem.config.cjs && pm2 save"

echo "[6/6] smoke test"
sleep 3
ssh "$REMOTE" "curl -s -o /dev/null -w 'http://localhost:9760/ → %{http_code}\n' --max-time 5 http://localhost:9760/"
echo ""
echo "From your laptop, with the same ADMIN_TOKEN value:"
echo "  curl http://45.61.58.125:9760/healthz"
echo ""
echo "Done. Remember to:"
echo "  • unset ADMIN_TOKEN  in this shell"
echo "  • rm /tmp/.smb_admin_token_*"
echo "  • route the new token through ~/Projects/secrets-manager/cli.js add SMB_ADMIN_TOKEN"