Skip to content

Commit 78dabf7

Browse files
Merge pull request #45 from CodeMonkeyCybersecurity/claude/api-key-management-script-011CUrCr7tXgZkrecW3LCZmP
feat(moni): add API key rotation command
2 parents f93be93 + 773ab98 commit 78dabf7

3 files changed

Lines changed: 864 additions & 0 deletions

File tree

cmd/update/moni.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package update
77
import (
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"
@@ -25,6 +26,12 @@ var (
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
300409
func runMoniInit(rc *eos_io.RuntimeContext, cmd *cobra.Command, args []string) error {

0 commit comments

Comments
 (0)