import asyncio import os import shutil import sys from pathlib import Path # Add backend to path sys.path.append(os.path.join(os.getcwd(), "backend")) from app.services.infrastructure.storage.backup_service import get_backup_manager async def verify_disaster_recovery(): print("๐Ÿš€ Starting Disaster Recovery Verification...") # Set environment variables for config app_data_dir = os.path.expanduser("~/.zenith") db_path = f"{app_data_dir}/fraud_detection.db" backup_dir = os.path.join(os.getcwd(), "data/backups_verify") os.environ["BACKUP_DIR"] = backup_dir os.environ["DATABASE_PATH"] = db_path os.environ["EVIDENCE_DIR"] = os.path.join(os.getcwd(), "data/evidence_verify") os.environ["CONFIG_DIR"] = os.path.join(os.getcwd(), "data/config_verify") # Ensure app data dir exists for verification os.makedirs(app_data_dir, exist_ok=True) backup_manager = await get_backup_manager() print(f"โœ… Backup directory: {backup_dir}") print(f"โœ… Database path: {db_path}") # 2. Create a full backup print("\n๐Ÿ’พ Creating Full Backup...") try: backup_info = await backup_manager.create_full_backup(reason="DR Verification") print(f"โœ… Backup created: {backup_info['id']}") print(f"โœ… Size: {backup_info['size_bytes']} bytes") print(f"โœ… Hash: {backup_info['integrity_hash']}") except Exception as e: print(f"โŒ Backup failed: {e}") return # 3. Verify integrity print("\n๐Ÿ” Verifying Integrity...") verification = await backup_manager.verify_backup_integrity(backup_info["id"]) if verification["valid"]: print("โœ… Integrity check passed!") else: print(f"โŒ Integrity check failed: {verification.get('error')}") return # 4. Simulate disaster (move DB) print("\n๐Ÿ”ฅ Simulating Disaster (Data Loss)...") original_db_path = Path(db_path) if not original_db_path.exists(): # Create a dummy one if it doesn't exist for the test print("โš ๏ธ Database didn't exist, creating dummy for test...") with open(original_db_path, "w") as f: f.write("DUMMY DATA") temp_loss_path = original_db_path.with_suffix(".lost") shutil.move(original_db_path, temp_loss_path) print(f"โœ… Original database moved to: {temp_loss_path}") print(f"โœ… Database exists: {original_db_path.exists()}") # 5. Restore from backup print("\n๐Ÿฅ Restoring from Backup...") restore_target = os.path.join(os.getcwd(), "data/restore_verify") restore_result = await backup_manager.restore_backup( backup_info["id"], target_dir=restore_target ) if restore_result["success"]: print("โœ… Restore operation reported success!") # BackupManager.restore_backup also copies back to original path if target_dir is None, # but since we specified target_dir, we need to check the components # Verify components were restored restored_db = Path(restore_target) / backup_info["id"] / "database.db" if restored_db.exists(): print(f"โœ… Component verified: {restored_db}") else: print("โŒ Restored component missing!") # The _restore_database method also attempts to restore to config["database_path"] if original_db_path.exists(): print(f"โœ… Database restored to original location: {original_db_path}") else: print("โŒ Database NOT restored to original location!") else: print(f"โŒ Restore failed: {restore_result.get('error')}") # 1. Cleanup print("\n๐Ÿงน Cleaning Up...") if original_db_path.exists() and temp_loss_path.exists(): os.remove(temp_loss_path) print("โœ… Simualted loss file removed.") if os.path.exists(backup_dir): shutil.rmtree(backup_dir) print("โœ… Verification backups removed.") if os.path.exists(restore_target): shutil.rmtree(restore_target) print("โœ… Verification restore directory removed.") print("\nโœจ Disaster Recovery Verification COMPLETED SUCCESSFULLY!") if __name__ == "__main__": asyncio.run(verify_disaster_recovery())