# Update Manager - Technical Documentation ## Overview The Update Manager provides automatic system updates from GitHub releases, including version checking, downloading, installation, and rollback capabilities. ## Architecture ### Backend Components **Location**: `app/backend/managers/update_manager.py` **Key Classes:** - `UpdateManager` - Core manager class - `UpdateStatus` - Enum for update states - `ReleaseInfo` - Data class for GitHub release information - `UpdateProgress` - Data class for progress tracking ### API Endpoints **Location**: `app/backend/api/updates.py` | Endpoint | Method | Description | |----------|--------|-------------| | `/api/updates/check` | GET | Check for available updates | | `/api/updates/progress` | GET | Get current update progress | | `/api/updates/download` | POST | Download available update | | `/api/updates/install` | POST | Install downloaded update | | `/api/updates/release-notes` | POST | Get release notes for a version | | `/api/updates/current-version` | GET | Get current system version | ## Features ### 1. Automatic Update Checks Periodically checks GitHub releases API for new versions: ```python # Configurable check interval (default: 1 hour) UPDATE_CHECK_INTERVAL=3600 # Checks start automatically on backend startup update_manager = get_update_manager() await update_manager.start_periodic_checks() ``` **Detection Logic:** - Fetches latest release from GitHub API - Compares semantic versions (e.g., "1.2.3") - Handles pre-release tags - Stores last check timestamp ### 2. Version Comparison Uses semantic versioning for comparison: ```python def _is_newer_version(self, version1: str, version2: str) -> bool: # Parses versions like "1.2.3" or "v1.2.3" # Compares major.minor.patch components # Returns True if version1 > version2 ``` **Supported Formats:** - Standard: `1.2.3` - Prefixed: `v1.2.3` - Pre-release: `1.2.3-beta.1` (metadata stripped for comparison) ### 3. Update Download Downloads release assets with progress tracking: ```python async def download_update(self) -> bool: # Downloads to temporary directory # Tracks progress for UI updates # Verifies checksum if available # Cleans up on failure ``` **Features:** - Progress tracking (0-100%) - Checksum verification (SHA256) - Automatic cleanup on errors - Configurable timeout ### 4. Installation Process Safe installation with backup and rollback: ```python async def install_update(self) -> bool: # 1. Backup current installation # 2. Extract update archive # 3. Run post-install script # 4. Rebuild PM3 client # 5. Update version file # 6. Rollback on failure ``` **Installation Steps:** 1. Create backup of `/opt/dangerous-pi` 2. Extract tar.gz archive to install directory 3. Execute `scripts/post-install.sh` if present 4. Rebuild Proxmark3 client (`make clean && make`) 5. Update VERSION file 6. Restore backup if any step fails ### 5. Update States **State Machine:** ``` IDLE → CHECKING → AVAILABLE → DOWNLOADING → INSTALLING → COMPLETE ↓ ↓ ↓ FAILED ←────────────┴─────────────┘ ``` **State Descriptions:** - `IDLE`: No update activity - `CHECKING`: Querying GitHub API - `AVAILABLE`: Update ready to download - `DOWNLOADING`: Download in progress - `INSTALLING`: Installing update - `COMPLETE`: Update successfully installed - `FAILED`: Error occurred (see error_message) ## Frontend Integration ### Updates Page **Location**: `app/frontend/app/routes/updates.tsx` **Features:** - Current version display - Update availability check - Release notes viewer - Download progress bar - Installation status - Error handling **UI Components:** ```typescript // Current Version Card - Version number display - Status badge - Last check timestamp - "Check for Updates" button // Update Available Card - New version number - Download size - Release date - Pre-release indicator - Release notes (scrollable) - Download/Install buttons - Progress bar during download - Installation status // Action Messages - Success/failure notifications - Error details ``` ## Usage Examples ### Backend API **Check for Updates:** ```bash curl http://localhost:8000/api/updates/check ``` Response: ```json { "update_available": true, "current_version": "0.1.0", "latest_version": "0.2.0", "release_date": "2024-01-15T10:30:00Z", "changelog": "## What's New\n- Feature 1\n- Bug fixes", "is_prerelease": false, "download_size": 5242880 } ``` **Get Progress:** ```bash curl http://localhost:8000/api/updates/progress ``` Response: ```json { "status": "downloading", "current_version": "0.1.0", "available_version": "0.2.0", "download_progress": 45.5, "error_message": null, "last_check": "2024-01-15T12:00:00Z" } ``` **Download Update:** ```bash curl -X POST http://localhost:8000/api/updates/download ``` **Install Update:** ```bash curl -X POST http://localhost:8000/api/updates/install ``` ### Frontend Usage 1. Navigate to Updates page 2. Click "Check for Updates" 3. Review release notes if update available 4. Click "Download Update" 5. Wait for download to complete 6. Click "Install Update" 7. Restart service when prompted ## Implementation Details ### GitHub API Integration Uses GitHub REST API v3: ```python # Fetch latest release url = f"https://api.github.com/repos/{GITHUB_REPO}/releases/latest" # Fetch specific version url = f"https://api.github.com/repos/{GITHUB_REPO}/releases/tags/v1.0.0" ``` **Rate Limiting:** - Unauthenticated: 60 requests/hour - Authenticated: 5000 requests/hour - Consider adding GitHub token for higher limits **Release Asset Requirements:** - Must include `.tar.gz` file - Optional `.sha256` checksum file - Asset naming: `dangerous-pi-{version}.tar.gz` ### Checksum Verification SHA256 checksum validation: ```python async def _verify_checksum(self, file_path: Path, expected: str) -> bool: sha256 = hashlib.sha256() with open(file_path, 'rb') as f: while chunk := f.read(65536): # 64KB chunks sha256.update(chunk) return sha256.hexdigest() == expected.lower() ``` ### Backup and Rollback Automatic backup before installation: ```python # Backup structure /opt/dangerous-pi/ # Current installation /opt/dangerous-pi-backup/ # Backup before update # Rollback on failure if installation_fails: shutil.rmtree(install_dir) shutil.copytree(backup_dir, install_dir) ``` ### PM3 Client Rebuild Rebuilds Proxmark3 client after updates: ```python async def _rebuild_pm3_client(self): pm3_dir = Path("/opt/proxmark3") if pm3_dir.exists(): await self._run_command( f"cd {pm3_dir} && make clean && make" ) ``` ## Configuration ### Environment Variables ```bash # Version (read from VERSION file or env) VERSION=0.1.0 # GitHub repository GITHUB_REPO=dangerous-things/dangerous-pi # Update check interval (seconds) UPDATE_CHECK_INTERVAL=3600 # Optional: GitHub token for higher rate limits GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx ``` ### Installation Paths ``` /opt/dangerous-pi/ # Application directory /opt/dangerous-pi/VERSION # Version file /opt/dangerous-pi/scripts/ # Install scripts /opt/dangerous-pi-backup/ # Backup directory /tmp/dangerous-pi-update-*/ # Temporary download directory ``` ## Security Considerations ### Verification - **Checksum Validation**: SHA256 verification of downloads - **HTTPS Only**: All downloads over HTTPS - **Signed Releases**: Consider GPG signature verification (future) ### Permissions Update operations require elevated privileges: ```bash # Commands that need sudo: - tar -xzf (to /opt directory) - make (for PM3 rebuild) - systemctl restart (for service restart) ``` **Solution**: Configure sudoers for specific commands: ``` www-data ALL=(ALL) NOPASSWD: /bin/tar www-data ALL=(ALL) NOPASSWD: /usr/bin/make www-data ALL=(ALL) NOPASSWD: /bin/systemctl restart dangerous-pi ``` ### Backup Safety - Backup created before every installation - Single backup retained (consider multiple backup retention) - Automatic rollback on installation failure - Manual rollback possible by copying backup ## Troubleshooting ### Update Check Fails **Symptom**: "Failed to check for updates" **Check:** ```bash # Test GitHub API access curl https://api.github.com/repos/YOUR_REPO/releases/latest # Check network connectivity ping api.github.com # Verify GITHUB_REPO config echo $GITHUB_REPO ``` **Solutions:** - Check internet connection - Verify repository exists and is public - Add GitHub token if rate limited - Check firewall settings ### Download Fails **Symptom**: Download stuck or fails **Check:** ```bash # Check disk space df -h /tmp # Check network speed wget --spider https://github.com/releases/download/test.tar.gz # Check download URL curl -I [download_url] ``` **Solutions:** - Free up disk space - Check network connection - Verify asset exists in release - Increase timeout if slow connection ### Installation Fails **Symptom**: Installation fails, system rolled back **Check:** ```bash # Check installation directory ls -la /opt/dangerous-pi # Check backup exists ls -la /opt/dangerous-pi-backup # Check permissions stat /opt/dangerous-pi # Check logs journalctl -u dangerous-pi ``` **Solutions:** - Verify sufficient disk space - Check directory permissions - Ensure backup directory is not corrupted - Run post-install script manually to debug ### PM3 Rebuild Fails **Symptom**: PM3 client rebuild fails during installation **Check:** ```bash # Check PM3 directory ls -la /opt/proxmark3 # Try manual rebuild cd /opt/proxmark3 make clean make # Check build dependencies dpkg -l | grep build-essential ``` **Solutions:** - Install missing build dependencies - Check PM3 source integrity - Run rebuild manually - Skip rebuild if PM3 not used ## Testing ### Unit Tests ```python # Test version comparison assert manager._is_newer_version("1.2.0", "1.1.0") == True assert manager._is_newer_version("1.0.0", "1.0.0") == False assert manager._is_newer_version("2.0.0", "1.9.9") == True # Test checksum verification assert await manager._verify_checksum(file_path, valid_checksum) == True assert await manager._verify_checksum(file_path, invalid_checksum) == False ``` ### Integration Tests ```bash # Test check endpoint curl http://localhost:8000/api/updates/check # Test download (requires available update) curl -X POST http://localhost:8000/api/updates/download # Test progress polling while true; do curl http://localhost:8000/api/updates/progress sleep 1 done # Test installation curl -X POST http://localhost:8000/api/updates/install ``` ### Manual Testing 1. **Fresh Check:** - Start backend - Verify automatic check on startup - Check last_check timestamp 2. **Update Flow:** - Create new release on GitHub - Click "Check for Updates" - Verify release notes display - Download update - Monitor progress bar - Install update - Verify version changed 3. **Failure Scenarios:** - Test with no internet - Test with invalid checksum - Test with insufficient disk space - Verify rollback works 4. **Periodic Checks:** - Wait for automatic check (default: 1 hour) - Verify no UI interruption - Check last_check updates ## Performance ### Check Duration - API request: ~200-500ms - Version parsing: <10ms - **Total**: <1 second ### Download Duration - Depends on file size and connection speed - Example: 5MB @ 10Mbps = ~4 seconds - Progress updates every 8KB chunk ### Installation Duration - Extract: ~5-10 seconds (5MB archive) - PM3 rebuild: ~30-60 seconds - **Total**: ~1-2 minutes ### Resource Usage - Memory: Minimal (<10MB during download) - CPU: Low (except during PM3 rebuild) - Disk: 2x update size (download + extracted) ## Future Enhancements ### Near Term - [ ] Multiple backup retention - [ ] Scheduled update windows - [ ] Update notifications via SSE - [ ] Auto-restart after installation - [ ] Rollback UI button ### Medium Term - [ ] Delta updates (only changed files) - [ ] Update channels (stable, beta, nightly) - [ ] Manual update file upload - [ ] Update history/changelog viewer - [ ] Automatic rollback on boot failure ### Long Term - [ ] A/B partition updates - [ ] Incremental updates - [ ] Peer-to-peer update distribution - [ ] OTA firmware updates for PM3 - [ ] Update signing and verification (GPG) ## Code Organization ``` app/backend/ ├── managers/ │ └── update_manager.py # Core update logic (500+ lines) ├── api/ │ └── updates.py # API endpoints (150 lines) ├── config.py # VERSION, GITHUB_REPO config └── main.py # Periodic checks initialization app/frontend/ └── app/routes/ └── updates.tsx # Update UI (350+ lines) ``` ## Dependencies **Python Packages:** - `aiohttp` - Async HTTP client for GitHub API - `hashlib` - Checksum verification (built-in) - `asyncio` - Async operations (built-in) **System Commands:** - `tar` - Archive extraction - `make` - PM3 client rebuild - `systemctl` - Service management (future) **Optional:** - GitHub personal access token for higher rate limits ## Conclusion The Update Manager provides a robust, automatic update system with: - Seamless GitHub integration - Safe installation with rollback - Real-time progress tracking - Version management - Error handling and recovery It ensures Dangerous Pi stays up-to-date with minimal user intervention while maintaining system stability through backups and automatic rollback on failure.