Replaces manual pipe-delimited file editing with a guided setup
script matching the configure_env.sh UX pattern.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move 10 validation functions from configure_env.sh to lib/common.sh as
shared utilities. Define variable-to-validator mapping using parallel
arrays (bash 3.2 compatible). validate_env() checks all ~50 .env
variables against their expected format and reports all failures at once.
Wired into preflight.sh (Check 6b) and bitwarden_to_env.sh (post-restore).
configure_env.sh now sources validators from common.sh instead of
defining its own copies.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 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>
- teardown_all.sh: replace `yes |` pipeline with `< <(yes)` process
substitution to avoid SIGPIPE (exit 141) false failures under pipefail
- phase6_teardown.sh: extract push mirror `.id` instead of `.remote_name`
to match the DELETE /push_mirrors/{id} API contract
- phase5_migrate_pipelines.sh: expand sed regex from `[a-z_]*` to
`[a-z_.]*` to handle nested GitHub contexts like
`github.event.pull_request.number`
- lib/common.sh: render_template now requires explicit variable list to
prevent envsubst from eating Nginx variables ($host, $proxy_add_...)
- backup scripts: remove MacBook relay, use direct Unraid↔Fedora SCP;
fix dump path to write to /data/ (mounted volume) instead of /tmp/
(container-only); add unzip -t integrity verification
- preflight.sh: add --skip-port-checks flag for resuming with
--start-from (ports already bound by earlier phases)
- run_all.sh: update run_step to pass extra args; use --skip-port-checks
when --start-from > 1
- post-checks (phase4/7/9): wrap API calls in helper functions with
>/dev/null redirection instead of passing -o /dev/null as API data
- phase8: replace GitHub archiving with [MIRROR] description marking
and disable wiki/projects/Pages (archived repos reject push mirrors)
- restore_to_primary.sh: add require_vars for Fedora SSH variables
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add minimum version validation for all dependencies across local and
remote machines (jq>=1.6, curl>=7.70, git>=2.30, docker>=20.0,
compose>=2.0, shellcheck>=0.8, gh>=2.0). Setup scripts now record
every install action to .manifests/<host>.manifest files, enabling
full rollback via setup/cleanup.sh. teardown_all.sh gains --cleanup
flag to chain prerequisite removal after phase teardowns.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- lib/common.sh: add require_local_os, require_remote_os, require_remote_pkg_manager
- setup/macbook.sh: require macOS (Darwin)
- setup/unraid.sh: require remote is Linux
- setup/fedora.sh: require remote is Linux + has dnf (RPM-based)
- manage_runner.sh: native runner add/remove requires macOS
- run_all.sh: control plane must be macOS
- preflight.sh: 3 new checks (1: local=macOS, 2: Unraid=Linux, 3: Fedora=Linux+dnf)
- phase5_migrate_pipelines.sh: fix sed -i to be portable (no macOS-only syntax)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- phase1_gitea_unraid.sh: 9-step deploy (dirs, docker-compose, app.ini,
container start, wait, admin user, API token, save to .env, create org).
Every step has idempotency check — running twice changes nothing.
- phase1_post_check.sh: 5 independent verification checks
- phase1_teardown.sh: stop container + optionally remove data, with prompts
Also adds inline comments to lib/common.sh and preflight.sh explaining
WHY decisions were made (SSH flags, API tmpfile pattern, port checks, etc.)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
16 checks: .env exists, runners.conf exists, 24 required vars non-empty,
SSH to Unraid/Fedora, Docker + docker-compose on both servers, ports free,
DNS resolution, GitHub token valid, GitHub repos exist, Nginx running,
Nginx conf dir writable. Runs ALL checks even if earlier ones fail.
Exits 0 only if all 16 pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document all Gitea REST API v1 and GitHub REST API endpoints used across
phases 1-9. Each endpoint includes: method, path, request/response schemas,
status codes, and which script uses it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
17 functions: logging (info/warn/error/success/step/phase_header),
env management (load_env/save_env_var/require_vars), SSH wrappers
(ssh_exec/ssh_check/scp_to), API wrappers (gitea_api/gitea_backup_api/
github_api), template rendering, and polling (wait_for_http/wait_for_ssh).
All logs go to stderr, JSON data to stdout. Shellcheck clean.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- .gitignore: excludes .env, runners.conf, certs, temp files, editor files
- .env.example: all configuration variables with sections and descriptions
- runners.conf.example: dynamic runner definition format (pipe-delimited)
- PLAN.md: comprehensive implementation plan with DoD for all 18 milestones
- CLAUDE.md: project conventions and instructions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>