fix(ci): стек CouchDB после переезда остаётся на своём хосте #3087

Merged
lekss361 merged 1 commit from fix/deploy-obsidian-infra-host into main 2026-08-24 17:58:57 +00:00

View file

@ -32,13 +32,21 @@ name: Deploy Obsidian
# v1.5.0 означает ssh.InsecureIgnoreHostKey(), то есть ровно как до этого PR.
# Включается одной настройкой, как INFRA_DEPLOY_HOST (#3059) и fail-open у
# TRADEIN_INTERNAL_AUTH_SECRET (#2989).
# NB: этот workflow ходит на secrets.DEPLOY_HOST, поэтому и отпечаток берётся
# DEPLOY_SSH_FINGERPRINT — пара «хост+отпечаток» обязана меняться вместе. Но
# CouchDB по плану ОСТАЁТСЯ на Beget вместе с Forgejo/GlitchTip (#3062), а
# DEPLOY_HOST после 30.08 будет указывать на Selectel. Значит у этого файла есть
# отдельная, ещё не закрытая проблема адресата — тот же класс, что #3059. Здесь
# намеренно НЕ трогаем: правка про подлинность хоста, а не про маршрутизацию.
# При переводе на INFRA_DEPLOY_HOST не забыть переключить и отпечаток.
# АДРЕСАТ (#3062). CouchDB/Obsidian ОСТАЁТСЯ на Beget вместе с Forgejo и
# GlitchTip, а DEPLOY_HOST после 30.08 будет указывать на Selectel. Раньше этот
# workflow ходил на DEPLOY_HOST безусловно — то есть в день переезда молча начал
# бы разворачивать стек CouchDB не на той машине: git reset на /opt/gendesign
# продуктового хоста, а волт на Beget тем временем перестал бы обновляться.
# Отказа при этом не было бы — деплой зелёный, адресат другой.
#
# Теперь адресат берётся как INFRA_DEPLOY_HOST, а если он не задан — DEPLOY_HOST.
# До переезда это одна и та же машина, поэтому поведение не меняется; после —
# workflow сам остаётся на инфраструктурном хосте, без правки этого файла.
#
# Отпечаток идёт В ПАРЕ с адресатом и БЕЗ перекрёстного фолбэка: сверять ключ
# Beget'а с отпечатком Selectel'а — гарантированный отказ. Задан INFRA_DEPLOY_HOST
# → берётся INFRA_DEPLOY_SSH_FINGERPRINT; не задан → DEPLOY_SSH_FINGERPRINT.
# Пусто в выбранной ветке → проверка подлинности пропускается, как и раньше.
# ─────────────────────────────────────────────────────────────────────────────
on:
push:
@ -68,17 +76,46 @@ jobs:
# кого, отказ сломал бы деплой в момент мержа этого PR, а правило здесь —
# «инертно по умолчанию, включается одной настройкой». Заведут секрет —
# предупреждение исчезнет само.
- name: Подлинность хоста — статус проверки (#3029)
- name: Адресат и подлинность хоста (#3062, #3029)
id: target
env:
HOST_FINGERPRINT: ${{ secrets.DEPLOY_SSH_FINGERPRINT }}
INFRA_HOST: ${{ secrets.INFRA_DEPLOY_HOST }}
INFRA_FINGERPRINT: ${{ secrets.INFRA_DEPLOY_SSH_FINGERPRINT }}
MAIN_FINGERPRINT: ${{ secrets.DEPLOY_SSH_FINGERPRINT }}
run: |
set -euo pipefail
if [ -n "${HOST_FINGERPRINT:-}" ]; then
echo "Подлинность хоста: сверяется по DEPLOY_SSH_FINGERPRINT."
# Отпечаток — публичный хеш ключа хоста, не секрет: его можно
# передать через output. Приватный ключ так передавать нельзя,
# поэтому он остаётся прямой ссылкой на секрет в шаге ниже.
if [ -n "${INFRA_HOST:-}" ]; then
echo "Адресат: INFRA_DEPLOY_HOST — хосты разъехались, стек CouchDB едет на инфраструктурный хост."
HOST_FINGERPRINT="${INFRA_FINGERPRINT:-}"
FINGERPRINT_SOURCE="INFRA_DEPLOY_SSH_FINGERPRINT"
else
echo '::warning title=SSH без проверки подлинности хоста::DEPLOY_SSH_FINGERPRINT не задан — ключ хоста НЕ проверяется (#3029). По каналу едет DEPLOY_SSH_KEY и разворачивается стек CouchDB/Obsidian. После переезда на Selectel (#3057) соединение идёт через интернет. Как снять отпечаток — см. шапку этого файла.'
echo "Адресат: DEPLOY_HOST — INFRA_DEPLOY_HOST не задан, хосты ещё одна машина."
HOST_FINGERPRINT="${MAIN_FINGERPRINT:-}"
FINGERPRINT_SOURCE="DEPLOY_SSH_FINGERPRINT"
fi
# $GITHUB_OUTPUT — формат «ключ=значение» построчно, поэтому перевод
# строки внутри значения означает инъекцию произвольного output'а.
# Отпечаток однострочный по определению (SHA256:...), а вот копипаста
# в поле секрета лишний \n добавляет легко — шапка этого файла об этом
# прямо предупреждает. Не вычищаем молча: сверка побайтовая, тихий trim
# изменил бы результат проверки. Падаем с внятным текстом.
case "${HOST_FINGERPRINT}" in
*[![:print:]]*)
echo "ОШИБКА: ${FINGERPRINT_SOURCE} содержит перевод строки или непечатный символ." >&2
echo "ОШИБКА: значение должно быть одной строкой вида SHA256:xxxx — перезадай секрет без лишних символов." >&2
exit 1
;;
esac
echo "fingerprint=${HOST_FINGERPRINT}" >> "$GITHUB_OUTPUT"
if [ -n "${HOST_FINGERPRINT:-}" ]; then
echo "Подлинность хоста: сверяется по ${FINGERPRINT_SOURCE}."
else
echo "::warning title=SSH без проверки подлинности хоста::${FINGERPRINT_SOURCE} не задан — ключ хоста НЕ проверяется (#3029). По каналу едет ssh-ключ и разворачивается стек CouchDB/Obsidian. После разъезда хостов (#3057) соединение идёт через интернет. Как снять отпечаток — см. шапку этого файла."
echo '###############################################################'
echo '# ВНИМАНИЕ (#3029): DEPLOY_SSH_FINGERPRINT не задан.'
echo "# ВНИМАНИЕ (#3029): ${FINGERPRINT_SOURCE} не задан."
echo '# Ключ хоста НЕ проверяется — канал уязвим к MITM.'
echo '# Как снять отпечаток — см. шапку этого файла.'
echo '###############################################################'
@ -87,13 +124,19 @@ jobs:
- name: Deploy obsidian stack via SSH
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
port: ${{ secrets.DEPLOY_PORT || 22 }}
# #3029: подлинность хоста. Секрет НЕ задан → пустая строка → easyssh-proxy
# оставляет ssh.InsecureIgnoreHostKey(), то есть сегодняшнее поведение.
fingerprint: ${{ secrets.DEPLOY_SSH_FINGERPRINT }}
# #3062: адресат — инфраструктурный хост, если хосты уже разъехались.
# До этого INFRA_DEPLOY_HOST пуст и всё идёт на DEPLOY_HOST, как раньше.
host: ${{ secrets.INFRA_DEPLOY_HOST || secrets.DEPLOY_HOST }}
# user/key/port с фолбэком: у двух хостов они совпадают, а отдельные
# INFRA_*-секреты может и не завести — тогда работают общие.
username: ${{ secrets.INFRA_DEPLOY_USER || secrets.DEPLOY_USER }}
key: ${{ secrets.INFRA_DEPLOY_SSH_KEY || secrets.DEPLOY_SSH_KEY }}
port: ${{ secrets.INFRA_DEPLOY_PORT || secrets.DEPLOY_PORT || 22 }}
# #3029: подлинность хоста. Отпечаток выбран шагом выше В ПАРЕ с
# адресатом — перекрёстного фолбэка здесь быть не должно, иначе после
# переезда ключ Beget'а сверялся бы с отпечатком Selectel'а.
# Пусто → easyssh-proxy оставляет ssh.InsecureIgnoreHostKey(), как сегодня.
fingerprint: ${{ steps.target.outputs.fingerprint }}
script: |
set -euo pipefail
cd /opt/gendesign