feat: add cross-host SSH trust, state-aware teardown, and configurable migration polling

- Add setup/cross_host_ssh.sh to establish ed25519 SSH trust between
  Unraid and Fedora (required by backup/restore scripts for direct SCP)
- Add ssh_key and authorized_key cleanup handlers to setup/cleanup.sh
- Rewrite phase8 cutover to mark GitHub repos as mirrors instead of
  archiving them (archived repos reject push mirror writes), with a
  JSON state snapshot of pre-cutover settings (description, homepage,
  wiki, projects, Pages) for exact restoration on teardown
- Rewrite phase8 teardown to restore from state snapshot with fallback
  to legacy "— was:" description parsing
- Make migration polling configurable via MIGRATION_POLL_INTERVAL_SEC
  and MIGRATION_POLL_TIMEOUT_SEC in .env (was hardcoded 120s/3s)
- Fix preflight SSL validation: check SSL_MODE instead of always
  requiring SSL_EMAIL, add conditional checks per SSL_MODE
- Add preflight checks 23-24: cross-host SSH connectivity
- Add --start-from range validation and cross_host_ssh.sh to run_all.sh

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
S
2026-02-28 20:50:41 -05:00
parent dc08375ad0
commit 316d318b5e
8 changed files with 509 additions and 31 deletions

View File

@@ -116,7 +116,7 @@ REQUIRED_VARS=(
GITHUB_USERNAME GITHUB_TOKEN
REPO_1_NAME REPO_2_NAME REPO_3_NAME
GITHUB_MIRROR_TOKEN
NGINX_CONTAINER_NAME NGINX_CONF_PATH SSL_EMAIL
NGINX_CONTAINER_NAME NGINX_CONF_PATH SSL_MODE
)
check_required_vars() {
@@ -127,6 +127,33 @@ check_required_vars() {
missing=1
fi
done
# SSL vars are conditional on SSL_MODE:
# - letsencrypt => SSL_EMAIL is required
# - existing => SSL_CERT_PATH + SSL_KEY_PATH are required
case "${SSL_MODE:-}" in
letsencrypt)
if [[ -z "${SSL_EMAIL:-}" ]]; then
log_error " → Missing required var: SSL_EMAIL (required when SSL_MODE=letsencrypt)"
missing=1
fi
;;
existing)
if [[ -z "${SSL_CERT_PATH:-}" ]]; then
log_error " → Missing required var: SSL_CERT_PATH (required when SSL_MODE=existing)"
missing=1
fi
if [[ -z "${SSL_KEY_PATH:-}" ]]; then
log_error " → Missing required var: SSL_KEY_PATH (required when SSL_MODE=existing)"
missing=1
fi
;;
*)
log_error " → Invalid SSL_MODE='${SSL_MODE:-<empty>}' (must be 'letsencrypt' or 'existing')"
missing=1
;;
esac
return $missing
}
check 6 "All required .env vars are set" check_required_vars
@@ -348,6 +375,30 @@ check_fedora_versions() {
}
check 22 "Fedora tool minimum versions (docker>=20, compose>=2, jq>=1.6)" check_fedora_versions
# ---------------------------------------------------------------------------
# Check 23: Unraid can SSH to Fedora (required for backup transfer)
# ---------------------------------------------------------------------------
check_unraid_to_fedora_ssh() {
ssh_exec UNRAID "ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new -o BatchMode=yes -p '${FEDORA_SSH_PORT:-22}' '${FEDORA_SSH_USER}@${FEDORA_IP}' true" &>/dev/null
}
check 23 "Unraid can SSH to Fedora (host-to-host backup path)" check_unraid_to_fedora_ssh
if ! check_unraid_to_fedora_ssh 2>/dev/null; then
log_error " → Unraid cannot SSH to Fedora with key auth (needed by backup/backup_primary.sh)."
log_error " → Configure SSH keys so Unraid can run: ssh ${FEDORA_SSH_USER}@${FEDORA_IP}"
fi
# ---------------------------------------------------------------------------
# Check 24: Fedora can SSH to Unraid (required for restore transfer)
# ---------------------------------------------------------------------------
check_fedora_to_unraid_ssh() {
ssh_exec FEDORA "ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new -o BatchMode=yes -p '${UNRAID_SSH_PORT:-22}' '${UNRAID_SSH_USER}@${UNRAID_IP}' true" &>/dev/null
}
check 24 "Fedora can SSH to Unraid (host-to-host restore path)" check_fedora_to_unraid_ssh
if ! check_fedora_to_unraid_ssh 2>/dev/null; then
log_error " → Fedora cannot SSH to Unraid with key auth (needed by backup/restore_to_primary.sh)."
log_error " → Configure SSH keys so Fedora can run: ssh ${UNRAID_SSH_USER}@${UNRAID_IP}"
fi
# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------