#!/usr/bin/env bash set -euo pipefail # === METADATA === SCRIPT_NAME="$(basename "$0")" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SKILL_ROOT="$(dirname "$SCRIPT_DIR")" # === CONFIGURATION === : "${OUTPUT_DIR:=$SKILL_ROOT/outputs}" : "${AGE_IDENTITY_FILE:=}" : "${DRY_RUN:=1}" : "${REQUIRE_CONFIRM:=1}" : "${CONFIRM_PHRASE:=I UNDERSTAND THIS WILL CREATE AND ENCRYPT BACKUPS}" # === FUNCTIONS === log_info() { echo "[INFO] $(date -Iseconds) $*"; } log_warn() { echo "[WARN] $(date -Iseconds) $*" >&2; } log_error() { echo "[ERROR] $(date -Iseconds) $*" >&2; } die() { log_error "$@"; exit 1; } require_confirm() { [[ "$DRY_RUN" == "0" ]] || die "DRY_RUN=$DRY_RUN (set DRY_RUN=0 to apply)." if [[ "$REQUIRE_CONFIRM" == "1" ]]; then echo "" echo "RESTORE DRILL - CONFIRMATION REQUIRED" echo "This will decrypt and extract the backup to verify recoverability." echo "Type the phrase exactly to continue:" echo " $CONFIRM_PHRASE" read -r input [[ "$input" == "$CONFIRM_PHRASE" ]] || die "Confirmation phrase mismatch; aborting." fi } main() { require_confirm local last_run_file="$OUTPUT_DIR/last_run_dir.txt" [[ -f "$last_run_file" ]] || die "No last run pointer. Run 11_backup_apply.sh first." local run_dir run_dir="$(cat "$last_run_file")" # Find encrypted archive local encrypted="" if [[ -f "$run_dir/archive.tar.gz.age" ]]; then encrypted="$run_dir/archive.tar.gz.age" else die "Missing encrypted archive. Run 21_encrypt_apply.sh first." fi [[ -n "$AGE_IDENTITY_FILE" ]] || die "AGE_IDENTITY_FILE is required for restore drill." [[ -f "$AGE_IDENTITY_FILE" ]] || die "AGE_IDENTITY_FILE not found: $AGE_IDENTITY_FILE" # Create temp directory for restore local restore_dir restore_dir=$(mktemp -d) log_info "Restore drill temp directory: $restore_dir" local decrypted="$restore_dir/archive.tar.gz" # Decrypt log_info "Decrypting archive..." age -d -i "$AGE_IDENTITY_FILE" -o "$decrypted" "$encrypted" log_info "Decryption successful." # Extract log_info "Extracting archive..." mkdir -p "$restore_dir/extract" tar -xzf "$decrypted" -C "$restore_dir/extract" # Count files local file_count file_count=$(find "$restore_dir/extract" -type f | wc -l | tr -d ' ') if [[ "$file_count" -eq 0 ]]; then die "Restore drill FAILED: No files extracted." fi log_info "Extracted $file_count files." # Save restore pointer echo "$restore_dir" > "$run_dir/last_restore_dir.txt" log_info "Saved restore pointer: $run_dir/last_restore_dir.txt" echo "" log_info "==========================================" log_info " RESTORE DRILL: PASSED" log_info " Files restored: $file_count" log_info " Location: $restore_dir/extract" log_info "==========================================" echo "" log_info "Restore drill complete." log_info "Next: ./scripts/90_verify.sh then ./scripts/99_report.sh" } [[ "${BASH_SOURCE[0]}" == "$0" ]] && main "$@"