Secrets Migration Guide
This guide helps you migrate from environment variable-based secrets to Lemon's encrypted secrets store.
Why Migrate?
The encrypted secrets store provides:
- Encryption at rest - Secrets are encrypted with AES-256-GCM
- No shell history leakage - Secrets aren't in your shell history like
exportcommands - No process environment exposure - Secrets aren't visible in
/proc/<pid>/environ - Keychain integration - Master key can be stored in macOS Keychain
- Fine-grained access - Per-secret access control and audit logging
Quick Migration
1. Check Your Current Secrets
See which secrets are currently resolved from environment vs the encrypted store:
mix lemon.secrets.checkExample output:
NAME SOURCE VALUE
--------------------------------------------------
ANTHROPIC_API_KEY env sk-an...t-abc1
OPENAI_API_KEY store sk-...-xyz9
GITHUB_TOKEN missing ---
1 from store, 1 from env, 1 missing2. Import Environment Secrets
Import all secrets that are currently set in your environment:
# Preview what would be imported (dry run)
mix lemon.secrets.import_env --dry-run
# Actually import (skips secrets already in store)
mix lemon.secrets.import_env
# Force import even if already in store
mix lemon.secrets.import_env --force3. Verify Migration
Run the check again to confirm secrets are now in the store:
mix lemon.secrets.check4. Clean Up Environment
Once you've verified everything works, remove secrets from your environment:
# Remove from shell profile (e.g., ~/.zshrc, ~/.bashrc)
unset ANTHROPIC_API_KEY
unset OPENAI_API_KEY
# etc.Manual Migration
If you prefer to migrate secrets one at a time:
# Set a secret manually
mix lemon.secrets.set ANTHROPIC_API_KEY "sk-ant-..."
# Verify it was stored
mix lemon.secrets.list
# Test resolution
mix lemon.secrets.checkSupported Secret Names
The following secrets are recognized by the migration tooling:
AI Providers
ANTHROPIC_API_KEY- Anthropic Claude APIOPENAI_API_KEY- OpenAI APIOPENAI_CODEX_API_KEY- OpenAI CodexCHATGPT_TOKEN- ChatGPT OAuthGOOGLE_GENERATIVE_AI_API_KEY/GOOGLE_API_KEY/GEMINI_API_KEY- Google AIAWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_SESSION_TOKEN- AWS BedrockAZURE_OPENAI_API_KEY- Azure OpenAIGROQ_API_KEY,MISTRAL_API_KEY,XAI_API_KEY,CEREBRAS_API_KEYKIMI_API_KEY,MOONSHOT_API_KEY,OPENCODE_API_KEY
Coding Agent Tools
PERPLEXITY_API_KEY- Perplexity searchOPENROUTER_API_KEY- OpenRouter APIFIRECRAWL_API_KEY- Firecrawl web scrapingBRAVE_API_KEY- Brave Search APIGITHUB_TOKEN- GitHub API access
Troubleshooting
Secret not found after migration
If a secret resolves as :missing after migration:
- Check the exact name matches (case-sensitive)
- Verify the secret was actually imported:
mix lemon.secrets.list - Check for typos in the secret name
Import fails with "missing_master_key"
Initialize the secrets store first:
mix lemon.secrets.initBackward compatibility
If you need to temporarily fall back to environment variables:
# Secrets store will be skipped, env vars used directly
LEMON_SECRETS_MASTER_KEY=invalid mix lemon.secrets.checkOr disable secrets store in config:
[secrets]
use_store = falseVerification
After migration, verify everything works:
# Run the full test suite
mix test
# Check specific provider connectivity
mix lemon.config --show-secrets-sourceSecurity Best Practices
- Never commit secrets - The encrypted store keeps secrets out of your codebase
- Rotate imported secrets - After migration, consider rotating API keys
- Use expiration - Set expiration dates for temporary credentials:bash
mix lemon.secrets.set TEMP_KEY "value" --expires-at 1735689600000 - Audit access - Check which secrets are being used:bash
mix lemon.secrets.list --with-usage
See Also
docs/security/secrets-and-keychain.md- Resolution and fallback contractmix help lemon.secrets.init- Initialize secrets storemix help lemon.secrets.set- Store a secretmix help lemon.secrets.check- Check secret sourcesmix help lemon.secrets.import_env- Bulk import from environment