tftsr-devops_investigation/docs/architecture/adrs/ADR-005-auto-generate-encryption-keys.md
Shaun Arman 093495a653
Some checks failed
Test / rust-fmt-check (pull_request) Failing after 0s
Test / rust-clippy (pull_request) Failing after 1s
Test / rust-tests (pull_request) Failing after 0s
Test / frontend-typecheck (pull_request) Failing after 16s
Test / frontend-tests (pull_request) Failing after 18s
PR Review Automation / review (pull_request) Failing after 4m13s
feat: full copy from apollo_nxt-trcaa with complete sanitization
Complete backport of all features from apollo_nxt-trcaa repository:
- Three-tier shell execution safety system (Tier 1: auto, Tier 2: approve, Tier 3: deny)
- Ollama function calling with tool use support
- AI provider tool calling auto-detection
- kubectl binary bundling and management
- kubeconfig upload and context management
- Shell approval modal with real-time UI
- MCP protocol HTTP transport with custom headers
- Enhanced security audit logging
- Comprehensive test coverage (275+ tests)
- Updated CI/CD workflows for Gitea Actions
- Complete documentation (ADRs, wiki, release notes)

Sanitization applied to all files:
- Removed all MSI, Motorola, VNXT, Vesta references
- Replaced internal infrastructure references with TFTSR equivalents
- Updated all URLs and API endpoints
- Sanitized commit history references in documentation

Technical changes:
- New modules: shell/classifier, shell/executor, shell/kubectl, shell/kubeconfig
- Enhanced AI providers: ollama.rs, openai.rs with function calling
- New Tauri commands: shell execution, kubeconfig management, tool calling detection
- Database migrations: shell_execution_audit table
- Frontend: ShellApprovalModal, ShellExecution, KubeconfigManager pages
- CI/CD: kubectl bundling, multi-platform builds, Gitea Actions integration

Version: 1.0.8

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-06-05 14:12:43 -05:00

4.2 KiB

ADR-005: Auto-generate Encryption Keys at Runtime

Status: Accepted Date: 2026-04 Deciders: sarman


Context

The application uses two encryption keys:

  1. Database key (TRCAA_DB_KEY (or legacy TRCAA_DB_KEY)): SQLCipher AES-256 key for the full database
  2. Credential key (TRCAA_ENCRYPTION_KEY (or legacy TRCAA_ENCRYPTION_KEY)): AES-256-GCM key for token/API key encryption

The original design required both to be set as environment variables in release builds. This caused:

  • Critical failure on Mac: Fresh installs would crash at startup with "file is not a database" error
  • Silent failure on save: Saving AI providers would fail with "TRCAA_ENCRYPTION_KEY must be set in release builds"
  • Developer friction: Switching from cargo tauri dev (debug, plain SQLite) to a release build would crash because the existing plain database couldn't be opened as encrypted

Decision

Auto-generate cryptographically secure 256-bit keys at first launch and persist them to the app data directory with restricted file permissions.


Key Storage

Key File Permissions Location
Database .dbkey 0600 (owner r/w only) $TRCAA_DATA_DIR/
Credentials .enckey 0600 (owner r/w only) $TRCAA_DATA_DIR/

Platform data directories:

  • macOS: ~/Library/Application Support/trcaa/
  • Linux: ~/.local/share/trcaa/
  • Windows: %APPDATA%\trcaa\

Key Resolution Order

For both keys:

  1. Check environment variable (TRCAA_DB_KEY (or legacy TRCAA_DB_KEY) / TRCAA_ENCRYPTION_KEY (or legacy TRCAA_ENCRYPTION_KEY)) — use if set and non-empty
  2. If debug build — use hardcoded dev key (never touches filesystem)
  3. If .dbkey / .enckey exists and is non-empty — load from file
  4. Otherwise — generate 32 random bytes via OsRng, hex-encode to 64-char string, write to file with mode 0600

Plain-to-Encrypted Migration

When a release build encounters an existing plain SQLite database (written by a debug build), rather than crashing:

1. Detect plain SQLite via 16-byte header check ("SQLite format 3\0")
2. Copy database to .db.plain-backup
3. Open plain database
4. ATTACH encrypted database at temp path with new key
5. SELECT sqlcipher_export('encrypted')   -- copies all tables, indexes, triggers
6. DETACH encrypted
7. rename(temp_encrypted, original_path)
8. Open encrypted database with key

Alternatives Considered

Option Pros Cons
Auto-generate keys (chosen) Works out-of-the-box, no user config Key file loss = data loss (acceptable: key + DB on same machine)
Require env vars (original) Explicit — users know their key Crashes on fresh install, poor UX
Derive from machine ID No file to lose Machine ID changes break DB on hardware changes
OS keychain Most secure Complex cross-platform implementation; adds dependency
Prompt user for password User controls key Poor UX for a tool; password complexity issues

Why not OS keychain: The tauri-plugin-stronghold already provides a keychain-like abstraction for credentials, but integrating SQLCipher key retrieval into Stronghold would create a chicken-and-egg problem: Stronghold itself needs to be initialized before the database that stores Stronghold's key material.


Consequences

Positive:

  • Zero-configuration installation — app works on first launch
  • Developers can freely switch between debug and release builds
  • Environment variable override still available for automated/enterprise deployments
  • Key files are protected by Unix file permissions (0600)

Negative:

  • If .dbkey or .enckey are deleted, the database and all stored credentials become permanently inaccessible
  • Key files are not themselves encrypted — OS-level protection depends on filesystem permissions
  • Not suitable for multi-user scenarios where different users need isolated key material (single-user desktop app — acceptable)

Mitigation for key loss: Document clearly that backing up $TRCAA_DATA_DIR (including hidden files) preserves both key files and database. Loss of keys without losing the database = data loss.