Build: $(date)
+Commit: $(git rev-parse HEAD 2>/dev/null || echo "unknown")
+Branch: $(git branch --show-current 2>/dev/null || echo "unknown")
+" >> "$TEST_RESULTS_DIR/test-summary.html" + head -100 "$log_file" >> "$TEST_RESULTS_DIR/test-summary.html" + echo "" >> "$TEST_RESULTS_DIR/test-summary.html" + fi + done + + echo "" >> "$TEST_RESULTS_DIR/test-summary.html" + + log "Test report generated: $TEST_RESULTS_DIR/test-summary.html" +} + +cleanup_test_environment() { + log "Cleaning up test environment" + + # Stop platform services + "$SCRIPT_DIR/platform_launcher.sh" stop || true + + # Clean up test data + rm -rf "$PROJECT_ROOT/test-data" || true +} + +main() { + local test_type="${1:-all}" + + log "Starting CI/CD test pipeline" + + # Set up error handling + trap cleanup_test_environment EXIT + + # Run tests + setup_test_environment + run_code_quality_checks + run_test_suite "$test_type" + generate_test_report + + log "CI/CD test pipeline completed" +} + +main "$@" +``` + +## Quality Gates and Metrics + +### Test Coverage Requirements +- Unit test coverage: ≥ 80% +- Integration test coverage: ≥ 70% +- Critical path coverage: 100% + +### Performance Benchmarks +- API response time: < 200ms (95th percentile) +- Container startup time: < 5 seconds +- AI inference latency: < 1 second +- System resource usage: < 80% + +### Security Requirements +- Zero high-severity vulnerabilities +- All dependencies up to date +- Security scan pass rate: 100% +- Code quality score: ≥ 8.0/10 + +### Build and Deployment Criteria +- All tests must pass +- Code quality gates must be met +- Security scans must pass +- Performance benchmarks must be within limits +- Documentation must be up to date + +## Best Practices + +1. **Test-Driven Development**: Write tests before implementation +2. **Continuous Testing**: Run tests on every commit +3. **Fast Feedback**: Keep test execution time under 10 minutes +4. **Test Environment Parity**: Match production environment closely +5. **Automated Verification**: Minimize manual testing requirements +6. **Comprehensive Coverage**: Test happy paths, edge cases, and error conditions +7. **Performance Testing**: Include performance tests in CI pipeline +8. **Security First**: Integrate security testing throughout the pipeline + +## Support and Resources + +- **Testing Documentation**: [https://docs.mobileops.local/testing](https://docs.mobileops.local/testing) +- **CI/CD Pipeline**: [https://ci.mobileops.local](https://ci.mobileops.local) +- **Test Results Dashboard**: [https://dashboard.mobileops.local/tests](https://dashboard.mobileops.local/tests) +- **Quality Metrics**: [https://quality.mobileops.local](https://quality.mobileops.local) +- **Testing Best Practices**: [https://docs.mobileops.local/testing/best-practices](https://docs.mobileops.local/testing/best-practices) \ No newline at end of file diff --git a/docs/UX_GUIDELINES.md b/docs/UX_GUIDELINES.md new file mode 100644 index 00000000000..4e533a3ae8b --- /dev/null +++ b/docs/UX_GUIDELINES.md @@ -0,0 +1,1205 @@ +--- +title: User Experience Guidelines +category: Platform Documentation +layout: default +SPDX-License-Identifier: LGPL-2.1-or-later +--- + +# MobileOps Platform User Experience Guidelines + +## Overview + +This document establishes user experience (UX) guidelines and design principles for the MobileOps platform, ensuring consistent, intuitive, and accessible interfaces across all platform components, mobile applications, and web interfaces. + +## Design Principles + +### 1. Mobile-First Design +- Prioritize mobile device experience +- Responsive design for all screen sizes +- Touch-friendly interface elements +- Optimized for one-handed operation + +### 2. Simplicity and Clarity +- Minimize cognitive load +- Clear visual hierarchy +- Progressive disclosure of complex features +- Consistent navigation patterns + +### 3. Performance-Oriented +- Fast loading times and smooth animations +- Efficient use of device resources +- Offline capability where appropriate +- Optimized for various network conditions + +### 4. Accessibility-First +- WCAG 2.1 AA compliance +- Support for assistive technologies +- High contrast and readable typography +- Alternative input methods + +### 5. Security-Aware UX +- Transparent security indicators +- Clear privacy controls +- Secure default configurations +- User education on security features + +## Visual Design System + +### Color Palette + +#### Primary Colors +```css +:root { + /* Primary brand colors */ + --primary-blue: #1976d2; + --primary-blue-light: #42a5f5; + --primary-blue-dark: #0d47a1; + + /* Secondary colors */ + --secondary-green: #388e3c; + --secondary-green-light: #66bb6a; + --secondary-green-dark: #1b5e20; + + /* Accent colors */ + --accent-orange: #ff9800; + --accent-purple: #9c27b0; + --accent-red: #f44336; +} +``` + +#### Neutral Colors +```css +:root { + /* Grayscale */ + --gray-50: #fafafa; + --gray-100: #f5f5f5; + --gray-200: #eeeeee; + --gray-300: #e0e0e0; + --gray-400: #bdbdbd; + --gray-500: #9e9e9e; + --gray-600: #757575; + --gray-700: #616161; + --gray-800: #424242; + --gray-900: #212121; + + /* Semantic colors */ + --success: var(--secondary-green); + --warning: var(--accent-orange); + --error: var(--accent-red); + --info: var(--primary-blue); +} +``` + +#### Dark Mode Support +```css +@media (prefers-color-scheme: dark) { + :root { + --background: var(--gray-900); + --surface: var(--gray-800); + --text-primary: var(--gray-100); + --text-secondary: var(--gray-400); + } +} +``` + +### Typography + +#### Font Stack +```css +:root { + --font-family-primary: 'Inter', system-ui, -apple-system, sans-serif; + --font-family-mono: 'JetBrains Mono', 'Consolas', monospace; + + /* Font sizes */ + --text-xs: 0.75rem; /* 12px */ + --text-sm: 0.875rem; /* 14px */ + --text-base: 1rem; /* 16px */ + --text-lg: 1.125rem; /* 18px */ + --text-xl: 1.25rem; /* 20px */ + --text-2xl: 1.5rem; /* 24px */ + --text-3xl: 1.875rem; /* 30px */ + --text-4xl: 2.25rem; /* 36px */ + + /* Font weights */ + --font-light: 300; + --font-normal: 400; + --font-medium: 500; + --font-semibold: 600; + --font-bold: 700; + + /* Line heights */ + --leading-tight: 1.25; + --leading-normal: 1.5; + --leading-relaxed: 1.75; +} +``` + +#### Typography Scale +```css +.text-display { + font-size: var(--text-4xl); + font-weight: var(--font-bold); + line-height: var(--leading-tight); +} + +.text-headline { + font-size: var(--text-3xl); + font-weight: var(--font-semibold); + line-height: var(--leading-tight); +} + +.text-title { + font-size: var(--text-2xl); + font-weight: var(--font-medium); + line-height: var(--leading-normal); +} + +.text-body { + font-size: var(--text-base); + font-weight: var(--font-normal); + line-height: var(--leading-normal); +} + +.text-caption { + font-size: var(--text-sm); + font-weight: var(--font-normal); + line-height: var(--leading-normal); +} +``` + +### Spacing and Layout + +#### Spacing Scale +```css +:root { + --space-1: 0.25rem; /* 4px */ + --space-2: 0.5rem; /* 8px */ + --space-3: 0.75rem; /* 12px */ + --space-4: 1rem; /* 16px */ + --space-5: 1.25rem; /* 20px */ + --space-6: 1.5rem; /* 24px */ + --space-8: 2rem; /* 32px */ + --space-10: 2.5rem; /* 40px */ + --space-12: 3rem; /* 48px */ + --space-16: 4rem; /* 64px */ + --space-20: 5rem; /* 80px */ +} +``` + +#### Grid System +```css +.container { + max-width: 1200px; + margin: 0 auto; + padding: 0 var(--space-4); +} + +.grid { + display: grid; + gap: var(--space-6); +} + +.grid-cols-1 { grid-template-columns: repeat(1, 1fr); } +.grid-cols-2 { grid-template-columns: repeat(2, 1fr); } +.grid-cols-3 { grid-template-columns: repeat(3, 1fr); } +.grid-cols-4 { grid-template-columns: repeat(4, 1fr); } + +/* Responsive breakpoints */ +@media (min-width: 640px) { + .sm\:grid-cols-2 { grid-template-columns: repeat(2, 1fr); } +} + +@media (min-width: 768px) { + .md\:grid-cols-3 { grid-template-columns: repeat(3, 1fr); } +} + +@media (min-width: 1024px) { + .lg\:grid-cols-4 { grid-template-columns: repeat(4, 1fr); } +} +``` + +## Component Library + +### Buttons + +#### Primary Button +```css +.btn-primary { + background-color: var(--primary-blue); + color: white; + border: none; + border-radius: 8px; + padding: var(--space-3) var(--space-6); + font-size: var(--text-base); + font-weight: var(--font-medium); + cursor: pointer; + transition: all 0.2s ease; + min-height: 44px; /* Touch target */ +} + +.btn-primary:hover { + background-color: var(--primary-blue-dark); + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(25, 118, 210, 0.3); +} + +.btn-primary:active { + transform: translateY(0); + box-shadow: 0 2px 4px rgba(25, 118, 210, 0.2); +} + +.btn-primary:disabled { + background-color: var(--gray-300); + cursor: not-allowed; + transform: none; + box-shadow: none; +} +``` + +#### Button Variants +```css +.btn-secondary { + background-color: transparent; + color: var(--primary-blue); + border: 2px solid var(--primary-blue); +} + +.btn-outline { + background-color: transparent; + color: var(--text-primary); + border: 1px solid var(--gray-300); +} + +.btn-ghost { + background-color: transparent; + color: var(--text-primary); + border: none; +} + +.btn-danger { + background-color: var(--error); + color: white; +} + +.btn-success { + background-color: var(--success); + color: white; +} +``` + +### Forms and Inputs + +#### Input Fields +```css +.input { + width: 100%; + padding: var(--space-3) var(--space-4); + border: 2px solid var(--gray-300); + border-radius: 8px; + font-size: var(--text-base); + background-color: var(--background); + color: var(--text-primary); + transition: border-color 0.2s ease; + min-height: 44px; +} + +.input:focus { + outline: none; + border-color: var(--primary-blue); + box-shadow: 0 0 0 3px rgba(25, 118, 210, 0.1); +} + +.input:invalid { + border-color: var(--error); +} + +.input:disabled { + background-color: var(--gray-100); + cursor: not-allowed; +} +``` + +#### Form Groups +```css +.form-group { + margin-bottom: var(--space-6); +} + +.form-label { + display: block; + font-size: var(--text-sm); + font-weight: var(--font-medium); + color: var(--text-secondary); + margin-bottom: var(--space-2); +} + +.form-help { + font-size: var(--text-xs); + color: var(--text-secondary); + margin-top: var(--space-1); +} + +.form-error { + font-size: var(--text-xs); + color: var(--error); + margin-top: var(--space-1); +} +``` + +### Navigation + +#### Top Navigation +```css +.navbar { + background-color: var(--background); + border-bottom: 1px solid var(--gray-200); + padding: var(--space-4) 0; + position: sticky; + top: 0; + z-index: 100; +} + +.navbar-brand { + font-size: var(--text-xl); + font-weight: var(--font-bold); + color: var(--primary-blue); + text-decoration: none; +} + +.navbar-nav { + display: flex; + gap: var(--space-6); + list-style: none; + margin: 0; + padding: 0; +} + +.navbar-link { + color: var(--text-secondary); + text-decoration: none; + font-weight: var(--font-medium); + padding: var(--space-2) var(--space-3); + border-radius: 6px; + transition: color 0.2s ease; +} + +.navbar-link:hover, +.navbar-link.active { + color: var(--primary-blue); + background-color: rgba(25, 118, 210, 0.1); +} +``` + +#### Mobile Navigation +```css +.mobile-nav { + position: fixed; + bottom: 0; + left: 0; + right: 0; + background-color: var(--background); + border-top: 1px solid var(--gray-200); + display: flex; + justify-content: space-around; + padding: var(--space-2) 0; + z-index: 100; +} + +.mobile-nav-item { + display: flex; + flex-direction: column; + align-items: center; + text-decoration: none; + color: var(--text-secondary); + font-size: var(--text-xs); + padding: var(--space-2); + min-width: 44px; + min-height: 44px; +} + +.mobile-nav-item.active { + color: var(--primary-blue); +} + +.mobile-nav-icon { + width: 24px; + height: 24px; + margin-bottom: var(--space-1); +} +``` + +### Cards and Containers + +#### Card Component +```css +.card { + background-color: var(--background); + border: 1px solid var(--gray-200); + border-radius: 12px; + padding: var(--space-6); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + transition: box-shadow 0.2s ease; +} + +.card:hover { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); +} + +.card-header { + margin-bottom: var(--space-4); + padding-bottom: var(--space-4); + border-bottom: 1px solid var(--gray-200); +} + +.card-title { + font-size: var(--text-lg); + font-weight: var(--font-semibold); + color: var(--text-primary); + margin: 0; +} + +.card-subtitle { + font-size: var(--text-sm); + color: var(--text-secondary); + margin-top: var(--space-1); +} + +.card-body { + color: var(--text-primary); +} + +.card-footer { + margin-top: var(--space-4); + padding-top: var(--space-4); + border-top: 1px solid var(--gray-200); +} +``` + +## Mobile Application UX + +### Android Design Guidelines + +#### Material Design 3 Integration +```xml + +
Generated: $(date)
+ +" >> "$report_file" + head -50 "$log_file" >> "$report_file" + echo "" >> "$report_file" + done + + echo "" >> "$report_file" + + log "INFO: Test report generated: $report_file" + echo "Test report: $report_file" +} + +run_all_tests() { + log "INFO: Running complete test suite" + + local failed_tests=0 + + # Run all test categories + test_script_syntax || ((failed_tests++)) + test_script_execution || ((failed_tests++)) + test_integration || ((failed_tests++)) + test_security || ((failed_tests++)) + test_performance || ((failed_tests++)) + + # Generate report + generate_test_report + + if [[ $failed_tests -eq 0 ]]; then + log "INFO: All tests completed successfully" + echo "✓ All tests PASSED" + return 0 + else + log "ERROR: $failed_tests test categories failed" + echo "✗ $failed_tests test categories FAILED" + return 1 + fi +} + +main() { + mkdir -p "$(dirname "$LOG_FILE")" "$TEST_CONFIG_DIR" "$TEST_RESULTS_DIR" + log "INFO: Test Suite started" + + case "${1:-all}" in + "init") + initialize_test_environment + ;; + "syntax") + test_script_syntax + ;; + "execution") + test_script_execution + ;; + "integration") + test_integration + ;; + "security") + test_security + ;; + "performance") + test_performance + ;; + "report") + generate_test_report + ;; + "all") + run_all_tests + ;; + *) + echo "Usage: $0 {init|syntax|execution|integration|security|performance|report|all}" + echo "" + echo "Test categories:" + echo " syntax - Test script syntax" + echo " execution - Test script execution" + echo " integration - Test component integration" + echo " security - Test security aspects" + echo " performance - Test performance metrics" + echo " report - Generate test report" + echo " all - Run all tests" + exit 1 + ;; + esac +} + +main "$@" \ No newline at end of file diff --git a/scripts/toolbox_integrity_check.sh b/scripts/toolbox_integrity_check.sh new file mode 100755 index 00000000000..12f07777584 --- /dev/null +++ b/scripts/toolbox_integrity_check.sh @@ -0,0 +1,203 @@ +#!/bin/bash + +# Toolbox Integrity Check Script for MobileOps Platform +# Performs comprehensive system integrity verification + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +LOG_FILE="/var/log/mobileops/toolbox_integrity.log" +INTEGRITY_CONFIG_DIR="/etc/mobileops/integrity" +CHECKSUM_FILE="$INTEGRITY_CONFIG_DIR/checksums.sha256" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE" +} + +check_system_binaries() { + log "INFO: Checking system binary integrity" + + local critical_binaries=( + "/bin/bash" + "/bin/sh" + "/usr/bin/sudo" + "/usr/bin/ssh" + "/usr/bin/systemctl" + ) + + for binary in "${critical_binaries[@]}"; do + if [[ -f "$binary" ]]; then + local checksum=$(sha256sum "$binary" | cut -d' ' -f1) + log "INFO: $binary - $checksum" + else + log "ERROR: Critical binary missing: $binary" + fi + done +} + +verify_mobileops_components() { + log "INFO: Verifying MobileOps component integrity" + + local components_dir="/opt/mobileops" + local scripts_dir="$SCRIPT_DIR" + + # Check script integrity + for script in "$scripts_dir"/*.sh; do + if [[ -f "$script" ]]; then + local checksum=$(sha256sum "$script" | cut -d' ' -f1) + log "INFO: Script $(basename "$script") - $checksum" + fi + done + + # Check component binaries if they exist + if [[ -d "$components_dir" ]]; then + find "$components_dir" -type f -executable | while read -r file; do + local checksum=$(sha256sum "$file" | cut -d' ' -f1) + log "INFO: Component $file - $checksum" + done + fi +} + +check_configuration_files() { + log "INFO: Checking configuration file integrity" + + local config_dirs=( + "/etc/mobileops" + "/etc/systemd/system" + ) + + for config_dir in "${config_dirs[@]}"; do + if [[ -d "$config_dir" ]]; then + find "$config_dir" -type f -name "*.conf" -o -name "*.service" | while read -r file; do + local checksum=$(sha256sum "$file" | cut -d' ' -f1) + log "INFO: Config $file - $checksum" + done + fi + done +} + +verify_network_security() { + log "INFO: Checking network security configuration" + + # Check firewall rules + if command -v iptables >/dev/null; then + local rules_count=$(iptables -L | wc -l) + log "INFO: Firewall rules count: $rules_count" + fi + + # Check open ports + if command -v ss >/dev/null; then + local listening_ports=$(ss -tuln | grep LISTEN | wc -l) + log "INFO: Listening ports count: $listening_ports" + fi + + # Check for suspicious network connections + if command -v netstat >/dev/null; then + local active_connections=$(netstat -an | grep ESTABLISHED | wc -l) + log "INFO: Active connections count: $active_connections" + fi +} + +check_container_integrity() { + log "INFO: Checking container integrity" + + # Check container runtime + if command -v docker >/dev/null; then + local running_containers=$(docker ps -q | wc -l) + log "INFO: Running Docker containers: $running_containers" + fi + + # Check for unauthorized containers + if [[ -d "/var/run/mobileops/chisel" ]]; then + local chisel_containers=$(find /var/run/mobileops/chisel -name "*.pid" | wc -l) + log "INFO: Running Chisel containers: $chisel_containers" + fi +} + +generate_baseline() { + log "INFO: Generating integrity baseline" + mkdir -p "$INTEGRITY_CONFIG_DIR" + + # Generate checksums for critical files + { + check_system_binaries 2>/dev/null | grep "INFO:" | cut -d' ' -f3- + find "$SCRIPT_DIR" -name "*.sh" -exec sha256sum {} \; + find /etc/mobileops -type f 2>/dev/null -exec sha256sum {} \; || true + } > "$CHECKSUM_FILE" + + log "INFO: Baseline saved to $CHECKSUM_FILE" +} + +verify_against_baseline() { + log "INFO: Verifying against baseline" + + if [[ ! -f "$CHECKSUM_FILE" ]]; then + log "ERROR: No baseline found. Run with 'baseline' first." + return 1 + fi + + local violations=0 + while IFS=' ' read -r expected_hash file; do + if [[ -f "$file" ]]; then + local current_hash=$(sha256sum "$file" | cut -d' ' -f1) + if [[ "$current_hash" != "$expected_hash" ]]; then + log "VIOLATION: $file - Expected: $expected_hash, Current: $current_hash" + ((violations++)) + fi + else + log "VIOLATION: Missing file: $file" + ((violations++)) + fi + done < "$CHECKSUM_FILE" + + if [[ $violations -eq 0 ]]; then + log "INFO: All integrity checks passed" + else + log "ERROR: $violations integrity violations found" + return 1 + fi +} + +full_system_check() { + log "INFO: Starting full system integrity check" + + check_system_binaries + verify_mobileops_components + check_configuration_files + verify_network_security + check_container_integrity + + log "INFO: Full system integrity check completed" +} + +main() { + mkdir -p "$(dirname "$LOG_FILE")" "$INTEGRITY_CONFIG_DIR" + log "INFO: Toolbox Integrity Check started" + + case "${1:-check}" in + "check") + full_system_check + ;; + "baseline") + generate_baseline + ;; + "verify") + verify_against_baseline + ;; + "binaries") + check_system_binaries + ;; + "network") + verify_network_security + ;; + "containers") + check_container_integrity + ;; + *) + echo "Usage: $0 {check|baseline|verify|binaries|network|containers}" + exit 1 + ;; + esac +} + +main "$@" \ No newline at end of file diff --git a/scripts/update_binaries.sh b/scripts/update_binaries.sh new file mode 100755 index 00000000000..7a06de6db3a --- /dev/null +++ b/scripts/update_binaries.sh @@ -0,0 +1,248 @@ +#!/bin/bash + +# Update Binaries Script for MobileOps Platform +# Handles secure binary updates and rollback capabilities + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +LOG_FILE="/var/log/mobileops/update_binaries.log" +UPDATE_CONFIG_DIR="/etc/mobileops/updates" +BINARY_BACKUP_DIR="/var/backups/mobileops" +UPDATE_CACHE_DIR="/var/cache/mobileops/updates" + +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE" +} + +check_update_available() { + log "INFO: Checking for available updates" + + local update_server="${UPDATE_SERVER:-https://updates.mobileops.local}" + local current_version=$(cat /etc/mobileops/version 2>/dev/null || echo "unknown") + + log "INFO: Current version: $current_version" + + # Simulate update check + if curl -sf "$update_server/latest" >/dev/null 2>&1; then + local latest_version=$(curl -s "$update_server/latest" || echo "unknown") + log "INFO: Latest version: $latest_version" + + if [[ "$current_version" != "$latest_version" ]]; then + log "INFO: Update available: $current_version -> $latest_version" + return 0 + else + log "INFO: System is up to date" + return 1 + fi + else + log "WARN: Cannot reach update server" + return 1 + fi +} + +backup_current_binaries() { + log "INFO: Backing up current binaries" + + local backup_timestamp=$(date +%Y%m%d_%H%M%S) + local backup_dir="$BINARY_BACKUP_DIR/$backup_timestamp" + + mkdir -p "$backup_dir" + + # Backup MobileOps scripts + cp -r "$SCRIPT_DIR" "$backup_dir/scripts" + + # Backup system components + if [[ -d "/opt/mobileops" ]]; then + cp -r "/opt/mobileops" "$backup_dir/components" + fi + + # Backup configuration + if [[ -d "/etc/mobileops" ]]; then + cp -r "/etc/mobileops" "$backup_dir/config" + fi + + echo "$backup_timestamp" > "$BINARY_BACKUP_DIR/latest_backup" + log "INFO: Backup completed: $backup_dir" +} + +download_updates() { + local update_package="$1" + log "INFO: Downloading update package: $update_package" + + mkdir -p "$UPDATE_CACHE_DIR" + local update_url="${UPDATE_SERVER:-https://updates.mobileops.local}/$update_package" + local local_file="$UPDATE_CACHE_DIR/$update_package" + + if curl -L -o "$local_file" "$update_url"; then + log "INFO: Downloaded: $local_file" + + # Verify checksum if available + if curl -sf "${update_url}.sha256" >/dev/null; then + local expected_hash=$(curl -s "${update_url}.sha256") + local actual_hash=$(sha256sum "$local_file" | cut -d' ' -f1) + + if [[ "$expected_hash" == "$actual_hash" ]]; then + log "INFO: Checksum verification passed" + else + log "ERROR: Checksum verification failed" + rm -f "$local_file" + return 1 + fi + fi + + return 0 + else + log "ERROR: Failed to download update package" + return 1 + fi +} + +apply_updates() { + local update_package="$1" + local local_file="$UPDATE_CACHE_DIR/$update_package" + + log "INFO: Applying updates from: $update_package" + + if [[ ! -f "$local_file" ]]; then + log "ERROR: Update package not found: $local_file" + return 1 + fi + + # Create temporary extraction directory + local temp_dir=$(mktemp -d) + trap "rm -rf $temp_dir" EXIT + + # Extract update package + if tar -xzf "$local_file" -C "$temp_dir"; then + log "INFO: Extracted update package" + else + log "ERROR: Failed to extract update package" + return 1 + fi + + # Apply script updates + if [[ -d "$temp_dir/scripts" ]]; then + log "INFO: Updating scripts" + cp -r "$temp_dir/scripts/"* "$SCRIPT_DIR/" + chmod +x "$SCRIPT_DIR"/*.sh + fi + + # Apply component updates + if [[ -d "$temp_dir/components" ]]; then + log "INFO: Updating components" + mkdir -p "/opt/mobileops" + cp -r "$temp_dir/components/"* "/opt/mobileops/" + fi + + # Apply configuration updates + if [[ -d "$temp_dir/config" ]]; then + log "INFO: Updating configuration" + cp -r "$temp_dir/config/"* "/etc/mobileops/" + fi + + # Update version file + if [[ -f "$temp_dir/version" ]]; then + cp "$temp_dir/version" "/etc/mobileops/version" + local new_version=$(cat "/etc/mobileops/version") + log "INFO: Updated to version: $new_version" + fi + + log "INFO: Updates applied successfully" +} + +rollback_updates() { + log "INFO: Rolling back to previous version" + + if [[ ! -f "$BINARY_BACKUP_DIR/latest_backup" ]]; then + log "ERROR: No backup available for rollback" + return 1 + fi + + local backup_timestamp=$(cat "$BINARY_BACKUP_DIR/latest_backup") + local backup_dir="$BINARY_BACKUP_DIR/$backup_timestamp" + + if [[ ! -d "$backup_dir" ]]; then + log "ERROR: Backup directory not found: $backup_dir" + return 1 + fi + + log "INFO: Restoring from backup: $backup_timestamp" + + # Restore scripts + if [[ -d "$backup_dir/scripts" ]]; then + rm -rf "$SCRIPT_DIR"/* + cp -r "$backup_dir/scripts/"* "$SCRIPT_DIR/" + chmod +x "$SCRIPT_DIR"/*.sh + fi + + # Restore components + if [[ -d "$backup_dir/components" ]]; then + rm -rf "/opt/mobileops" + cp -r "$backup_dir/components" "/opt/mobileops" + fi + + # Restore configuration + if [[ -d "$backup_dir/config" ]]; then + rm -rf "/etc/mobileops" + cp -r "$backup_dir/config" "/etc/mobileops" + fi + + log "INFO: Rollback completed successfully" +} + +list_backups() { + log "INFO: Available backups:" + + if [[ -d "$BINARY_BACKUP_DIR" ]]; then + ls -1 "$BINARY_BACKUP_DIR" | grep -E "^[0-9]{8}_[0-9]{6}$" | sort -r | head -10 + else + log "INFO: No backups found" + fi +} + +main() { + mkdir -p "$(dirname "$LOG_FILE")" "$UPDATE_CONFIG_DIR" "$BINARY_BACKUP_DIR" "$UPDATE_CACHE_DIR" + log "INFO: Binary Update Manager started" + + case "${1:-check}" in + "check") + check_update_available + ;; + "download") + if [[ $# -lt 2 ]]; then + echo "Usage: $0 download