Skip to content

Commit 29b570a

Browse files
author
Test User
committed
feat: Complete Phase 3 - Secrets & API Keys (RAKD/SOPS)
- Add RAKD (Required API Keys Document) system: - Service detection from package.json, go.mod, requirements.txt, and code - API key validation from .env file with format checking - RAKD.md generator with comprehensive status sections - Support for 10+ services (Stripe, SendGrid, AWS, Supabase, Auth0, Clerk, OpenAI, Sentry, etc.) - Add SOPS (Service Operating Procedures) system: - Auto-generate service setup guides in .doplan/SOPS/ - Templates for authentication, database, payment, storage, email, analytics, AI services - Each SOP includes: overview, setup steps, API key creation, env vars, code examples, testing, common issues, resources - Implement keys management TUI: - Interactive service list with status indicators - Service detail view showing all API keys - Validate all keys (V key) - Sync .env.example (S key) - Navigation with arrow keys - Add API keys status widget to dashboard: - Progress bar showing configuration percentage - Status summary (configured/pending/required/optional) - Warning highlight for high-priority missing keys - Keyboard shortcut [k] to open keys management - Integrate with TUI menu and command executor - Wire up keys command to menu action Phase 3 of v0.0.19-beta complete.
1 parent 5531b1c commit 29b570a

File tree

10 files changed

+1837
-60
lines changed

10 files changed

+1837
-60
lines changed

internal/commands/executor.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ func (e *TUICommandExecutor) UpdateProgress() error {
5757
}
5858

5959
func (e *TUICommandExecutor) ManageAPIKeys() error {
60-
// TODO: Implement keys command
61-
return nil
60+
return ManageAPIKeys()
6261
}
6362

6463
func (e *TUICommandExecutor) ApplyDesign() error {

internal/commands/keys.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package commands
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/DoPlan-dev/CLI/internal/rakd"
8+
"github.com/DoPlan-dev/CLI/internal/sops"
9+
"github.com/DoPlan-dev/CLI/internal/wizard"
10+
)
11+
12+
// ManageAPIKeys launches the API keys management TUI
13+
func ManageAPIKeys() error {
14+
projectRoot, err := os.Getwd()
15+
if err != nil {
16+
return fmt.Errorf("failed to get current directory: %w", err)
17+
}
18+
19+
// Generate/update RAKD.md
20+
_, err = rakd.GenerateRAKD(projectRoot)
21+
if err != nil {
22+
return fmt.Errorf("failed to generate RAKD: %w", err)
23+
}
24+
25+
// Generate SOPS if they don't exist
26+
sopsGen := sops.NewGenerator(projectRoot)
27+
if err := sopsGen.GenerateAll(); err != nil {
28+
return fmt.Errorf("failed to generate SOPS: %w", err)
29+
}
30+
31+
// Launch keys management wizard
32+
return wizard.RunKeysWizard()
33+
}
34+
35+
// ValidateAPIKeys validates all API keys
36+
func ValidateAPIKeys() error {
37+
projectRoot, err := os.Getwd()
38+
if err != nil {
39+
return fmt.Errorf("failed to get current directory: %w", err)
40+
}
41+
42+
data, err := rakd.GenerateRAKD(projectRoot)
43+
if err != nil {
44+
return fmt.Errorf("failed to validate keys: %w", err)
45+
}
46+
47+
fmt.Printf("✅ Validated %d services\n", len(data.Services))
48+
fmt.Printf(" Configured: %d\n", data.ConfiguredCount)
49+
fmt.Printf(" Required (Missing): %d\n", data.RequiredCount)
50+
fmt.Printf(" Pending: %d\n", data.PendingCount)
51+
fmt.Printf(" Optional: %d\n", data.OptionalCount)
52+
53+
return nil
54+
}
55+
56+
// SyncEnvExample syncs .env.example with detected keys
57+
func SyncEnvExample() error {
58+
projectRoot, err := os.Getwd()
59+
if err != nil {
60+
return fmt.Errorf("failed to get current directory: %w", err)
61+
}
62+
63+
detector := rakd.NewDetector(projectRoot)
64+
services, err := detector.DetectServices()
65+
if err != nil {
66+
return fmt.Errorf("failed to detect services: %w", err)
67+
}
68+
69+
// Generate .env.example content
70+
envExamplePath := fmt.Sprintf("%s/.env.example", projectRoot)
71+
content := "# Environment Variables\n"
72+
content += "# Copy this file to .env and fill in your values\n\n"
73+
74+
for _, service := range services {
75+
content += fmt.Sprintf("# %s\n", service.Name)
76+
for _, key := range service.Keys {
77+
if key.Required {
78+
content += fmt.Sprintf("%s=\n", key.EnvVar)
79+
} else {
80+
content += fmt.Sprintf("# %s=\n", key.EnvVar)
81+
}
82+
}
83+
content += "\n"
84+
}
85+
86+
if err := os.WriteFile(envExamplePath, []byte(content), 0644); err != nil {
87+
return fmt.Errorf("failed to write .env.example: %w", err)
88+
}
89+
90+
fmt.Printf("✅ Synced .env.example with %d services\n", len(services))
91+
return nil
92+
}
93+

0 commit comments

Comments
 (0)