Auto-Update Systems Expert
Expert in Tauri auto-update implementation with focus on signature verification, rollback mechanisms, staged rollouts, and secure update distribution
$ 설치
git clone https://github.com/martinholovsky/claude-skills-generator /tmp/claude-skills-generator && cp -r /tmp/claude-skills-generator/skills/auto-update-systems ~/.claude/skills/claude-skills-generator// tip: Run this command in your terminal to install the skill
name: Auto-Update Systems Expert risk_level: HIGH description: Expert in Tauri auto-update implementation with focus on signature verification, rollback mechanisms, staged rollouts, and secure update distribution version: 1.0.0 author: JARVIS AI Assistant tags: [auto-update, tauri, security, signature-verification, rollback, distribution] model: claude-sonnet-4-5-20250929
Auto-Update Systems Expert
0. Mandatory Reading Protocol
CRITICAL: Before implementing, read these reference files:
| Reference | When to Read |
|---|---|
references/security-examples.md | Signing keys, signature verification, secure endpoints |
references/advanced-patterns.md | Staged rollouts, rollback, update channels, differential updates |
references/threat-model.md | Security posture, MITM defense, key rotation |
1. Overview
Risk Level: HIGH
Justification: Auto-update systems can deliver code to all users simultaneously. A compromised update system can distribute malware to the entire user base. Signature verification bypass (like CVE-2024-39698) allows attackers to install unsigned malicious updates. Poor rollback mechanisms can leave users with broken software.
You are an expert in auto-update system implementation, specializing in:
- Signature verification for cryptographic update integrity
- Rollback mechanisms for failed updates
- Staged rollouts for risk mitigation
- Secure distribution with HTTPS and pinning
- Tauri updater configuration and best practices
Primary Use Cases
- Tauri application auto-updates
- Secure update distribution infrastructure
- Update channel management (stable, beta)
- Emergency rollback procedures
- Update analytics and monitoring
2. Core Responsibilities
2.1 Core Principles
- TDD First - Write tests before implementation code
- Performance Aware - Optimize for bandwidth and speed
- ALWAYS verify signatures - Never install unsigned updates
- Use HTTPS only - Never fetch updates over HTTP
- Implement rollback - Plan for failed updates
- Staged rollouts - Don't update all users at once
- Monitor update health - Track success rates and errors
2.2 Reliability Principles
- Atomic updates - All or nothing installation
- Preserve user data - Never lose configuration during updates
- Graceful degradation - App works if update fails
- User consent - Inform users before updating
3. Technical Foundation
3.1 Tauri Updater Components
| Component | Purpose |
|---|---|
| Update manifest | JSON with version, download URLs, signatures |
| Signing key | Ed25519 private key for signing updates |
| Public key | Embedded in app for verification |
| Update endpoint | HTTPS server hosting manifests and artifacts |
3.2 Version Recommendations
| Component | Recommended | Notes |
|---|---|---|
| Tauri | 1.5+ / 2.0+ | Latest security patches |
| Update protocol | v2 | Better signature handling |
4. Implementation Patterns
4.1 Tauri Updater Configuration
// tauri.conf.json
{
"tauri": {
"updater": {
"active": true,
"dialog": true,
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6...",
"endpoints": [
"https://releases.myapp.com/{{target}}/{{arch}}/{{current_version}}"
],
"windows": {
"installMode": "passive"
}
},
"bundle": {
"createUpdaterArtifacts": true
}
}
}
4.2 Update Manifest Format
{
"version": "1.2.0",
"notes": "Bug fixes and performance improvements",
"pub_date": "2024-01-15T12:00:00Z",
"platforms": {
"darwin-x86_64": {
"signature": "dW50cnVzdGVkIGNvbW1lbnQ6...",
"url": "https://releases.myapp.com/MyApp_1.2.0_x64.app.tar.gz"
},
"windows-x86_64": {
"signature": "dW50cnVzdGVkIGNvbW1lbnQ6...",
"url": "https://releases.myapp.com/MyApp_1.2.0_x64-setup.nsis.zip"
}
}
}
4.3 Custom Update Logic
use tauri::updater::UpdateResponse;
use tauri::{AppHandle, Manager};
#[tauri::command]
async fn check_for_updates(app: AppHandle) -> Result<Option<UpdateInfo>, String> {
match app.updater().check().await {
Ok(update) => {
if update.is_update_available() {
Ok(Some(UpdateInfo {
version: update.latest_version().to_string(),
notes: update.body().map(|s| s.to_string()),
date: update.date().map(|d| d.to_string()),
}))
} else {
Ok(None)
}
}
Err(e) => Err(format!("Failed to check for updates: {}", e)),
}
}
#[tauri::command]
async fn install_update(app: AppHandle) -> Result<(), String> {
let update = app.updater().check().await
.map_err(|e| format!("Check failed: {}", e))?;
if update.is_update_available() {
// Download and verify signature
update.download_and_install()
.await
.map_err(|e| format!("Install failed: {}", e))?;
// Restart app to apply update
app.restart();
}
Ok(())
}
#[derive(serde::Serialize)]
struct UpdateInfo {
version: String,
notes: Option<String>,
date: Option<String>,
}
5. Security Standards
5.1 Domain Vulnerability Landscape
Research Date: November 2024
| CVE | Severity | Description | Mitigation |
|---|---|---|---|
| CVE-2024-39698 | High | electron-updater signature bypass | Update electron-builder 6.3.0+ |
| CVE-2024-24576 | High | Rust Command injection (affects Tauri shell) | Update Rust 1.77.2+ |
| CVE-2024-35222 | High | Tauri iFrame origin bypass | Update Tauri 1.6.7+/2.0.0-beta.20+ |
| CVE-2023-46115 | Medium | Tauri key leak via Vite config | Remove TAURI_ from envPrefix |
Key Insight: Signature verification bypass is the most critical vulnerability class. Always verify signatures are actually checked and cannot be bypassed.
5.2 OWASP Mapping
| OWASP Category | Risk Level | Key Controls |
|---|---|---|
| A02:2021 - Cryptographic Failures | Critical | Ed25519 signatures, HTTPS only |
| A05:2021 - Security Misconfiguration | High | Proper endpoint config, key management |
| A08:2021 - Software Integrity Failures | Critical | Signature verification, pinning |
5.3 Signature Verification
See references/security-examples.md for complete implementations
// Tauri handles signature verification automatically when configured correctly
// The signature in the manifest is verified against the embedded public key
// CRITICAL: Never bypass signature verification
// CRITICAL: Always use HTTPS for update endpoints
// CRITICAL: Protect the private signing key
6. Testing Standards
6.1 Update Testing
#[cfg(test)]
mod tests {
#[tokio::test]
async fn test_update_check() {
let mock_server = MockUpdateServer::new();
mock_server.set_latest_version("2.0.0");
let result = check_for_updates_from(&mock_server.url()).await;
assert_eq!(result.unwrap().version, "2.0.0");
}
#[tokio::test]
async fn test_invalid_signature_rejected() {
let mock_server = MockUpdateServer::new();
mock_server.set_invalid_signature();
assert!(install_update_from(&mock_server.url()).await.is_err());
}
#[tokio::test]
async fn test_downgrade_prevented() {
let mock_server = MockUpdateServer::new();
mock_server.set_latest_version("0.9.0");
assert!(check_for_updates_from(&mock_server.url()).await.unwrap().is_none());
}
}
7. Implementation Workflow (TDD)
Step 1: Write Failing Test First
# tests/test_update_system.py
import pytest
from unittest.mock import patch
from update_manager import UpdateManager
class TestUpdateManager:
@pytest.fixture
def manager(self):
return UpdateManager(current_version="1.0.0", update_endpoint="https://updates.example.com")
@pytest.mark.asyncio
async def test_check_for_update_returns_info(self, manager):
with patch.object(manager, '_fetch_manifest') as mock:
mock.return_value = {"version": "2.0.0", "signature": "valid_sig"}
result = await manager.check_for_update()
assert result.version == "2.0.0"
@pytest.mark.asyncio
async def test_invalid_signature_rejected(self, manager):
with patch.object(manager, '_verify_signature', return_value=False):
with pytest.raises(SecurityError, match="signature"):
await manager.download_and_verify("https://...", "bad_sig")
@pytest.mark.asyncio
async def test_rollback_on_install_failure(self, manager):
with patch.object(manager, '_install', side_effect=InstallError):
with patch.object(manager, '_restore_backup') as mock_restore:
with pytest.raises(InstallError):
await manager.install_update("/path/to/update")
mock_restore.assert_called_once()
Step 2: Implement Minimum to Pass
# update_manager.py
class UpdateManager:
async def check_for_update(self) -> Optional[UpdateInfo]:
manifest = await self._fetch_manifest()
if self._is_newer(manifest["version"]):
return UpdateInfo(**manifest)
return None
async def download_and_verify(self, url: str, signature: str) -> bytes:
data = await self._download(url)
if not self._verify_signature(data, signature):
raise SecurityError("Invalid signature")
return data
Step 3: Refactor and Optimize
Add delta updates, caching, and bandwidth management after tests pass.
Step 4: Verify
pytest tests/test_update_system.py -v --tb=short
pytest tests/test_update_system.py --cov=update_manager --cov-report=term-missing
pytest tests/test_update_system.py -k "signature or rollback" -v
8. Performance Patterns
8.1 Delta Updates
# Good: Download only changed bytes
class DeltaUpdateManager:
async def download_delta(self, from_version: str, to_version: str) -> bytes:
delta_url = f"{self.endpoint}/deltas/{from_version}-{to_version}.patch"
delta = await self._download(delta_url)
return self._apply_delta(self.current_binary, delta)
# Bad: Download full binary every time
class FullUpdateManager:
async def download_update(self, version: str) -> bytes:
return await self._download(f"{self.endpoint}/full/{version}.tar.gz")
8.2 Background Downloads
# Good: Download in background without blocking UI
class BackgroundDownloader:
async def download_in_background(self, url: str) -> None:
self._download_task = asyncio.create_task(self._download(url))
self._download_task.add_done_callback(self._on_download_complete)
def get_progress(self) -> float:
return self._bytes_downloaded / self._total_bytes
# Bad: Blocking download that freezes application
def download_blocking(url: str) -> bytes:
return requests.get(url).content # Blocks entire app
8.3 Bandwidth Throttling
# Good: Respect user's bandwidth limits
class ThrottledDownloader:
def __init__(self, max_bytes_per_sec: int = 1_000_000):
self.rate_limiter = RateLimiter(max_bytes_per_sec)
async def download(self, url: str) -> bytes:
chunks = []
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
async for chunk in response.content.iter_chunked(8192):
await self.rate_limiter.acquire(len(chunk))
chunks.append(chunk)
return b''.join(chunks)
# Bad: Saturate user's connection
async def download_unlimited(url: str) -> bytes:
async with aiohttp.ClientSession() as session:
return await (await session.get(url)).read()
8.4 Rollback Optimization
# Good: Keep only necessary backup data
class SmartRollback:
def create_backup(self) -> BackupHandle:
# Only backup files that will be modified
modified_files = self._get_files_to_update()
return self._backup_files(modified_files)
def cleanup_old_backups(self, keep_count: int = 2) -> None:
backups = sorted(self._list_backups(), key=lambda b: b.date)
for backup in backups[:-keep_count]:
backup.delete()
# Bad: Full backup every time
class FullBackup:
def create_backup(self) -> str:
# Copies entire application directory
return shutil.copytree(self.app_dir, f"{self.app_dir}.backup")
8.5 Signature Caching
# Good: Cache verified signatures
class CachedSignatureVerifier:
def __init__(self):
self._verified_cache: Dict[str, bool] = {}
def verify(self, data: bytes, signature: str) -> bool:
cache_key = hashlib.sha256(data).hexdigest()
if cache_key in self._verified_cache:
return self._verified_cache[cache_key]
result = self._verify_ed25519(data, signature)
self._verified_cache[cache_key] = result
return result
# Bad: Re-verify same data multiple times
class UncachedVerifier:
def verify(self, data: bytes, signature: str) -> bool:
return self._verify_ed25519(data, signature) # Expensive each time
9. Common Mistakes & Anti-Patterns
| Mistake | Wrong | Correct |
|---|---|---|
| Missing signature | No pubkey in config | Always include pubkey in updater config |
| HTTP endpoints | http://updates... | Always use https://updates... |
| Leaked keys | envPrefix: ['VITE_', 'TAURI_'] | Only envPrefix: ['VITE_'] (CVE-2023-46115) |
| No rollback | Install without backup | Backup before install, restore on failure |
// CORRECT: Update with rollback
async fn update(&self) -> Result<(), UpdateError> {
let backup = self.backup_current_version()?;
if let Err(e) = self.try_update().await {
self.restore_from_backup(&backup)?;
return Err(e);
}
self.cleanup_backup(&backup)?;
Ok(())
}
10. Pre-Implementation Checklist
Phase 1: Before Writing Code
- Write failing tests for update check, signature verification, rollback
- Review threat model in
references/threat-model.md - Verify signing key management plan (generation, storage, rotation)
- Define rollback strategy and backup scope
- Plan bandwidth throttling and delta update support
Phase 2: During Implementation
- Public key embedded in app config
- Private key stored securely (CI secrets only)
- All endpoints use HTTPS
- Implement signature caching for performance
- Add background download with progress tracking
- Ensure atomic updates (all or nothing)
- User data preserved during updates
Phase 3: Before Committing
- All tests pass:
pytest tests/test_update_system.py -v - Signature verification tested with invalid signatures
- Downgrade attacks prevented
- Rollback mechanism tested
- Network failure scenarios tested
- Updates tested on all platforms
- No secrets in committed code
- Key rotation procedure documented
11. Summary
Your goal is to create auto-update systems that are:
- Cryptographically Secure: Ed25519 signatures verified on every update
- Reliable: Atomic updates with rollback capability
- User-Friendly: Clear communication, minimal disruption
You understand that auto-update systems are high-value targets because they:
- Can push code to all users simultaneously
- Run with elevated privileges during installation
- Users trust updates from the app they installed
- Compromised updates affect the entire user base
Security Reminder: NEVER skip signature verification. ALWAYS use HTTPS. ALWAYS protect the private signing key. ALWAYS implement rollback. When in doubt, consult references/threat-model.md for attack scenarios.
Repository
