#!/usr/bin/env bash set -euo pipefail # ============================================================================= # phase8_teardown.sh — Reverse the cutover: remove HTTPS, restore GitHub repos # Steps: # 1. Stop + remove Caddy container and compose file # 2. Optionally remove Caddy data (certs, config) # 3. Restore GitHub repo settings from the saved Phase 8 state snapshot # ============================================================================= SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" source "${SCRIPT_DIR}/lib/common.sh" load_env require_vars UNRAID_IP UNRAID_SSH_USER \ GITEA_DOMAIN CADDY_DATA_PATH \ GITHUB_USERNAME GITHUB_TOKEN \ REPO_NAMES log_warn "=== Phase 8 Teardown: Cutover ===" read -ra REPOS <<< "$REPO_NAMES" PHASE8_STATE_FILE="$(_project_root)/.manifests/phase8_github_repo_state.json" github_pages_http_code() { local repo="$1" curl -s -o /dev/null -w "%{http_code}" \ -H "Authorization: token ${GITHUB_TOKEN}" \ -H "Accept: application/json" \ "https://api.github.com/repos/${GITHUB_USERNAME}/${repo}/pages" 2>/dev/null || echo "000" } # --------------------------------------------------------------------------- # Step 1: Stop + remove Caddy container # --------------------------------------------------------------------------- CONTAINER_STATUS=$(ssh_exec UNRAID "docker ps --filter name=caddy --format '{{.Status}}'" 2>/dev/null || true) if [[ "$CONTAINER_STATUS" == *"Up"* ]]; then printf 'Stop and remove Caddy container? [y/N] ' read -r confirm if [[ "$confirm" =~ ^[Yy]$ ]]; then ssh_exec UNRAID "cd '${CADDY_DATA_PATH}' && docker compose down 2>/dev/null || docker-compose down" log_success "Caddy container stopped and removed" else log_info "Caddy container preserved" fi else log_info "Caddy container not running" fi # Remove Caddy compose + Caddyfile if ssh_exec UNRAID "test -f '${CADDY_DATA_PATH}/docker-compose.yml'" 2>/dev/null; then ssh_exec UNRAID "rm -f '${CADDY_DATA_PATH}/docker-compose.yml' '${CADDY_DATA_PATH}/Caddyfile'" log_success "Removed Caddy config files" else log_info "Caddy config files already removed" fi # --------------------------------------------------------------------------- # Step 2: Optionally remove Caddy data (certs, config) # --------------------------------------------------------------------------- if ssh_exec UNRAID "test -d '${CADDY_DATA_PATH}/data'" 2>/dev/null; then printf 'Remove Caddy TLS data (certificates) for %s? [y/N] ' "$GITEA_DOMAIN" read -r confirm if [[ "$confirm" =~ ^[Yy]$ ]]; then ssh_exec UNRAID "rm -rf '${CADDY_DATA_PATH}/data' '${CADDY_DATA_PATH}/config'" log_success "Caddy TLS data removed" else log_info "Caddy TLS data preserved" fi fi # --------------------------------------------------------------------------- # Step 3: Restore GitHub repos # Primary path: restore from state snapshot written by phase8_cutover.sh. # Fallback path: if snapshot is missing, restore description from "— was: ..." # and use legacy defaults for homepage/wiki/projects. # --------------------------------------------------------------------------- printf 'Restore GitHub repo settings (description/homepage/wiki/projects/pages)? [y/N] ' read -r confirm if [[ "$confirm" =~ ^[Yy]$ ]]; then STATE_AVAILABLE=false if [[ -f "$PHASE8_STATE_FILE" ]]; then STATE_AVAILABLE=true log_info "Using saved Phase 8 state from ${PHASE8_STATE_FILE}" else log_warn "No Phase 8 state file found — using fallback restore behavior" fi RESTORE_ERRORS=0 for repo in "${REPOS[@]}"; do CURRENT_DESC=$(github_api GET "/repos/${GITHUB_USERNAME}/${repo}" 2>/dev/null | jq -r '.description // ""') RESTORE_DESC="" RESTORE_HOMEPAGE="" RESTORE_HAS_WIKI=true RESTORE_HAS_PROJECTS=true RESTORE_PAGES_ENABLED=false RESTORE_PAGES_CNAME="" RESTORE_PAGES_BRANCH="" RESTORE_PAGES_PATH="/" if [[ "$STATE_AVAILABLE" == "true" ]] && jq -e --arg repo "$repo" 'has($repo)' "$PHASE8_STATE_FILE" >/dev/null 2>&1; then REPO_STATE=$(jq -c --arg repo "$repo" '.[$repo]' "$PHASE8_STATE_FILE") RESTORE_DESC=$(printf '%s' "$REPO_STATE" | jq -r '.description // ""') RESTORE_HOMEPAGE=$(printf '%s' "$REPO_STATE" | jq -r '.homepage // ""') RESTORE_HAS_WIKI=$(printf '%s' "$REPO_STATE" | jq -r '.has_wiki // true') RESTORE_HAS_PROJECTS=$(printf '%s' "$REPO_STATE" | jq -r '.has_projects // true') RESTORE_PAGES_ENABLED=$(printf '%s' "$REPO_STATE" | jq -r '.pages_enabled // false') RESTORE_PAGES_CNAME=$(printf '%s' "$REPO_STATE" | jq -r '.pages_cname // ""') RESTORE_PAGES_BRANCH=$(printf '%s' "$REPO_STATE" | jq -r '.pages_source_branch // ""') RESTORE_PAGES_PATH=$(printf '%s' "$REPO_STATE" | jq -r '.pages_source_path // "/"') else if [[ "$CURRENT_DESC" != "[MIRROR]"* ]]; then log_info "GitHub repo ${repo} not marked as mirror and no snapshot found — skipping" continue fi if [[ "$CURRENT_DESC" == *" — was: "* ]]; then RESTORE_DESC="${CURRENT_DESC##* — was: }" fi fi # Restore description/homepage/wiki/projects RESTORE_PAYLOAD=$(jq -n \ --arg description "$RESTORE_DESC" \ --arg homepage "$RESTORE_HOMEPAGE" \ --argjson has_wiki "$RESTORE_HAS_WIKI" \ --argjson has_projects "$RESTORE_HAS_PROJECTS" \ '{ description: $description, homepage: $homepage, has_wiki: $has_wiki, has_projects: $has_projects }') if github_api PATCH "/repos/${GITHUB_USERNAME}/${repo}" "$RESTORE_PAYLOAD" >/dev/null 2>&1; then log_success "Restored GitHub repo settings: ${repo}" else log_error "Failed to restore GitHub repo: ${repo}" RESTORE_ERRORS=$((RESTORE_ERRORS + 1)) continue fi # Restore GitHub Pages state CURRENT_PAGES_CODE=$(github_pages_http_code "$repo") if [[ "$RESTORE_PAGES_ENABLED" == "true" ]]; then if [[ -z "$RESTORE_PAGES_BRANCH" ]]; then log_warn "Cannot restore Pages for ${repo}: missing source branch in saved state" RESTORE_ERRORS=$((RESTORE_ERRORS + 1)) continue fi PAGES_PAYLOAD=$(jq -n \ --arg branch "$RESTORE_PAGES_BRANCH" \ --arg path "$RESTORE_PAGES_PATH" \ --arg cname "$RESTORE_PAGES_CNAME" \ '{ source: { branch: $branch, path: $path } } + (if $cname != "" then {cname: $cname} else {} end)') if [[ "$CURRENT_PAGES_CODE" == "200" ]]; then if github_api PUT "/repos/${GITHUB_USERNAME}/${repo}/pages" "$PAGES_PAYLOAD" >/dev/null 2>&1; then log_success "Restored GitHub Pages config for ${repo}" else log_warn "Failed to update GitHub Pages config for ${repo}" RESTORE_ERRORS=$((RESTORE_ERRORS + 1)) fi else if github_api POST "/repos/${GITHUB_USERNAME}/${repo}/pages" "$PAGES_PAYLOAD" >/dev/null 2>&1; then log_success "Recreated GitHub Pages for ${repo}" else log_warn "Failed to recreate GitHub Pages for ${repo}" RESTORE_ERRORS=$((RESTORE_ERRORS + 1)) fi fi else if [[ "$CURRENT_PAGES_CODE" == "200" ]]; then if github_api DELETE "/repos/${GITHUB_USERNAME}/${repo}/pages" >/dev/null 2>&1; then log_info "Disabled GitHub Pages for ${repo} (matches pre-cutover state)" else log_warn "Failed to disable GitHub Pages for ${repo}" RESTORE_ERRORS=$((RESTORE_ERRORS + 1)) fi else log_info "GitHub Pages already disabled for ${repo}" fi fi done if [[ "$STATE_AVAILABLE" == "true" ]]; then if [[ "$RESTORE_ERRORS" -eq 0 ]]; then rm -f "$PHASE8_STATE_FILE" log_info "Removed saved Phase 8 state file after successful restore" else log_warn "Keeping Phase 8 state file due to restore errors: ${PHASE8_STATE_FILE}" fi fi else log_info "GitHub repos left as-is" fi log_success "Phase 8 teardown complete"