fix(install): сделать границу «хост изменён» настоящим инвариантом
fatal_pre_apply мог означать «хост уже изменён». install-state.json пишется сразу после успешного preflight, до установки пакетов, но классификация отказа его не учитывала. Падение apt-get объявлялось как «на сервере ничего не изменено»: откат и обработка состояния пропускались, а маркер оставался на диске и ломал следующую установку по clean-host контракту. Ownership-флаги переформулированы с «шаг успешно завершился» на «операция могла начать менять систему» и взводятся перед мутирующим вызовом: apt-get умеет изменить систему и упасть. fatal_pre_apply теперь недостижим ни при одном взведённом флаге, включая stateWritten. Read-only guard PHASE 0 можно было обойти. Guard стоял на writeText, writeTextAtomic, runVisible, runHidden и runRawVisible, но не на универсальном run, через который в коде проходили и наблюдение (ss, systemctl is-active), и настоящие мутации (useradd, install -d, mkdir, cp -a, tar). Универсального раннера больше нет: runReadOnly/runReadOnlySecret без guard'а и runMutating* под guard'ом, выбор — явное решение на месте вызова. clean-host не замечал часть того, что удаляет purge. /var/lib/hysteria с ACME-состоянием Hysteria, /var/log/hy2xs, /usr/local/lib/hy2xs и /usr/local/bin/hy2xs-orchestrator не были маркерами: сервер, где остался только старый runtime-state Hysteria, проходил проверку и получал свежую установку поверх чужого состояния. Пути, которые install.sh создаёт между фазами, помечены как созданные установщиком, иначе PHASE 1 отказала бы на собственном оркестраторе. purge-v0.sh --keep-hysteria-binary противоречил установщику: скрипт сохранял /usr/local/bin/hysteria и сообщал «хост чист для установки HY2XS v1», хотя clean-host считает этот бинарник legacy-маркером. Флаг удалён. DNS проверялся на существование A-записи, но не на то, куда она ведёт. После принудительной смены IPv4 провайдером doctor отвечал успехом, хотя клиентская ссылка отправляла людей на чужую машину. Проверялся при этом HY2XS_DOMAIN, тогда как в hysteria2:// уезжает HY2XS_PUBLIC_HOST. Добавлен инвариант публичного endpoint: A-записи обязаны принадлежать множеству публичных IPv4, назначенных интерфейсам этого сервера. Проверка живёт в общем preflight, поэтому действует в install, reconfigure и doctor. Адрес определяется локально, без внешних сервисов определения IP. Строгость управляется HY2XS_PUBLIC_ENDPOINT_POLICY (strict по умолчанию); отсутствие A-записи фатально при любом значении. TS-санитайзер приведён к той же формулировке, что и Go: URL-значение определяется по самому значению, а не по имени ключа.
This commit is contained in:
+17
-16
@@ -21,20 +21,28 @@ set -euo pipefail
|
||||
|
||||
APPLY="false"
|
||||
CONFIRMED="false"
|
||||
KEEP_HYSTERIA_BINARY="false"
|
||||
|
||||
log() { printf '[hy2xs-purge] %s\n' "$*"; }
|
||||
warn() { printf '[hy2xs-purge] WARNING: %s\n' "$*" >&2; }
|
||||
fail() { printf '[hy2xs-purge] ERROR: %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
# Флага «оставить бинарник Hysteria» здесь нет намеренно.
|
||||
#
|
||||
# /usr/local/bin/hysteria входит в список legacy-маркеров clean-host
|
||||
# контракта установщика. Скрипт, который оставлял бы его и при этом печатал
|
||||
# «хост чист для установки HY2XS v1», прямо противоречил бы следующему
|
||||
# запуску install.sh: тот отказался бы ставиться.
|
||||
#
|
||||
# Полезного сценария у флага тоже не было: свежая установка всё равно кладёт
|
||||
# собственную проверенную по SHA-256 версию Hysteria.
|
||||
|
||||
usage() {
|
||||
cat >&2 <<'EOF'
|
||||
Usage: purge-v0.sh [--apply --yes-i-know] [--keep-hysteria-binary]
|
||||
Usage: purge-v0.sh [--apply --yes-i-know]
|
||||
|
||||
(без флагов) показать план очистки и выйти
|
||||
--apply выполнить очистку
|
||||
--yes-i-know подтверждение: обязателен вместе с --apply
|
||||
--keep-hysteria-binary не удалять /usr/local/bin/hysteria
|
||||
(без флагов) показать план очистки и выйти
|
||||
--apply выполнить очистку
|
||||
--yes-i-know подтверждение: обязателен вместе с --apply
|
||||
|
||||
Скрипт удаляет службы, приложение, конфигурацию и БАЗУ ДАННЫХ админки.
|
||||
EOF
|
||||
@@ -46,7 +54,6 @@ parse_args() {
|
||||
case "$1" in
|
||||
--apply) APPLY="true"; shift ;;
|
||||
--yes-i-know) CONFIRMED="true"; shift ;;
|
||||
--keep-hysteria-binary) KEEP_HYSTERIA_BINARY="true"; shift ;;
|
||||
-h|--help) usage ;;
|
||||
*) fail "unknown argument: $1" ;;
|
||||
esac
|
||||
@@ -120,11 +127,7 @@ show_plan() {
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$KEEP_HYSTERIA_BINARY" = "true" ]; then
|
||||
log "/usr/local/bin/hysteria будет сохранён (--keep-hysteria-binary)"
|
||||
else
|
||||
log "будет удалён /usr/local/bin/hysteria"
|
||||
fi
|
||||
log "будет удалён /usr/local/bin/hysteria"
|
||||
|
||||
log "из /etc/nftables.conf будет убрана строка include для $NFT_FRAGMENT"
|
||||
warn "БАЗА ДАННЫХ админки (/var/lib/hy2xs-admin) удаляется: пиры и их ссылки будут потеряны"
|
||||
@@ -164,9 +167,7 @@ remove_paths() {
|
||||
rm -rf "$path"
|
||||
done
|
||||
|
||||
if [ "$KEEP_HYSTERIA_BINARY" != "true" ]; then
|
||||
rm -f /usr/local/bin/hysteria
|
||||
fi
|
||||
rm -f /usr/local/bin/hysteria
|
||||
}
|
||||
|
||||
# Из /etc/nftables.conf убирается только include HY2XS: остальной ruleset
|
||||
@@ -202,7 +203,7 @@ verify_clean_host() {
|
||||
[ -e "$path" ] && leftovers+=("$path")
|
||||
done
|
||||
|
||||
if [ "$KEEP_HYSTERIA_BINARY" != "true" ] && [ -e /usr/local/bin/hysteria ]; then
|
||||
if [ -e /usr/local/bin/hysteria ]; then
|
||||
leftovers+=(/usr/local/bin/hysteria)
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user