@@ -7,6 +7,7 @@ package update
77import (
88 "fmt"
99
10+ "github.com/CodeMonkeyCybersecurity/eos/pkg/bionicgpt"
1011 "github.com/CodeMonkeyCybersecurity/eos/pkg/bionicgpt/apikeys"
1112 "github.com/CodeMonkeyCybersecurity/eos/pkg/bionicgpt/postinstall"
1213 "github.com/CodeMonkeyCybersecurity/eos/pkg/bionicgpt/refresh"
2526 moniRefreshValidateOnly bool
2627 moniRefreshInstallDir string
2728
29+ // Moni API key rotation flags
30+ moniRotateAPIKeysDryRun bool
31+ moniRotateAPIKeysSkipBackup bool
32+ moniRotateAPIKeysSkipVerify bool
33+ moniRotateAPIKeysSkipRestart bool
34+ moniRotateAPIKeysInstallDir string
2835 // Moni post-install and API key rotation flags
2936 moniPostInstall bool
3037 moniRotateAPIKeys bool
@@ -117,6 +124,61 @@ Examples:
117124 MoniCmd .Flags ().BoolVar (& moniRefreshForce , "refresh" , false ,
118125 "Refresh Moni configuration and restart services" )
119126
127+ // Rotate API keys subcommand
128+ rotateAPIKeysCmd := & cobra.Command {
129+ Use : "rotate-api-keys" ,
130+ Short : "Rotate LiteLLM virtual API keys for Moni" ,
131+ Long : `Rotate the virtual API keys used by Moni to access LiteLLM models.
132+
133+ This operation regenerates the virtual key with access to all configured models:
134+ • Moni (GPT-5-mini)
135+ • Moni-4.1 (GPT-4.1-mini)
136+ • Moni-o3 (o3-mini)
137+ • nomic-embed-text (Ollama embeddings)
138+
139+ The rotation process:
140+ 1. ASSESS: Check prerequisites (database, LiteLLM health, current keys)
141+ 2. INTERVENE: Generate new key, update .env, update database, restart app
142+ 3. EVALUATE: Verify new key works and is properly configured
143+
144+ Safety features:
145+ • Automatic backup of .env file before changes
146+ • Transaction-like behavior with automatic rollback on failure
147+ • Comprehensive verification tests after rotation
148+ • Old keys are deleted after successful rotation
149+
150+ Estimated downtime: ~30 seconds (during app restart)
151+
152+ Examples:
153+ # Full API key rotation with confirmation
154+ eos update moni rotate-api-keys
155+
156+ # Dry run (show what would be done)
157+ eos update moni rotate-api-keys --dry-run
158+
159+ # Skip backup (not recommended)
160+ eos update moni rotate-api-keys --skip-backup
161+
162+ # Skip verification tests
163+ eos update moni rotate-api-keys --skip-verify
164+
165+ # Custom installation directory
166+ eos update moni rotate-api-keys --install-dir /opt/moni` ,
167+ RunE : eos .Wrap (runMoniRotateAPIKeys ),
168+ }
169+
170+ rotateAPIKeysCmd .Flags ().BoolVar (& moniRotateAPIKeysDryRun , "dry-run" , false ,
171+ "Show what would be done without making changes" )
172+ rotateAPIKeysCmd .Flags ().BoolVar (& moniRotateAPIKeysSkipBackup , "skip-backup" , false ,
173+ "Skip .env backup (not recommended)" )
174+ rotateAPIKeysCmd .Flags ().BoolVar (& moniRotateAPIKeysSkipVerify , "skip-verify" , false ,
175+ "Skip verification tests after rotation" )
176+ rotateAPIKeysCmd .Flags ().BoolVar (& moniRotateAPIKeysSkipRestart , "skip-restart" , false ,
177+ "Skip app restart after rotation" )
178+ rotateAPIKeysCmd .Flags ().StringVar (& moniRotateAPIKeysInstallDir , "install-dir" , "/opt/bionicgpt" ,
179+ "Path to Moni installation directory" )
180+
181+ MoniCmd .AddCommand (refreshCmd , rotateAPIKeysCmd )
120182 // Add post-install flag
121183 MoniCmd .Flags ().BoolVar (& moniPostInstall , "post-install" , false ,
122184 "Run post-installation configuration (upsert models, regenerate API keys)" )
@@ -295,6 +357,53 @@ func runMoniRefresh(rc *eos_io.RuntimeContext, cmd *cobra.Command, args []string
295357 return nil
296358}
297359
360+ // runMoniRotateAPIKeys handles the API key rotation operation
361+ // Orchestration layer: delegates to pkg/bionicgpt for business logic
362+ func runMoniRotateAPIKeys (rc * eos_io.RuntimeContext , cmd * cobra.Command , args []string ) error {
363+ logger := otelzap .Ctx (rc .Ctx )
364+
365+ logger .Info ("Starting Moni API key rotation" ,
366+ zap .String ("install_dir" , moniRotateAPIKeysInstallDir ),
367+ zap .Bool ("dry_run" , moniRotateAPIKeysDryRun ),
368+ zap .Bool ("skip_backup" , moniRotateAPIKeysSkipBackup ),
369+ zap .Bool ("skip_verify" , moniRotateAPIKeysSkipVerify ),
370+ zap .Bool ("skip_restart" , moniRotateAPIKeysSkipRestart ))
371+
372+ // Build rotation configuration
373+ config := & bionicgpt.RotateAPIKeysConfig {
374+ InstallDir : moniRotateAPIKeysInstallDir ,
375+ DryRun : moniRotateAPIKeysDryRun ,
376+ SkipBackup : moniRotateAPIKeysSkipBackup ,
377+ SkipVerify : moniRotateAPIKeysSkipVerify ,
378+ SkipRestart : moniRotateAPIKeysSkipRestart ,
379+ }
380+
381+ // Execute rotation
382+ if err := bionicgpt .RotateAPIKeys (rc , config ); err != nil {
383+ logger .Error ("Moni API key rotation failed" , zap .Error (err ))
384+ return fmt .Errorf ("API key rotation failed: %w" , err )
385+ }
386+
387+ logger .Info ("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" )
388+ logger .Info ("✅ API KEY ROTATION COMPLETE" )
389+ logger .Info ("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" )
390+ logger .Info ("" )
391+ logger .Info ("🔑 New virtual key has been generated and configured" )
392+ logger .Info ("" )
393+ logger .Info ("🤖 Authorized Models:" )
394+ logger .Info (" • Moni (GPT-5-mini)" )
395+ logger .Info (" • Moni-4.1 (GPT-4.1-mini)" )
396+ logger .Info (" • Moni-o3 (o3-mini)" )
397+ logger .Info (" • nomic-embed-text (Ollama)" )
398+ logger .Info ("" )
399+ logger .Info ("🧪 Test in Moni UI:" )
400+ logger .Info (" http://localhost:8513" )
401+ logger .Info (" Try: 'What is your name?'" )
402+ logger .Info ("" )
403+ logger .Info ("📝 Monitor logs:" )
404+ logger .Info (" docker compose -f /opt/bionicgpt/docker-compose.yml logs -f app litellm-proxy" )
405+ logger .Info ("" )
406+
298407// runMoniInit handles the Moni initialization worker
299408// Orchestration layer: delegates to pkg/moni for business logic
300409func runMoniInit (rc * eos_io.RuntimeContext , cmd * cobra.Command , args []string ) error {
0 commit comments