From 970f0037c187bfce444d21faddd8dda2a249557b Mon Sep 17 00:00:00 2001 From: Ekezie Uchechukwu Date: Thu, 26 Mar 2026 13:30:29 +0100 Subject: [PATCH] feat: add automated backup system and disaster recovery plan Add scripts/backup.sh: - Timestamped backups of contracts, deployments, and config - SHA-256 checksums for integrity verification - Automatic rotation (keeps last 30 backups) - Redacts sensitive .env values in backups - Cron-compatible for 6-hour scheduling Add docs/DISASTER_RECOVERY.md: - Backup strategy and schedule - Step-by-step recovery for contracts, config, bridge, oracle - Data integrity verification procedure - Severity-based escalation matrix Closes #106 --- docs/DISASTER_RECOVERY.md | 98 +++++++++++++++++++++++++++++++++++++++ scripts/backup.sh | 78 +++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+) create mode 100644 docs/DISASTER_RECOVERY.md create mode 100755 scripts/backup.sh diff --git a/docs/DISASTER_RECOVERY.md b/docs/DISASTER_RECOVERY.md new file mode 100644 index 000000000..d9b5a1ae3 --- /dev/null +++ b/docs/DISASTER_RECOVERY.md @@ -0,0 +1,98 @@ +# PropChain Disaster Recovery Plan + +## Backup Strategy + +### Automated Backups + +Run `scripts/backup.sh` on a schedule (recommended: every 6 hours): + +```bash +# Cron entry +0 */6 * * * /path/to/propchain/scripts/backup.sh /path/to/backups +``` + +**What is backed up:** +- Contract source code and configuration +- Deployment artifacts (addresses, ABIs) +- Environment structure (values redacted) +- Workspace manifest (Cargo.toml, Cargo.lock) +- SHA-256 checksums for integrity verification + +**Retention:** Last 30 backups (configurable via `MAX_BACKUPS`). + +### Manual Backup + +```bash +./scripts/backup.sh ./my-backups +``` + +## Recovery Procedures + +### 1. Contract State Recovery + +On-chain state is inherently backed up by the blockchain. Recovery means +redeploying contracts and restoring configuration: + +```bash +# Restore from backup +tar -xzf propchain_backup_TIMESTAMP.tar.gz +cd propchain_backup_TIMESTAMP + +# Verify checksums +sha256sum -c checksums.sha256 + +# Redeploy contracts +cd contracts && cargo contract build --release +``` + +### 2. Configuration Recovery + +```bash +# Restore Cargo.toml and Cargo.lock +cp Cargo.toml Cargo.lock /path/to/project/ + +# Recreate .env from structure +cp env_structure.txt /path/to/project/.env +# Fill in actual values manually +``` + +### 3. Bridge Recovery + +If a bridge operation fails: + +1. Call `recover_failed_bridge(request_id, RecoveryAction::RetryBridge)` +2. If retry fails, use `RecoveryAction::CancelBridge` to release funds +3. Use `RecoveryAction::RefundGas` to compensate for failed gas + +### 4. Oracle Recovery + +If oracle sources are compromised: + +1. Pause the oracle via admin +2. Remove compromised sources (reputation drops below threshold) +3. Re-register trusted sources +4. Unpause after verification + +## Data Integrity Checks + +Run after any recovery: + +```bash +# Verify backup integrity +sha256sum -c checksums.sha256 + +# Verify contract compilation +cargo contract build --release + +# Run test suite +cargo test --workspace +``` + +## Escalation + +| Severity | Response Time | Action | +|----------|--------------|--------| +| Low | 24 hours | Standard recovery procedure | +| Medium | 4 hours | Pause affected contracts, notify team | +| High | 1 hour | Emergency pause all contracts, investigate | +| Critical | Immediate | Emergency pause + bridge lockdown | diff --git a/scripts/backup.sh b/scripts/backup.sh new file mode 100755 index 000000000..9225e4547 --- /dev/null +++ b/scripts/backup.sh @@ -0,0 +1,78 @@ +#!/bin/bash +# ============================================================================= +# PropChain Automated Backup Script +# ============================================================================= +# Creates timestamped backups of contract state, configuration, and metadata. +# Designed for cron scheduling: 0 */6 * * * /path/to/backup.sh +# +# Usage: ./backup.sh [backup_dir] +# ============================================================================= + +set -euo pipefail + +BACKUP_DIR="${1:-./backups}" +TIMESTAMP=$(date +%Y%m%d_%H%M%S) +BACKUP_NAME="propchain_backup_${TIMESTAMP}" +BACKUP_PATH="${BACKUP_DIR}/${BACKUP_NAME}" +MAX_BACKUPS=30 # Keep last 30 backups + +echo "=== PropChain Backup: ${TIMESTAMP} ===" + +# Create backup directory +mkdir -p "${BACKUP_PATH}" + +# 1. Backup contract source and configuration +echo "[1/4] Backing up contract source..." +tar -czf "${BACKUP_PATH}/contracts.tar.gz" \ + --exclude='target' \ + --exclude='*.wasm' \ + contracts/ 2>/dev/null || echo "Warning: contracts directory not found" + +# 2. Backup deployment artifacts +echo "[2/4] Backing up deployment artifacts..." +if [ -d "deployments" ]; then + cp -r deployments/ "${BACKUP_PATH}/deployments/" +fi + +# Export contract addresses and metadata if available +if command -v cargo-contract &> /dev/null; then + echo " Exporting contract metadata..." + for contract_dir in contracts/*/; do + contract_name=$(basename "${contract_dir}") + if [ -f "${contract_dir}/Cargo.toml" ]; then + echo " - ${contract_name}" + fi + done > "${BACKUP_PATH}/contract_inventory.txt" 2>/dev/null || true +fi + +# 3. Backup configuration and environment +echo "[3/4] Backing up configuration..." +if [ -f ".env" ]; then + # Strip sensitive values, keep structure + sed 's/=.*/=/' .env > "${BACKUP_PATH}/env_structure.txt" +fi + +# Copy non-sensitive config files +for config_file in Cargo.toml Cargo.lock; do + [ -f "${config_file}" ] && cp "${config_file}" "${BACKUP_PATH}/" +done + +# 4. Create integrity checksum +echo "[4/4] Computing checksums..." +find "${BACKUP_PATH}" -type f -exec sha256sum {} \; > "${BACKUP_PATH}/checksums.sha256" + +# Compress the full backup +tar -czf "${BACKUP_DIR}/${BACKUP_NAME}.tar.gz" -C "${BACKUP_DIR}" "${BACKUP_NAME}" +rm -rf "${BACKUP_PATH}" + +echo "Backup created: ${BACKUP_DIR}/${BACKUP_NAME}.tar.gz" + +# Rotate old backups +BACKUP_COUNT=$(ls -1 "${BACKUP_DIR}"/propchain_backup_*.tar.gz 2>/dev/null | wc -l) +if [ "${BACKUP_COUNT}" -gt "${MAX_BACKUPS}" ]; then + REMOVE_COUNT=$((BACKUP_COUNT - MAX_BACKUPS)) + ls -1t "${BACKUP_DIR}"/propchain_backup_*.tar.gz | tail -n "${REMOVE_COUNT}" | xargs rm -f + echo "Rotated ${REMOVE_COUNT} old backup(s)" +fi + +echo "=== Backup complete ==="