Commit graph

5 commits

Author SHA1 Message Date
bot-backend
de940c7534 feat(ops): off-box копия рантайм-конфига — зашифрованной, иначе никак
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 10s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
Четвёртый пункт приёмки #2203. В дампах есть колонки под pgp_sym_encrypt, ключ
к ним лежит на самой машине и никуда не уезжает: потеря машины означает «дампы
есть, расшифровать нечем». Ради этой связки шифрование в базе и заводилось.

КУДА И ПОЧЕМУ ИМЕННО ТУДА. В тот же S3, отдельным префиксом env/, и только
зашифрованным. Разобранные варианты:

  - рядом с дампами открытым — нельзя: ключ рядом с шифротекстом обнуляет
    шифрование, одна утечка доступа к бакету отдаёт и то и другое;
  - на соседний хост по SSH — потребовало бы завести доверие между машинами,
    которого нет (проверено: Permission denied (publickey)), то есть РАСШИРИТЬ
    периметр ровно тогда, когда #3075 его сужает;
  - отдельный бакет с отдельными ключами — правильнее всего, но требует новых
    учётных данных.

Выбран единственный исполнимый без расширения доступа: шифротекст в S3,
парольная фраза — вне S3.

FAIL-CLOSED. Без фразы скрипт не выгружает файл открытым, а падает с явным
сообщением и алертом. Молчаливая выгрузка ключа в бакет с дампами хуже
отсутствия копии: создаёт ложное чувство защищённости.

Фраза уходит через дескриптор, а не аргументом — иначе видна в ps любому
пользователю машины. После шифрования файл проверяется обратной расшифровкой:
без этого можно годами возить нечитаемый мусор и узнать в тот момент, когда он
понадобился.

Прогон на хосте 27.08 (подставной исходник, боевой не трогался):
  без фразы → код 1, файлов создано 0
  с фразой  → «Зашифровано и проверено расшифровкой», 110 байт
  своей фразой читается, чужой — нет

ОДИН ШАГ ЗА ВЛАДЕЛЬЦЕМ, и он неустраним: фраза обязана жить там, где переживёт
смерть машины, иначе копия бесполезна — расшифровать будет нечем. Сгенерировать
её здесь и оставить на хосте нельзя по построению. Инструкция — в шапке скрипта.

Пять тестов сторожат ровно те свойства, ради которых всё сделано.
Прогон: 85 ops-тестов зелёные, ruff чист.

Refs #2203
2026-08-27 16:32:27 +03:00
bot-backend
ec6181b7b3 chore(ops): restore-дрель для базы tradein — она не покрывалась вовсе
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 10s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
Дрель восстановления стоит в cron с #3085, но её строка берёт только
`gendesign_*`. База tradein — клиентские оценки, листинги, дома, сделки —
автоматически на восстановимость не проверялась ни разу: дампы снимались,
уезжали в S3, и никто не знал, разворачиваются ли они.

Сам `ops/restore-drill.sh` менять не пришлось — он с самого начала умеет оба
проекта: находит globals по своей схеме имён (`tradein-globals-<ts>`),
подставляет свой список таблиц для сверки. Не хватало ровно строки в cron.

Прогнал на боевом дампе 27.08 перед тем, как добавлять (оповещение заглушено,
чтобы не слать ложную тревогу):

    tradein-20260827-111102.sql.gz, 343 МБ → 58 c
    GRANT-ы применены, материализованные представления обновлены
    PostGIS 3.4.3, таблиц в public: 76
    listings 109978 · listing_sources 106704 · deals 108623
    houses 10400 · trade_in_estimates 1121

Сверка с боевой базой: houses, listings, deals, osm_poi сходятся точно;
trade_in_estimates и user_events больше на проде ровно на строки, созданные
ПОСЛЕ снятия дампа. То есть дамп верен.

Еженедельно, а не раз в месяц: две минуты работы против месяца, в течение
которого битый дамп остаётся незамеченным. Понедельник 03:00 — после дрели
gendesign (02:15 первого числа) и до ночных бэкапов в 03:30.
2026-08-27 14:57:40 +03:00
bot-backend
efaab2efda chore(ops): адрес Poincare — 188.124.37.140 вместо заменённого 188.246.224.93 (#3110)
All checks were successful
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / changes (pull_request) Successful in 7s
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / changes (pull_request) Successful in 9s
CI / openapi-codegen-check (pull_request) Successful in 1m58s
CI / backend-tests (pull_request) Successful in 17m16s
Selectel заменил адрес сервера в ночь на 27.08 по нашей заявке: старый
188.246.224.93 фильтровался российскими операторами и не открывался ни с
домашнего интернета, ни с мобильного (#3110). Новый адрес фильтрации не имеет —
проверено с машины владельца после переключения DNS.

Замена уронила сервер на 10 часов: адрес на порте сменился, а в ОС остался
прежний (разбор и восстановление — #3119). Здесь только то, что осталось в
репозитории.

Единственное функциональное вхождение — дефолт HOST_IP в ops/selectel-ci-access.sh:
скрипт открывает раннеру доступ на прод-хост, и с прежним значением он молча
настроил бы доступ на адрес, которого у нас больше нет. Остальные семь — тексты
комментариев в Caddyfile-секциях, compose, bootstrap-скриптах и раннбуке крона;
они не исполняются, но именно по ним сверяются при переезде, и разошедшийся
адрес в них дороже, чем кажется.
2026-08-27 11:23:37 +03:00
2feb0de446 fix(ops): бэкап без выгрузки в S3 падает, а не рапортует успех (#3086)
All checks were successful
Deploy Infra Host / sync-infra-host (push) Successful in 2s
Deploy / changes (push) Successful in 7s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy Trade-In / changes (push) Successful in 12s
Deploy / build-frontend (push) Has been skipped
Deploy / deploy-caddy (push) Has been skipped
Deploy Trade-In / build-browser (push) Successful in 45s
Deploy / deploy (push) Successful in 1m45s
Deploy / deploy-status (push) Successful in 1s
Deploy / perimeter-smoke (push) Successful in 10s
Deploy Trade-In / build-frontend (push) Successful in 2m35s
Deploy Trade-In / test (push) Successful in 3m53s
Deploy Trade-In / build-backend (push) Successful in 34s
Deploy Trade-In / deploy (push) Successful in 2m21s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / perimeter-smoke (push) Successful in 10s
2026-08-24 17:50:18 +00:00
0ba52e55db chore(ops): развести crontab по хостам под переезд (#3072)
All checks were successful
Deploy / changes (push) Successful in 7s
Deploy / deploy-caddy (push) Has been skipped
Deploy / build-frontend (push) Successful in 41s
Deploy / build-backend (push) Successful in 43s
Deploy / build-worker (push) Successful in 45s
Deploy / deploy (push) Successful in 1m32s
Deploy / deploy-status (push) Successful in 1s
Deploy / perimeter-smoke (push) Successful in 9s
2026-08-24 02:04:40 +00:00