gendesign/tradein-mvp/ops/db-bootstrap/set_gendesign_reader_password.sql
bot-backend 04da30b57a
All checks were successful
CI / changes (pull_request) Successful in 6s
CI / changes (push) Successful in 7s
CI / frontend-tests (push) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / backend-tests (push) Successful in 6m23s
CI / backend-tests (pull_request) Successful in 6m21s
fix(sf): psql stdin-bootstrap пароля gendesign_reader + COALESCE-protect внешних id (review fixup, #976)
- Создан tradein-mvp/ops/db-bootstrap/set_gendesign_reader_password.sql:
  set_config GUC + format('%L') + \o /dev/null — зеркальный паттерн
  ops/db-bootstrap/set_tradein_fdw_password.sql. Пароль не попадает
  в stdout/logs (leak-protected).
- deploy-tradein.yml: шаг bootstrap переписан на stdin-redirect
  (< ops/db-bootstrap/set_gendesign_reader_password.sql) вместо сломанного
  -c "ALTER ROLE ... PASSWORD :'TRADEIN_READER_PASSWORD'", которое давало
  syntax error at ':' (psql не интерполирует :'var' внутри -c строки).
- newbuilding_crossload.py ON CONFLICT DO UPDATE: yandex_jk_id и
  cian_internal_house_id → COALESCE(EXCLUDED.col, table.col), чтобы
  cian-запись не затирала yandex_jk_id NULL'ом и наоборот.
- Тест test_upsert_sql_coalesce_external_ids проверяет наличие COALESCE
  в DO UPDATE секции для обоих id.
2026-06-12 11:26:40 +03:00

54 lines
3.2 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- Set gendesign_reader password from env.
-- Applied by .forgejo/workflows/deploy-tradein.yml after migrations:
-- psql -v pw="$TRADEIN_READER_PASSWORD" -f ops/db-bootstrap/set_gendesign_reader_password.sql
-- cwd на деплое = /opt/gendesign/tradein-mvp (путь относительный).
--
-- Idempotent: ALTER если роль существует, NOTICE и продолжает если нет
-- (migration 101_gendesign_reader_role.sql может ещё не примениться на первом деплое).
-- Пароль НИКОГДА не хранится в этом файле или в git — только имя переменной.
--
-- Format %L экранирует пароль как SQL string literal — безопасно даже с кавычками.
--
-- psql variable substitution (:'pw') НЕ интерполируется внутри dollar-quoted
-- блока ($$...$$) — это правило psql, не bug. Поэтому password передаём в DO
-- через сессионный GUC (set_config), который psql интерполирует ВНЕ dollar
-- quote, и читаем внутри через current_setting().
-- Reference incident: deploy 2026-05-24 (post-merge PR #503) упал на
-- "syntax error at or near ':'" — :'pw' дошёл до сервера as literal вместо
-- интерполяции при использовании -c вместо stdin + файл.
--
-- Источник переменной pw: TRADEIN_READER_PASSWORD из tradein-mvp/.env.runtime.
-- Передаётся через: psql -v "pw=${TRADEIN_READER_PASSWORD}"
--
-- ⚠️ `set_config(name, value, is_local) -> text` ВОЗВРАЩАЕТ установленное
-- значение. Без `\o /dev/null` psql напечатал бы пароль на stdout → leak в
-- Forgejo Actions deploy logs (retained, visible всем с repo read access).
-- Поэтому оборачиваем оба set_config вызова в `\o /dev/null` / `\o` brackets
-- — output mutes только для этих строк, NOTICE-сообщения из DO block
-- (idempotency signal) остаются видимыми.
--
-- Rollback path: НЕ revert этого файла (вернёт сломанный :'pw' внутри $$).
-- Корректный rollback — unset TRADEIN_READER_PASSWORD в
-- /opt/gendesign/tradein-mvp/.env.runtime на VPS, deploy-tradein.yml
-- тогда пропустит этот шаг полностью.
\o /dev/null
SELECT set_config('app.reader_pw', :'pw', false);
\o
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'gendesign_reader') THEN
EXECUTE format('ALTER ROLE gendesign_reader WITH PASSWORD %L', current_setting('app.reader_pw'));
RAISE NOTICE 'gendesign_reader password set';
ELSE
RAISE NOTICE 'gendesign_reader role missing — migration 101_gendesign_reader_role.sql not applied yet';
END IF;
END $$;
-- Clear GUC after use (defense-in-depth — не оставляем password в session state
-- даже на short connection). Same \o trick — set_config return value is empty
-- string here, но всё равно лишний row в stdout не нужен.
\o /dev/null
SELECT set_config('app.reader_pw', '', false);
\o