# 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.
