fix(infra): bootstrap_glitchtip — \gexec instead of DO block (psql var trap)

psql variables (:'gt_pass') are substituted client-side in the psql stream
but NOT inside dollar-quoted DO $$..$$ bodies — those are sent to the server
as literal text, causing syntax error. Replace DO block with \gexec pattern:
quote_literal(:'gt_pass') builds the CREATE ROLE statement client-side, then
\gexec executes it. WHERE NOT EXISTS makes both role and DB steps idempotent.
Also connect to 'postgres' db (not app db) for CREATE DATABASE to work.
This commit is contained in:
lekss361 2026-05-16 18:28:42 +03:00
parent 277499684b
commit a1091cdd5a

View file

@ -48,28 +48,27 @@ for i in $(seq 1 30); do
done
# ── Create glitchtip DB + user (idempotent) ────────────────────────────────
# Password is passed via psql variable -v to avoid SQL injection from special
# chars (quotes, backslashes) in $GLITCHTIP_DB_PASS. format('%L', :'gt_pass')
# properly quotes the value server-side, so the shell never interpolates it
# into the SQL string.
# psql var :'gt_pass' НЕ подставляется внутри DO $$..$$ — тело dollar-quote
# уходит на сервер as-is. Используем \gexec в psql-стриме client-side.
#
# \gexec builds SQL client-side via quote_literal(:'gt_pass'), then executes it.
# quote_literal escapes apostrophes and backslashes — no SQL injection possible.
# If WHERE NOT EXISTS filters the row, \gexec receives no input → no-op, no error.
# ON_ERROR_STOP=1 ensures \gexec-executed statements also cause psql to exit non-zero.
echo "==> Creating glitchtip database and user (idempotent)..."
$COMPOSE exec -T postgres \
psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" \
-v "gt_pass=$GLITCHTIP_DB_PASS" \
-v ON_ERROR_STOP=on <<'SQL'
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'glitchtip') THEN
EXECUTE format('CREATE ROLE glitchtip LOGIN PASSWORD %L', :'gt_pass');
RAISE NOTICE 'Created role glitchtip';
ELSE
RAISE NOTICE 'Role glitchtip already exists';
END IF;
END$$;
psql -U "$POSTGRES_USER" -d postgres \
-v ON_ERROR_STOP=1 \
-v "gt_pass=$GLITCHTIP_DB_PASS" <<'SQL'
SELECT 'CREATE ROLE glitchtip LOGIN PASSWORD ' || quote_literal(:'gt_pass') || ';'
WHERE NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'glitchtip')
\gexec
SELECT 'CREATE DATABASE glitchtip OWNER glitchtip'
SELECT 'CREATE DATABASE glitchtip OWNER glitchtip;'
WHERE NOT EXISTS (SELECT 1 FROM pg_database WHERE datname = 'glitchtip')
\gexec
GRANT ALL PRIVILEGES ON DATABASE glitchtip TO glitchtip;
SQL
# ── Start GlitchTip containers ─────────────────────────────────────────────