Documentation Index
Fetch the complete documentation index at: https://mintlify.com/felixdotgo/querybox/llms.txt
Use this file to discover all available pages before exploring further.
CredManager manages secret storage with a 3-tier fallback chain, prioritizing OS-native secure storage when available. It is used exclusively by ConnectionService — the frontend never calls CredManager directly.
Location: services/credmanager/credmanager.go
Storage Tiers
CredManager attempts storage in this order:Tier Comparison
| Tier | Backend | Persistent | Availability |
|---|---|---|---|
| 1 | OS Keyring via go-keyring | ✓ | macOS Keychain, Windows Credential Manager, Linux Secret Service |
| 2 | data/credentials.db (SQLite) | ✓ | Server/CI/headless — OS keyring not available |
| 3 | In-memory sync.RWMutex map | ✗ | Last resort; dev/testing only |
CredManager stops at the first tier that succeeds. It does not sync across tiers if a higher tier becomes available later.
API
CredManager provides a simple interface:Store(key, secret string) error
Stores a credential, trying each tier until one succeeds: Key format:"connection:<uuid>" (set by ConnectionService)
Secret format: Credential JSON string (opaque to CredManager)
Get(key string) (string, error)
Retrieves a credential, trying each tier until one succeeds:Delete(key string) error
Removes a credential from all tiers:Delete attempts removal from all tiers, not just the first one that succeeds. This ensures cleanup even if credentials migrated between tiers.
Storage Tier Details
Tier 1: OS Keyring
Backend:go-keyring
Platform mapping:
- macOS: Keychain Access (
Security.framework) - Windows: Credential Manager (
wincred.dll) - Linux: Secret Service API (
libsecret/gnome-keyring)
"querybox"
Storage call:
- Native OS encryption
- Survives app restarts
- User-managed via OS tools
- Supports biometric unlock (macOS Touch ID, Windows Hello)
- Not available in headless environments (servers, CI)
- May prompt user for keyring unlock
- Cannot be used in sandboxed environments without entitlements
Tier 2: SQLite File
Backend: SQLite database atdata/credentials.db
Schema:
- Works in headless environments
- Portable (file can be backed up)
- No external dependencies
- Secrets stored unencrypted — restrict filesystem permissions in production
- Requires writable disk
- No OS-level audit trail
Tier 3: In-Memory Map
Backend: Gomap[string]string protected by sync.RWMutex
Storage call:
- Always available
- No external dependencies
- Fast access
- Ephemeral — cleared on app restart
- Not persistent — credentials must be re-entered after restart
- Memory can be inspected by debuggers
The in-memory tier is acceptable for:
- CI test runs where neither keyring nor writable disk is available
- Development with mock credentials
- Temporary connections that won’t be reused
Integration with ConnectionService
CredManager is called by ConnectionService at these points:| ConnectionService Operation | CredManager Call | When |
|---|---|---|
CreateConnection | Store(key, secret) | After generating UUID, before DB insert |
GetCredential | Get(key) | When frontend requests credential for plugin exec |
DeleteConnection | Delete(key) | Before removing metadata from DB |
Flow Example: Creating a Connection
Credentials are stored before metadata. If credential storage fails at all tiers (extremely rare), the connection is not created.
Security Considerations
Credential Isolation
- Credentials never appear in
connections.db - Frontend never caches credential values
- Plugins receive credentials only during execution
- Credentials are not logged or included in error messages
Keyring Security
When using OS keyring:- macOS: Protected by FileVault encryption + user keychain password
- Windows: Protected by DPAPI (Data Protection API) tied to user account
- Linux: Protected by keyring daemon password
SQLite File Permissions
When falling back to SQLite tier:-
Set restrictive file permissions immediately after creation:
-
Consider encrypting the parent directory:
-
Exclude from backups if credentials should not persist:
Memory Safety
In-memory tier considerations:- Credentials stored as Go strings (not zeroed after use)
- Memory can be inspected via debugger or core dump
- Acceptable for development; avoid for production
Troubleshooting
Credentials Not Persisting After Restart
Symptom: Connections exist but credentials are missing after restarting QueryBox. Cause: CredManager fell back to in-memory tier (tier 3). Solution:- Check if OS keyring is available (tier 1)
- Ensure
data/credentials.dbis writable (tier 2) - Recreate connections — credentials will be stored in the highest available tier
Keyring Unlock Prompts (macOS/Linux)
Symptom: OS prompts for keyring password on app startup. Cause: Keyring is locked and requires authentication. Solution:- macOS: Unlock Keychain Access or enable “Unlock on Login”
- Linux: Start keyring daemon with auto-unlock:
Orphaned Credentials
Symptom: Credentials exist in keyring but no corresponding connection in UI. Cause: Metadata deletion succeeded but credential deletion failed. Solution: Manually delete from keyring:SQLite File Corruption
Symptom: Tier 2 always fails, falling back to tier 3. Cause:data/credentials.db is corrupted.
Solution:
Best Practices
Development
- Use in-memory tier (tier 3) for mock credentials
- Commit example connection configs without real credentials
- Document which tier is expected in dev environments
Production
- Prefer OS keyring tier (tier 1) for desktop deployments
- Use encrypted filesystem for SQLite tier (tier 2) in headless environments
- Never commit
credentials.dbor keyring exports to version control - Set restrictive file permissions on
data/directory:
CI/Testing
- Use in-memory tier or temporary SQLite files
- Set
QUERYBOX_DATA_DIRto a test-specific path: - Clean up after tests: