-
Notifications
You must be signed in to change notification settings - Fork 0
Ddded option to use CLI in server environments #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,2 @@ | ||
| ek | ||
| ek | ||
| .DS_Store |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,9 +2,11 @@ package cmd | |||||||||||||||||||||
|
|
||||||||||||||||||||||
| import ( | ||||||||||||||||||||||
| "fmt" | ||||||||||||||||||||||
| "os" | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| "github.com/spf13/cobra" | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| "github.com/Enkryptify/cli/internal/auth" | ||||||||||||||||||||||
| "github.com/Enkryptify/cli/internal/config" | ||||||||||||||||||||||
| "github.com/Enkryptify/cli/internal/providers/enkryptify" | ||||||||||||||||||||||
| "github.com/Enkryptify/cli/internal/ui" | ||||||||||||||||||||||
|
|
@@ -36,9 +38,6 @@ func runSetup(cmd *cobra.Command, args []string) error { | |||||||||||||||||||||
| return err | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| ui.ShowBrandHeader() | ||||||||||||||||||||||
| ui.PrintTitle("🔗 Enkryptify Repository Setup") | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| currentPath, err := config.GetCurrentWorkingDirectory() | ||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||
| return fmt.Errorf("failed to get current directory: %w", err) | ||||||||||||||||||||||
|
|
@@ -49,6 +48,61 @@ func runSetup(cmd *cobra.Command, args []string) error { | |||||||||||||||||||||
| return fmt.Errorf("failed to load setup configuration: %w", err) | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| client := enkryptify.NewClient() | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Check if using environment variable token (for server environments) | ||||||||||||||||||||||
| if token := os.Getenv(auth.EnvTokenKey); token != "" { | ||||||||||||||||||||||
| return runNonInteractiveSetup(currentPath, setupStorage, client) | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Interactive setup for user authentication | ||||||||||||||||||||||
| return runInteractiveSetup(currentPath, setupStorage, client) | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // runNonInteractiveSetup handles setup for server environments using env token | ||||||||||||||||||||||
| func runNonInteractiveSetup(currentPath string, setupStorage *config.SetupStorage, client *enkryptify.Client) error { | ||||||||||||||||||||||
| // Fetch project details from the token | ||||||||||||||||||||||
| tokenDetails, err := client.GetProjectTokenDetails() | ||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||
| return fmt.Errorf("failed to fetch project token details: %w", err) | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Check if setup already exists | ||||||||||||||||||||||
| if setupStorage.HasSetupForPath(currentPath) { | ||||||||||||||||||||||
| existingSetup := setupStorage.GetSetupForPath(currentPath) | ||||||||||||||||||||||
| // In non-interactive mode, we just overwrite silently | ||||||||||||||||||||||
| fmt.Printf("Updating existing setup for %s\n", currentPath) | ||||||||||||||||||||||
| fmt.Printf("Previous: workspace=%s, project=%s, environment=%s\n", | ||||||||||||||||||||||
| existingSetup.WorkspaceSlug, existingSetup.ProjectSlug, existingSetup.EnvironmentID) | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Create setup config from token details | ||||||||||||||||||||||
| setupConfig := config.SetupConfig{ | ||||||||||||||||||||||
| Path: currentPath, | ||||||||||||||||||||||
| WorkspaceSlug: tokenDetails.Workspace.Slug, | ||||||||||||||||||||||
| ProjectSlug: tokenDetails.Project.Slug, | ||||||||||||||||||||||
| EnvironmentID: tokenDetails.EnvironmentID, | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| setupStorage.AddOrUpdateSetup(setupConfig) | ||||||||||||||||||||||
| if err := setupStorage.Save(); err != nil { | ||||||||||||||||||||||
| return fmt.Errorf("failed to save setup configuration: %w", err) | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| fmt.Printf("✓ Setup completed successfully!\n") | ||||||||||||||||||||||
| fmt.Printf(" Workspace: %s\n", tokenDetails.Workspace.Slug) | ||||||||||||||||||||||
| fmt.Printf(" Project: %s\n", tokenDetails.Project.Slug) | ||||||||||||||||||||||
| fmt.Printf(" Environment: %s\n", tokenDetails.EnvironmentID) | ||||||||||||||||||||||
| fmt.Printf(" Path: %s\n", currentPath) | ||||||||||||||||||||||
|
Comment on lines
+92
to
+96
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Use ui package functions for consistent output formatting. Similar to the previous comment, use Apply this diff: - fmt.Printf("✓ Setup completed successfully!\n")
- fmt.Printf(" Workspace: %s\n", tokenDetails.Workspace.Slug)
- fmt.Printf(" Project: %s\n", tokenDetails.Project.Slug)
- fmt.Printf(" Environment: %s\n", tokenDetails.EnvironmentID)
- fmt.Printf(" Path: %s\n", currentPath)
+ ui.PrintSuccess("Setup completed successfully!")
+ ui.PrintInfo(fmt.Sprintf("Workspace: %s", tokenDetails.Workspace.Slug))
+ ui.PrintInfo(fmt.Sprintf("Project: %s", tokenDetails.Project.Slug))
+ ui.PrintInfo(fmt.Sprintf("Environment: %s", tokenDetails.EnvironmentID))
+ ui.PrintInfo(fmt.Sprintf("Path: %s", currentPath))📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| return nil | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // runInteractiveSetup handles setup with interactive prompts for user authentication | ||||||||||||||||||||||
| func runInteractiveSetup(currentPath string, setupStorage *config.SetupStorage, client *enkryptify.Client) error { | ||||||||||||||||||||||
| ui.ShowBrandHeader() | ||||||||||||||||||||||
| ui.PrintTitle("🔗 Enkryptify Repository Setup") | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if setupStorage.HasSetupForPath(currentPath) { | ||||||||||||||||||||||
| existingSetup := setupStorage.GetSetupForPath(currentPath) | ||||||||||||||||||||||
| ui.PrintWarning("Setup already exists for this directory") | ||||||||||||||||||||||
|
|
@@ -61,8 +115,6 @@ func runSetup(cmd *cobra.Command, args []string) error { | |||||||||||||||||||||
| } | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| client := enkryptify.NewClient() | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| ui.ShowProgress(1, 3, "Fetching workspaces...") | ||||||||||||||||||||||
| workspaces, err := client.GetWorkspaces() | ||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| #!/bin/bash | ||
|
|
||
| VERSION="0.1.8" | ||
| VERSION="0.1.9" | ||
| set -e | ||
|
|
||
| if [ -t 1 ]; then | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -10,6 +10,7 @@ import ( | |||||||||||||||||||||||||||||||||||
| "io" | ||||||||||||||||||||||||||||||||||||
| "net/http" | ||||||||||||||||||||||||||||||||||||
| "net/url" | ||||||||||||||||||||||||||||||||||||
| "os" | ||||||||||||||||||||||||||||||||||||
| "strings" | ||||||||||||||||||||||||||||||||||||
| "time" | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
|
|
@@ -28,6 +29,7 @@ const ( | |||||||||||||||||||||||||||||||||||
| RedirectURL = "http://localhost:51823/callback" | ||||||||||||||||||||||||||||||||||||
| CallbackPort = "51823" | ||||||||||||||||||||||||||||||||||||
| DefaultScopes = "openid profile email secrets:read secrets:write" | ||||||||||||||||||||||||||||||||||||
| EnvTokenKey = "ENKRYPTIFY_TOKEN" | ||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // EnkryptifyAuth handles authentication with Enkryptify | ||||||||||||||||||||||||||||||||||||
|
|
@@ -76,6 +78,12 @@ func generateCodeChallenge(verifier string) string { | |||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Login performs the OAuth login flow with Enkryptify | ||||||||||||||||||||||||||||||||||||
| func (e *EnkryptifyAuth) Login(ctx context.Context) error { | ||||||||||||||||||||||||||||||||||||
| // Check if using environment variable token | ||||||||||||||||||||||||||||||||||||
| if token := os.Getenv(EnvTokenKey); token != "" { | ||||||||||||||||||||||||||||||||||||
| ui.PrintInfo(fmt.Sprintf("Authenticated using %s environment variable", EnvTokenKey)) | ||||||||||||||||||||||||||||||||||||
| return nil | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+81
to
+85
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major 🧩 Analysis chainValidate the environment token before accepting it. The code accepts any non-empty value from Apply this diff to add basic validation: func (e *EnkryptifyAuth) Login(ctx context.Context) error {
// Check if using environment variable token
if token := os.Getenv(EnvTokenKey); token != "" {
+ // Validate token is not just whitespace
+ if strings.TrimSpace(token) == "" {
+ return fmt.Errorf("invalid %s: token cannot be empty or whitespace", EnvTokenKey)
+ }
ui.PrintInfo(fmt.Sprintf("Authenticated using %s environment variable", EnvTokenKey))
return nil
}🏁 Script executed: #!/bin/bash
# Search for all uses of the environment token without validation
rg -nP --type Go 'os\.Getenv\(\s*EnvTokenKey\s*\)' -C3Length of output: 26 🏁 Script executed: #!/bin/bash
# Locate all occurrences of os.Getenv(EnvTokenKey) in .go files
rg -n 'os\.Getenv\(\s*EnvTokenKey\s*\)' -C3 --glob '*.go'Length of output: 1510 🏁 Script executed: #!/bin/bash
# Search for existing use of strings.TrimSpace in the repo
rg -n 'TrimSpace' --glob '*.go'Length of output: 144 🏁 Script executed: #!/bin/bash
# Show import block in enkryptify.go
rg -n 'import \(' -C5 --glob 'internal/auth/enkryptify.go'Length of output: 341 🏁 Script executed: sed -n '1,20p' internal/auth/enkryptify.goLength of output: 281 Trim and reject whitespace-only ENKRYPTIFY_TOKEN
Apply in Login (mirror in the other methods): func (e *EnkryptifyAuth) Login(ctx context.Context) error {
- if token := os.Getenv(EnvTokenKey); token != "" {
+ if token := strings.TrimSpace(os.Getenv(EnvTokenKey)); token != "" {
ui.PrintInfo(fmt.Sprintf("Authenticated using %s environment variable", EnvTokenKey))
return nil
- }
+ } else if os.Getenv(EnvTokenKey) != "" {
+ return fmt.Errorf("invalid %s: token cannot be empty or whitespace", EnvTokenKey)
+ }
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // Load configuration | ||||||||||||||||||||||||||||||||||||
| cfg, err := config.LoadConfig() | ||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||
|
|
@@ -410,6 +418,11 @@ func (e *EnkryptifyAuth) GetUserInfo(accessToken string) (*UserInfo, error) { | |||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // IsAuthenticated checks if the user is authenticated | ||||||||||||||||||||||||||||||||||||
| func (e *EnkryptifyAuth) IsAuthenticated() (bool, error) { | ||||||||||||||||||||||||||||||||||||
| // Check for environment variable token first (for server environments) | ||||||||||||||||||||||||||||||||||||
| if token := os.Getenv(EnvTokenKey); token != "" { | ||||||||||||||||||||||||||||||||||||
| return true, nil | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+421
to
+424
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure consistency with GetAccessToken for empty tokens. If Apply this diff to ensure consistency: func (e *EnkryptifyAuth) IsAuthenticated() (bool, error) {
// Check for environment variable token first (for server environments)
if token := os.Getenv(EnvTokenKey); token != "" {
- return true, nil
+ return strings.TrimSpace(token) != "", nil
}
return e.keyring.IsAuthenticated("enkryptify")
}🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| return e.keyring.IsAuthenticated("enkryptify") | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
|
|
@@ -425,6 +438,11 @@ func (e *EnkryptifyAuth) Logout() error { | |||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| // GetAccessToken retrieves the current access token | ||||||||||||||||||||||||||||||||||||
| func (e *EnkryptifyAuth) GetAccessToken() (string, error) { | ||||||||||||||||||||||||||||||||||||
| // Check for environment variable token first (for server environments) | ||||||||||||||||||||||||||||||||||||
| if token := os.Getenv(EnvTokenKey); token != "" { | ||||||||||||||||||||||||||||||||||||
| return token, nil | ||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||
|
Comment on lines
+441
to
+444
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add validation for the environment token. Similar to the concern in Apply this diff to add validation: func (e *EnkryptifyAuth) GetAccessToken() (string, error) {
// Check for environment variable token first (for server environments)
if token := os.Getenv(EnvTokenKey); token != "" {
- return token, nil
+ token = strings.TrimSpace(token)
+ if token == "" {
+ return "", fmt.Errorf("invalid %s: token cannot be empty or whitespace", EnvTokenKey)
+ }
+ return token, nil
}
authInfo, err := e.keyring.GetAuthInfo("enkryptify")📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| authInfo, err := e.keyring.GetAuthInfo("enkryptify") | ||||||||||||||||||||||||||||||||||||
| if err != nil { | ||||||||||||||||||||||||||||||||||||
| return "", err | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -69,6 +69,19 @@ type SecretValue struct { | |||||||||||||||||||||||||||||||||||||||||||||||
| Value string `json:"value"` | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| type ProjectTokenResponse struct { | ||||||||||||||||||||||||||||||||||||||||||||||||
| ID string `json:"id"` | ||||||||||||||||||||||||||||||||||||||||||||||||
| Workspace struct { | ||||||||||||||||||||||||||||||||||||||||||||||||
| ID string `json:"id"` | ||||||||||||||||||||||||||||||||||||||||||||||||
| Slug string `json:"slug"` | ||||||||||||||||||||||||||||||||||||||||||||||||
| } `json:"workspace"` | ||||||||||||||||||||||||||||||||||||||||||||||||
| Project struct { | ||||||||||||||||||||||||||||||||||||||||||||||||
| ID string `json:"id"` | ||||||||||||||||||||||||||||||||||||||||||||||||
| Slug string `json:"slug"` | ||||||||||||||||||||||||||||||||||||||||||||||||
| } `json:"project"` | ||||||||||||||||||||||||||||||||||||||||||||||||
| EnvironmentID string `json:"environmentId"` | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+72
to
+83
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Consider removing the unused ID field. The 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| func NewClient() *Client { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return &Client{ | ||||||||||||||||||||||||||||||||||||||||||||||||
| httpClient: &http.Client{Timeout: 30 * time.Second}, | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -154,4 +167,14 @@ func (c *Client) GetSecrets(workspaceSlug, projectSlug, environmentID string) ([ | |||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| return secrets, nil | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| func (c *Client) GetProjectTokenDetails() (*ProjectTokenResponse, error) { | ||||||||||||||||||||||||||||||||||||||||||||||||
| var tokenDetails ProjectTokenResponse | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if err := c.makeRequest("GET", "/auth/project-token", &tokenDetails); err != nil { | ||||||||||||||||||||||||||||||||||||||||||||||||
| return nil, fmt.Errorf("failed to get project token details: %w", err) | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| return &tokenDetails, nil | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+172
to
180
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Consider validating the API response. The method correctly uses the existing Apply this diff to add validation: func (c *Client) GetProjectTokenDetails() (*ProjectTokenResponse, error) {
var tokenDetails ProjectTokenResponse
if err := c.makeRequest("GET", "/auth/project-token", &tokenDetails); err != nil {
return nil, fmt.Errorf("failed to get project token details: %w", err)
}
+
+ // Validate required fields
+ if tokenDetails.Workspace.Slug == "" || tokenDetails.Project.Slug == "" || tokenDetails.EnvironmentID == "" {
+ return nil, fmt.Errorf("incomplete project token details: missing required fields")
+ }
return &tokenDetails, nil
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Use ui package functions for consistent output formatting.
The code uses
fmt.Printfdirectly instead of theuipackage functions. For consistency with the rest of the codebase, consider usingui.PrintInfofor informational messages.Apply this diff:
🤖 Prompt for AI Agents