#!/bin/bash # # Business Central Backup Configuration Tester # Validates setup and connectivity before running actual backups # set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" CONFIG_FILE="${SCRIPT_DIR}/bc-backup.conf" # Colors GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' BLUE='\033[0;34m' NC='\033[0m' pass_count=0 warn_count=0 fail_count=0 echo_info() { echo -e "${BLUE}[INFO]${NC} $*" } echo_pass() { echo -e "${GREEN}[PASS]${NC} $*" ((pass_count++)) } echo_warn() { echo -e "${YELLOW}[WARN]${NC} $*" ((warn_count++)) } echo_fail() { echo -e "${RED}[FAIL]${NC} $*" ((fail_count++)) } check_command() { if command -v "$1" &> /dev/null; then echo_pass "$1 is installed ($(command -v "$1"))" return 0 else echo_fail "$1 is NOT installed" return 1 fi } check_config_var() { local var_name="$1" local var_value="${!var_name:-}" if [[ -z "$var_value" ]]; then echo_fail "$var_name is not set" return 1 elif [[ "$var_value" == *"your-"* ]] || [[ "$var_value" == *"example"* ]]; then echo_warn "$var_name looks like a placeholder value" return 1 else echo_pass "$var_name is set" return 0 fi } echo_info "==========================================" echo_info "BC Backup Configuration Tester" echo_info "==========================================" echo "" # Test 1: Configuration file exists echo_info "=== Test 1: Configuration File ===" if [[ -f "$CONFIG_FILE" ]]; then echo_pass "Configuration file exists: $CONFIG_FILE" # Check permissions perms=$(stat -c "%a" "$CONFIG_FILE" 2>/dev/null || stat -f "%A" "$CONFIG_FILE" 2>/dev/null) if [[ "$perms" == "600" ]] || [[ "$perms" == "400" ]]; then echo_pass "Configuration file has secure permissions ($perms)" else echo_warn "Configuration file permissions are $perms (recommend 600)" fi # Load configuration source "$CONFIG_FILE" else echo_fail "Configuration file not found: $CONFIG_FILE" echo_info "Run: cp bc-backup.conf.template bc-backup.conf" exit 1 fi echo "" # Test 2: Required commands echo_info "=== Test 2: Required Commands ===" check_command pwsh check_command gpg check_command aws || check_command s3cmd check_command curl echo "" # Test 3: Configuration variables echo_info "=== Test 3: Configuration Variables ===" check_config_var "AZURE_TENANT_ID" check_config_var "AZURE_CLIENT_ID" check_config_var "AZURE_CLIENT_SECRET" check_config_var "BC_ENVIRONMENT_NAME" check_config_var "ENCRYPTION_PASSPHRASE" check_config_var "S3_BUCKET" check_config_var "S3_ENDPOINT" check_config_var "AWS_ACCESS_KEY_ID" check_config_var "AWS_SECRET_ACCESS_KEY" echo "" # Test 4: Azure AD Authentication echo_info "=== Test 4: Azure AD Authentication ===" if command -v pwsh &> /dev/null; then echo_info "Testing Azure AD authentication..." auth_test=$(pwsh -Command " \$tokenUrl = 'https://login.microsoftonline.com/$AZURE_TENANT_ID/oauth2/v2.0/token' \$body = @{ client_id = '$AZURE_CLIENT_ID' client_secret = '$AZURE_CLIENT_SECRET' scope = 'https://api.businesscentral.dynamics.com/.default' grant_type = 'client_credentials' } try { \$response = Invoke-RestMethod -Uri \$tokenUrl -Method Post -Body \$body -ContentType 'application/x-www-form-urlencoded' -ErrorAction Stop Write-Output 'SUCCESS' } catch { Write-Output \"FAILED: \$_\" } " 2>&1) if [[ "$auth_test" == "SUCCESS" ]]; then echo_pass "Azure AD authentication successful" else echo_fail "Azure AD authentication failed" echo " Error: $auth_test" fi else echo_warn "Skipping Azure AD test (pwsh not installed)" fi echo "" # Test 5: S3 Connectivity echo_info "=== Test 5: S3 Connectivity ===" export AWS_ACCESS_KEY_ID export AWS_SECRET_ACCESS_KEY export AWS_DEFAULT_REGION if [[ "${S3_TOOL:-awscli}" == "awscli" ]] && command -v aws &> /dev/null; then echo_info "Testing S3 connectivity with AWS CLI..." if aws s3 ls "s3://${S3_BUCKET}/" --endpoint-url "${S3_ENDPOINT}" > /dev/null 2>&1; then echo_pass "S3 bucket is accessible: ${S3_BUCKET}" # Check Object Lock status echo_info "Checking Object Lock configuration..." lock_config=$(aws s3api get-object-lock-configuration \ --bucket "${S3_BUCKET}" \ --endpoint-url "${S3_ENDPOINT}" 2>&1 || echo "NOT_CONFIGURED") if [[ "$lock_config" != "NOT_CONFIGURED" ]] && [[ "$lock_config" != *"ObjectLockConfigurationNotFoundError"* ]]; then echo_pass "Object Lock is enabled on bucket" else echo_fail "Object Lock is NOT enabled on bucket" echo " Object Lock must be enabled at bucket creation" echo " See README.md for setup instructions" fi else echo_fail "Cannot access S3 bucket: ${S3_BUCKET}" echo " Check: S3_BUCKET, S3_ENDPOINT, AWS credentials" fi elif [[ "${S3_TOOL}" == "s3cmd" ]] && command -v s3cmd &> /dev/null; then echo_info "Testing S3 connectivity with s3cmd..." if s3cmd ls "s3://${S3_BUCKET}/" --host="${S3_ENDPOINT#*://}" > /dev/null 2>&1; then echo_pass "S3 bucket is accessible: ${S3_BUCKET}" echo_warn "s3cmd doesn't support Object Lock verification" echo " Install aws-cli for full Object Lock support" else echo_fail "Cannot access S3 bucket: ${S3_BUCKET}" fi else echo_warn "Skipping S3 test (no S3 tool available)" fi echo "" # Test 6: Directory permissions echo_info "=== Test 6: Directory Permissions ===" for dir in "logs" "temp"; do dir_path="${SCRIPT_DIR}/${dir}" if [[ -d "$dir_path" ]] && [[ -w "$dir_path" ]]; then echo_pass "Directory is writable: $dir" else echo_fail "Directory is not writable: $dir" echo " Run: mkdir -p $dir_path && chmod 755 $dir_path" fi done echo "" # Test 7: Script permissions echo_info "=== Test 7: Script Permissions ===" for script in "bc-backup.sh" "bc-export.ps1"; do script_path="${SCRIPT_DIR}/${script}" if [[ -f "$script_path" ]] && [[ -x "$script_path" ]]; then echo_pass "Script is executable: $script" else echo_warn "Script is not executable: $script" echo " Run: chmod +x $script_path" fi done echo "" # Test 8: GPG encryption test echo_info "=== Test 8: GPG Encryption Test ===" test_file=$(mktemp) test_encrypted=$(mktemp) test_decrypted=$(mktemp) echo "test data" > "$test_file" if echo "$ENCRYPTION_PASSPHRASE" | gpg \ --batch \ --yes \ --passphrase-fd 0 \ --symmetric \ --cipher-algo AES256 \ --output "$test_encrypted" \ "$test_file" 2>/dev/null; then echo_pass "GPG encryption successful" # Test decryption if echo "$ENCRYPTION_PASSPHRASE" | gpg \ --batch \ --yes \ --passphrase-fd 0 \ --decrypt \ --output "$test_decrypted" \ "$test_encrypted" 2>/dev/null; then if diff -q "$test_file" "$test_decrypted" &>/dev/null; then echo_pass "GPG decryption successful" else echo_fail "GPG decryption produced different output" fi else echo_fail "GPG decryption failed" fi else echo_fail "GPG encryption failed" fi rm -f "$test_file" "$test_encrypted" "$test_decrypted" echo "" # Summary echo_info "==========================================" echo_info "Test Summary" echo_info "==========================================" echo_pass "Passed: $pass_count" echo_warn "Warnings: $warn_count" echo_fail "Failed: $fail_count" echo "" if [[ $fail_count -eq 0 ]]; then echo_info "Configuration looks good!" echo_info "You can now run a test backup:" echo " ${SCRIPT_DIR}/bc-backup.sh" exit 0 elif [[ $fail_count -le 2 ]] && [[ $pass_count -ge 10 ]]; then echo_warn "Configuration has minor issues but may work" echo_warn "Review failed tests above" exit 0 else echo_fail "Configuration has significant issues" echo_fail "Please fix the failed tests before running backups" exit 1 fi