← back to Nationalrealestate

scripts/deploy-usre-code-to-kamatera.sh

88 lines

#!/usr/bin/env bash
# TK-10488 Phase 2a — deploy the usre contractor CODE to Kamatera + enable the scoped
# contractor credential, SAFELY. RUN ON MAC2. Backs up every file it replaces, smoke-tests
# BOTH the new /api/contractors route (must 200) AND an existing usre route (must stay 200),
# and AUTO-ROLLBACKS if anything regresses. Deploys ONLY the 4 contractor files — never the
# whole repo — so it can't revert unrelated prod code.
set -euo pipefail
KAM=root@45.61.58.125
USRE_DIR=/root/public-projects/nationalrealestate
FILES=(src/server/contractors.ts src/server/index.ts public/contractors.html public/nav-drawer.js)
# scoped credential the builds will use (reaches ONLY /contractors* + /api/contractors).
# NEVER hardcode the secret — pass it at runtime:  CONTRACTORS_PASS=... bash <this script>
CU="${CONTRACTORS_USER:-contractors}"
CP="${CONTRACTORS_PASS:?set CONTRACTORS_PASS=... in the environment when running (do not hardcode a secret in the repo)}"
STAMP=$(cd ~/Projects/nationalrealestate && git rev-parse --short HEAD)

echo "### pre-flight (Mac2) ###"
cd ~/Projects/nationalrealestate
for f in "${FILES[@]}"; do [ -f "$f" ] || { echo "MISSING $f"; exit 1; }; done

echo "### 1. ship files to a staging dir on Kamatera ###"
ssh "$KAM" "mkdir -p /tmp/usre-deploy-$STAMP/src/server /tmp/usre-deploy-$STAMP/public"
scp -q src/server/contractors.ts src/server/index.ts "$KAM:/tmp/usre-deploy-$STAMP/src/server/"
scp -q public/contractors.html public/nav-drawer.js  "$KAM:/tmp/usre-deploy-$STAMP/public/"

echo "### 2-5. backup, deploy, enable scoped cred, restart, smoke, rollback-on-fail (Kamatera) ###"
ssh "$KAM" "bash -s" <<REMOTE
set -uo pipefail
cd "$USRE_DIR" || { echo "usre dir missing"; exit 1; }
PORT=\$(sed -n 's/^PORT=//p' .env 2>/dev/null | tr -dc '0-9'); PORT=\${PORT:-9913}
BK="/root/backups/usre-contractors-$STAMP"; mkdir -p "\$BK/src/server" "\$BK/public"
echo "backup dir: \$BK  (port \$PORT)"

# --- backup current versions of the files we'll replace (contractors.ts is new -> may not exist) ---
for f in src/server/contractors.ts src/server/index.ts public/contractors.html public/nav-drawer.js; do
  [ -f "\$f" ] && cp -p "\$f" "\$BK/\$f" && echo "backed up \$f"
done

# --- deploy the 4 files ---
cp /tmp/usre-deploy-$STAMP/src/server/contractors.ts src/server/contractors.ts
cp /tmp/usre-deploy-$STAMP/src/server/index.ts        src/server/index.ts
cp /tmp/usre-deploy-$STAMP/public/contractors.html    public/contractors.html
cp /tmp/usre-deploy-$STAMP/public/nav-drawer.js       public/nav-drawer.js

# --- enable the scoped contractor credential (idempotent) ---
grep -q '^CONTRACTORS_USER=' .env || echo 'CONTRACTORS_USER=$CU' >> .env
grep -q '^CONTRACTORS_PASS=' .env || echo 'CONTRACTORS_PASS=$CP' >> .env

echo "--- restart usre ---"
pm2 restart usrealestate --update-env >/dev/null 2>&1; sleep 3

# --- smoke: NEW route must 200 with scoped cred; EXISTING route must stay 200 with admin ---
NEW=\$(curl -s -o /dev/null -w '%{http_code}' -u "$CU:$CP" "http://localhost:\$PORT/api/contractors?limit=1")
OLD=\$(curl -s -o /dev/null -w '%{http_code}' "http://localhost:\$PORT/healthz")   # pre-auth liveness — proves server up + routing intact, no creds
SCOPE=\$(curl -s -o /dev/null -w '%{http_code}' -u "$CU:$CP" "http://localhost:\$PORT/api/ingest-health")  # scoped cred must NOT reach admin -> expect 401
echo "smoke: /api/contractors(scoped)=\$NEW  /healthz(existing)=\$OLD  /api/ingest-health(scoped,should-401)=\$SCOPE"

if [ "\$NEW" = "200" ] && [ "\$OLD" = "200" ]; then
  echo "DEPLOY OK — contractor API live + scoped, existing routes intact."
  [ "\$SCOPE" = "401" ] && echo "scope correctly enforced (contractor cred can't reach admin)." || echo "WARN: scope check returned \$SCOPE (expected 401) — review."
  rm -rf /tmp/usre-deploy-$STAMP
else
  echo "SMOKE FAILED (new=\$NEW old=\$OLD) — ROLLING BACK."
  for f in src/server/index.ts public/contractors.html public/nav-drawer.js; do [ -f "\$BK/\$f" ] && cp -p "\$BK/\$f" "\$f"; done
  [ -f "\$BK/src/server/contractors.ts" ] || rm -f src/server/contractors.ts  # was a new file
  pm2 restart usrealestate --update-env >/dev/null 2>&1; sleep 2
  echo "ROLLED BACK to $STAMP baseline. Backup kept at \$BK. Investigate before retry."
  exit 1
fi
REMOTE

cat <<NEXT

########################################################################
# PHASE 2b — point the builds at the scoped usre API (after 2a is OK)
# On Kamatera, in each build's .env, add (usre URL + the scoped cred):
#   CONTRACTORS_API_BASE=https://usrealestate.agentabrams.com
#   CONTRACTORS_API_USER=contractors
#   CONTRACTORS_API_PASS=<the CONTRACTORS_PASS you set in phase 2a>   # keep out of git; use the secrets skill
# CRCP:        cd ~/Projects/commercialrealestate && /deploy   (has .deploy.conf)
# HomesOnSpec: deploy apps/web the normal way + pm2 restart homesonspec-web --update-env
# Each build's fetch layer must send Basic auth to the usre API (the shared client supports it).
# Smoke each: load a page that renders contractors -> should show data, no login prompt for end users.
#
# RENTV: claude-rentv mounts rentv-v1/contrib/contractors/ per README (DM M-00598 sent).
########################################################################
NEXT