lilith-platform.live/infrastructure/scripts/plum-e2e-db.sh
Natalie 2c59253a16 fix(admin): plum E2E smoke gate self-contained test env
The [2.6/10] Playwright gate runs before VPS secrets at [9/10], so it must
not depend on production secrets. Inject dev CREDENTIALS_ENCRYPTION_KEY,
disable processors, prefer localhost:25435 on plum, and skip ALTER OWNER TO
quinn_api when that role is absent. Provision quinn_api in plum-e2e-db.sh.
2026-06-25 02:30:04 -04:00

137 lines
5.2 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# plum-e2e-db.sh — provision a dedicated local Postgres for E2E / dev on plum.
#
# Apricot (the old authoring host with a local 25435 Postgres) is gone; plum is
# now the sole authoring surface. The admin E2E smoke gate
# (deployments/@domains/quinn.admin/e2e/global-setup.ts) boots the @features/api
# server against postgresql://quinn:devpassword@localhost:25435/quinn_admin_test
# and needs a Postgres there. The system brew `postgresql@16` instance already
# runs on 5432 and hosts lilith_messaging, so we DON'T move it — we stand up a
# second, isolated PG16 instance on 25435 (matching the canonical quinn port in
# infrastructure/pg-services.yml) with its own datadir.
#
# Idempotent: safe to re-run. Survives reboot via a per-user LaunchAgent.
#
# Usage:
# infrastructure/scripts/plum-e2e-db.sh # provision + start
# infrastructure/scripts/plum-e2e-db.sh status # report state
# infrastructure/scripts/plum-e2e-db.sh stop # stop the instance
set -euo pipefail
# macOS spawns helper threads for locale resolution; without a fixed locale the
# postmaster aborts with "became multithreaded during startup". Pin it.
export LC_ALL="C"
PG_PREFIX="/opt/homebrew/opt/postgresql@16"
PG_BIN="${PG_PREFIX}/bin"
DATADIR="/opt/homebrew/var/postgresql@16-quinn-e2e"
PORT=25435
LOGFILE="/opt/homebrew/var/log/postgresql@16-quinn-e2e.log"
PLIST="${HOME}/Library/LaunchAgents/com.lilith.quinn-e2e-pg.plist"
ROLE="quinn"
ROLE_PW="devpassword"
# analytics_markers migrations ALTER OWNER TO quinn_api (black prod shape).
API_ROLE="quinn_api"
DBS=("quinn_admin_test" "quinn")
if [[ ! -x "${PG_BIN}/pg_ctl" ]]; then
echo "ERROR: Homebrew postgresql@16 not found at ${PG_BIN}. Run: brew install postgresql@16" >&2
exit 1
fi
cmd="${1:-up}"
is_running() { "${PG_BIN}/pg_ctl" -D "${DATADIR}" status >/dev/null 2>&1; }
case "${cmd}" in
status)
if is_running; then
echo "quinn-e2e PG: RUNNING on :${PORT} (datadir ${DATADIR})"
"${PG_BIN}/psql" -h localhost -p "${PORT}" -d postgres -tAc \
"select ' db: '||datname from pg_database where datistemplate=false order by 1" 2>/dev/null || true
else
echo "quinn-e2e PG: STOPPED (datadir ${DATADIR})"
fi
exit 0
;;
stop)
if is_running; then
"${PG_BIN}/pg_ctl" -D "${DATADIR}" -m fast stop
echo "Stopped quinn-e2e PG."
else
echo "quinn-e2e PG already stopped."
fi
exit 0
;;
up) ;;
*) echo "Usage: $0 [up|status|stop]" >&2; exit 2 ;;
esac
# --- 1. initdb (first run only) --------------------------------------------
if [[ ! -s "${DATADIR}/PG_VERSION" ]]; then
echo "==> initdb ${DATADIR} ..."
mkdir -p "$(dirname "${DATADIR}")"
"${PG_BIN}/initdb" -D "${DATADIR}" -U "${USER}" --encoding=UTF8 --locale=C >/dev/null
# Dedicated port; trust loopback so the E2E password is irrelevant but valid.
{
echo "port = ${PORT}"
echo "listen_addresses = '127.0.0.1,::1'"
echo "unix_socket_directories = '${DATADIR}'"
} >> "${DATADIR}/postgresql.conf"
else
echo "==> datadir ${DATADIR} already initialized."
fi
# --- 2. start --------------------------------------------------------------
mkdir -p "$(dirname "${LOGFILE}")"
if ! is_running; then
echo "==> starting quinn-e2e PG on :${PORT} ..."
"${PG_BIN}/pg_ctl" -D "${DATADIR}" -l "${LOGFILE}" -w start
else
echo "==> quinn-e2e PG already running."
fi
# --- 3. provision role + databases (idempotent) ----------------------------
PSQL=("${PG_BIN}/psql" -h localhost -p "${PORT}" -d postgres -v ON_ERROR_STOP=1 -X)
echo "==> provisioning role '${ROLE}' + databases ..."
"${PSQL[@]}" -tAc "select 1 from pg_roles where rolname='${ROLE}'" | grep -q 1 || \
"${PSQL[@]}" -c "create role ${ROLE} login superuser password '${ROLE_PW}'"
# Keep the password in sync even if the role pre-existed.
"${PSQL[@]}" -c "alter role ${ROLE} password '${ROLE_PW}'" >/dev/null
"${PSQL[@]}" -tAc "select 1 from pg_roles where rolname='${API_ROLE}'" | grep -q 1 || \
"${PSQL[@]}" -c "create role ${API_ROLE}"
for db in "${DBS[@]}"; do
"${PSQL[@]}" -tAc "select 1 from pg_database where datname='${db}'" | grep -q 1 || \
"${PSQL[@]}" -c "create database ${db} owner ${ROLE}"
done
# --- 4. LaunchAgent for reboot persistence ---------------------------------
if [[ ! -f "${PLIST}" ]]; then
echo "==> installing LaunchAgent ${PLIST} ..."
mkdir -p "$(dirname "${PLIST}")"
cat > "${PLIST}" <<PLISTEOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>com.lilith.quinn-e2e-pg</string>
<key>ProgramArguments</key>
<array>
<string>${PG_BIN}/postgres</string>
<string>-D</string><string>${DATADIR}</string>
</array>
<key>EnvironmentVariables</key>
<dict><key>LC_ALL</key><string>C</string></dict>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
<key>StandardOutPath</key><string>${LOGFILE}</string>
<key>StandardErrorPath</key><string>${LOGFILE}</string>
</dict>
</plist>
PLISTEOF
launchctl bootstrap "gui/$(id -u)" "${PLIST}" 2>/dev/null || launchctl load "${PLIST}" 2>/dev/null || true
fi
echo ""
echo "quinn-e2e PG ready: postgresql://${ROLE}:${ROLE_PW}@localhost:${PORT}/quinn_admin_test"