montana/Russian/Genesis/ГЕНЕЗИС_2026-05-09_00-00_UTC/bootstrap-узла.sh

130 lines
5.1 KiB
Bash
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.

#!/usr/bin/env bash
# Bootstrap нового узла Montana из Genesis 2026-05-09 00:00 UTC.
#
# Скрипт делает четыре вещи:
# 1. Находит живой источник Genesis (перебор IP-пула, далее TON DNS).
# 2. Клонирует репозиторий `Ничто` локально.
# 3. Проверяет МАНИФЕСТ.md по ed25519-подписи Genesis root pubkey.
# 4. Сверяет SHA-256 каждого файла с тем, что в манифесте.
#
# Использование:
# curl -sfL https://<любой-mirror>/montana.git/raw/main/.../bootstrap-узла.sh | bash
# или
# bash ./bootstrap-узла.sh [целевая_папка]
#
# Запуск без root. Зависимости: git, python3, curl, openssl.
set -euo pipefail
# --- Genesis-параметры (вшиты, не должны меняться) ---
ROOT_PUBKEY_B64="MtE485L/O87feImV8XjSdPPskgestVd7mqJvKo9MRas="
ROOT_FP="e4eb11c9d198ab80"
GENESIS_FOLDER="Montana/Russian/Genesis/ГЕНЕЗИС_2026-05-09_00-00_UTC"
# IP-пул реплицируемых узлов (обновляется только при новом Genesis)
IP_POOL=(
"91.132.142.42" # Helsinki (Hetzner AS24940)
"89.19.208.158" # Frankfurt (Timeweb AS9123)
"176.124.208.93" # Moscow (Timeweb AS9123, master/Gitea)
)
# Доменные источники (DNS + TON DNS)
DOMAINS=(
"hub.montana.quest/efir369999/montana"
"junomoneta.ton/montana"
)
TARGET="${1:-$HOME/montana-node}"
log() { echo "[bootstrap] $*" >&2; }
fail() { echo "[bootstrap] FATAL: $*" >&2; exit 1; }
# --- 1. Найти живой источник ---
SOURCE=""
log "Поиск живого Genesis-источника..."
for dom in "${DOMAINS[@]}"; do
if curl -fsI --max-time 5 "https://${dom}.git/info/refs?service=git-upload-pack" >/dev/null 2>&1; then
SOURCE="https://${dom}.git"
log "Найден: $SOURCE"
break
fi
done
if [[ -z "$SOURCE" ]]; then
for ip in "${IP_POOL[@]}"; do
if curl -fsI --max-time 5 -k "https://${ip}/montana.git/info/refs?service=git-upload-pack" >/dev/null 2>&1; then
SOURCE="https://${ip}/montana.git"
log "Найден IP-fallback: $SOURCE"
break
fi
done
fi
[[ -z "$SOURCE" ]] && fail "ни один Genesis-источник не отвечает (домены и IP-пул)"
# --- 2. Клонирование ---
log "Клонирование $SOURCE$TARGET"
mkdir -p "$(dirname "$TARGET")"
GIT_LFS_SKIP_SMUDGE=1 git clone --depth=1 --no-tags "$SOURCE" "$TARGET"
# --- 3. Проверка подписи манифеста ---
GDIR="$TARGET/$GENESIS_FOLDER"
[[ -d "$GDIR" ]] || fail "Genesis-папка не найдена в репозитории: $GDIR"
MANIFEST="$GDIR/МАНИФЕСТ.md"
[[ -f "$MANIFEST" ]] || fail "МАНИФЕСТ.md отсутствует"
log "Проверка ed25519-подписи манифеста против root pubkey $ROOT_FP"
python3 - "$MANIFEST" "$ROOT_PUBKEY_B64" "$GDIR" <<'PY'
import sys, base64, re, hashlib, pathlib
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
from cryptography.exceptions import InvalidSignature
manifest_path, pubkey_b64, gdir = sys.argv[1], sys.argv[2], sys.argv[3]
text = pathlib.Path(manifest_path).read_text()
m_files = re.search(r'## Файлы\n\n```\n(.*?)\n```', text, re.S)
m_sig = re.search(r'## Подпись.*?```\n(\S+)\n```', text, re.S)
m_pk = re.search(r'## Корневой ключ.*?```\n(\S+)\n```', text, re.S)
if not (m_files and m_sig and m_pk):
sys.exit("[bootstrap] FATAL: манифест повреждён, не удалось распарсить блоки")
if m_pk.group(1) != pubkey_b64:
sys.exit(f"[bootstrap] FATAL: pubkey в манифесте ({m_pk.group(1)[:20]}…) не совпадает со вшитым корнем")
body = m_files.group(1) + '\n'
sig = base64.b64decode(m_sig.group(1))
pk = Ed25519PublicKey.from_public_bytes(base64.b64decode(pubkey_b64))
try:
pk.verify(sig, body.encode())
except InvalidSignature:
sys.exit("[bootstrap] FATAL: подпись манифеста НЕ ПРОВЕРЕНА — источник возможно подменён")
print("[bootstrap] ✓ подпись манифеста валидна")
bad = []
for line in body.strip().split('\n'):
sha, fname = line.split(' ', 1)
p = pathlib.Path(gdir) / fname
if not p.exists():
bad.append(f" отсутствует: {fname}")
continue
actual = hashlib.sha256(p.read_bytes()).hexdigest()
if actual != sha:
bad.append(f" hash mismatch {fname}: expected {sha[:12]}…, got {actual[:12]}…")
if bad:
print("[bootstrap] FATAL: содержимое не совпадает с манифестом")
for b in bad: print(b)
sys.exit(1)
print(f"[bootstrap] ✓ {len(body.strip().splitlines())} файлов прошли SHA-256-сверку")
PY
log "Bootstrap завершён. Genesis: $GDIR"
log "Дальше: montana-node init --from-folder $TARGET --genesis $GENESIS_FOLDER"