fix(db): derive DATABASE_URL from POSTGRES_PASSWORD and harden credential sync

Stop web/scraper containers from using a stray literal DATABASE_URL in the
root .env (which desynced the postgres role password and caused persistent
'password authentication failed' errors). DATABASE_URL is now always computed
from POSTGRES_USER/POSTGRES_PASSWORD.

Also harden postgres-entrypoint.sh: log to stderr, retry on failure, and run
ALTER ROLE unconditionally so the stored password always matches the env.
This commit is contained in:
JobsBoard Deployer 2026-09-07 13:06:42 -04:00
parent c7259411ae
commit bb4c93b11c
2 changed files with 24 additions and 12 deletions

View file

@ -34,7 +34,7 @@ services:
ports: ports:
- "${WEB_PORT:-3000}:3000" - "${WEB_PORT:-3000}:3000"
environment: environment:
DATABASE_URL: "${DATABASE_URL:-postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@db:5432/${POSTGRES_DB:-jobsboard}?schema=public}" DATABASE_URL: "postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@db:5432/${POSTGRES_DB:-jobsboard}?schema=public"
NEXTAUTH_SECRET: "${NEXTAUTH_SECRET:-jobsboard-secret-key-for-auth-sessions}" NEXTAUTH_SECRET: "${NEXTAUTH_SECRET:-jobsboard-secret-key-for-auth-sessions}"
NEXTAUTH_URL: "${NEXTAUTH_URL:-http://localhost:3000}" NEXTAUTH_URL: "${NEXTAUTH_URL:-http://localhost:3000}"
NODE_ENV: "production" NODE_ENV: "production"
@ -55,7 +55,7 @@ services:
container_name: jobsboard_scraper container_name: jobsboard_scraper
restart: always restart: always
environment: environment:
DATABASE_URL: "${DATABASE_URL:-postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@db:5432/${POSTGRES_DB:-jobsboard}?schema=public}" DATABASE_URL: "postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@db:5432/${POSTGRES_DB:-jobsboard}?schema=public"
SCRAPE_INTERVAL_MINUTES: "30" SCRAPE_INTERVAL_MINUTES: "30"
SOCKS5_PROXY: "${SOCKS5_PROXY:-}" SOCKS5_PROXY: "${SOCKS5_PROXY:-}"
PROXY_URL: "${PROXY_URL:-}" PROXY_URL: "${PROXY_URL:-}"

View file

@ -1,7 +1,10 @@
#!/bin/sh #!/bin/sh
set -e set -e
# Run background synchronization once PostgreSQL is up on local unix socket # Re-align the Postgres role password with POSTGRES_PASSWORD on every boot.
# Connects via the local unix socket (pg_hba "trust"), so it works even when
# TCP password auth is currently broken. Runs in the background so it does not
# block server startup, but retries until it succeeds.
sync_credentials() { sync_credentials() {
until pg_isready -q -h /var/run/postgresql; do until pg_isready -q -h /var/run/postgresql; do
sleep 0.5 sleep 0.5
@ -10,17 +13,26 @@ sync_credentials() {
USER="${POSTGRES_USER:-postgres}" USER="${POSTGRES_USER:-postgres}"
PASS="${POSTGRES_PASSWORD:-postgres}" PASS="${POSTGRES_PASSWORD:-postgres}"
psql -v ON_ERROR_STOP=0 -h /var/run/postgresql -U postgres -d postgres <<-EOSQL >/dev/null 2>&1 for i in $(seq 1 30); do
DO \$\$ if psql -v ON_ERROR_STOP=1 -h /var/run/postgresql -U postgres -d postgres <<-EOSQL 2>/dev/null
BEGIN DO \$\$
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = '$USER') THEN BEGIN
CREATE ROLE "$USER" WITH LOGIN SUPERUSER PASSWORD '$PASS'; IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = '$USER') THEN
ELSE CREATE ROLE "$USER" WITH LOGIN SUPERUSER PASSWORD '$PASS';
END IF;
ALTER ROLE "$USER" WITH LOGIN SUPERUSER PASSWORD '$PASS'; ALTER ROLE "$USER" WITH LOGIN SUPERUSER PASSWORD '$PASS';
END IF; END
END \$\$;
\$\$;
EOSQL EOSQL
then
echo "[entrypoint] Synchronized '$USER' role password." >&2
return 0
fi
echo "[entrypoint] Credential sync attempt $i failed, retrying..." >&2
sleep 1
done
echo "[entrypoint] WARNING: could not synchronize credentials." >&2
} }
sync_credentials & sync_credentials &