Skip to content

No public description - #20

Open
wanlin31 wants to merge 1 commit into
mainfrom
copybara/978052929
Open

wanlin31 wants to merge 1 commit into
mainfrom
copybara/978052929

Conversation

@wanlin31

Copy link
Copy Markdown

No public description

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request replaces the experimental Node.js/Bun-based Gemini API CLI with a robust Go implementation generated by Speakeasy, introducing comprehensive commands for managing agents, environments, triggers, and webhooks. The review feedback identifies a security concern where errors from storing secrets in the OS keychain are silently ignored, potentially falling back to plaintext storage in the configuration file without warning the user. Additionally, the reviewer noted that the readSecret helper function is unused and should be removed to clean up the codebase.

Comment thread internal/cli/auth.go
Comment on lines +123 to +136
if f := cmd.Flags().Lookup("api-key"); f != nil && f.Changed {
v, _ := cmd.Flags().GetString("api-key")
if config.StoreSecret("api-key", v, &cfg.Security.ApiKey) == nil {
keychainStored = true
}
changed = true
}
if f := cmd.Flags().Lookup("access-token"); f != nil && f.Changed {
v, _ := cmd.Flags().GetString("access-token")
if config.StoreSecret("access-token", v, &cfg.Security.AccessToken) == nil {
keychainStored = true
}
changed = true
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

When storing credentials via config.StoreSecret, any error returned by the function (such as keyring locked or DBus connection issues) is silently ignored. If the OS keychain is available but the storage operation fails, the secret falls back to being written in plaintext to config.yaml without any warning to the user.

To improve security and transparency, consider checking the returned error and printing a warning to cmd.ErrOrStderr() if the error is not config.ErrKeyringUnavailable.

Suggested change
if f := cmd.Flags().Lookup("api-key"); f != nil && f.Changed {
v, _ := cmd.Flags().GetString("api-key")
if config.StoreSecret("api-key", v, &cfg.Security.ApiKey) == nil {
keychainStored = true
}
changed = true
}
if f := cmd.Flags().Lookup("access-token"); f != nil && f.Changed {
v, _ := cmd.Flags().GetString("access-token")
if config.StoreSecret("access-token", v, &cfg.Security.AccessToken) == nil {
keychainStored = true
}
changed = true
}
changed := false
if f := cmd.Flags().Lookup("api-key"); f != nil && f.Changed {
v, _ := cmd.Flags().GetString("api-key")
if err := config.StoreSecret("api-key", v, &cfg.Security.ApiKey); err == nil {
keychainStored = true
} else if err != config.ErrKeyringUnavailable {
fmt.Fprintf(cmd.ErrOrStderr(), "Warning: failed to store api-key in OS keychain: %v. Falling back to plaintext config file.\n", err)
}
changed = true
}
if f := cmd.Flags().Lookup("access-token"); f != nil && f.Changed {
v, _ := cmd.Flags().GetString("access-token")
if err := config.StoreSecret("access-token", v, &cfg.Security.AccessToken); err == nil {
keychainStored = true
} else if err != config.ErrKeyringUnavailable {
fmt.Fprintf(cmd.ErrOrStderr(), "Warning: failed to store access-token in OS keychain: %v. Falling back to plaintext config file.\n", err)
}
changed = true
}

Comment thread internal/cli/auth.go
Comment on lines +182 to +186
if authApiKey != "" {
if config.StoreSecret("api-key", authApiKey, &cfg.Security.ApiKey) == nil {
keychainStored = true
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

Similar to the non-interactive path, any error returned by config.StoreSecret when storing the api-key is silently ignored. Consider checking the error and printing a warning if the OS keychain is available but the storage operation fails.

Suggested change
if authApiKey != "" {
if config.StoreSecret("api-key", authApiKey, &cfg.Security.ApiKey) == nil {
keychainStored = true
}
}
if authApiKey != "" {
if err := config.StoreSecret("api-key", authApiKey, &cfg.Security.ApiKey); err == nil {
keychainStored = true
} else if err != config.ErrKeyringUnavailable {
fmt.Fprintf(cmd.ErrOrStderr(), "Warning: failed to store api-key in OS keychain: %v. Falling back to plaintext config file.\n", err)
}
}

Comment thread internal/cli/auth.go
Comment on lines +210 to +214
if authAccessToken != "" {
if config.StoreSecret("access-token", authAccessToken, &cfg.Security.AccessToken) == nil {
keychainStored = true
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

Similar to the non-interactive path, any error returned by config.StoreSecret when storing the access-token is silently ignored. Consider checking the error and printing a warning if the OS keychain is available but the storage operation fails.

			if authAccessToken != "" {
				if err := config.StoreSecret("access-token", authAccessToken, &cfg.Security.AccessToken); err == nil {
					keychainStored = true
				} else if err != config.ErrKeyringUnavailable {
					fmt.Fprintf(cmd.ErrOrStderr(), "Warning: failed to store access-token in OS keychain: %v. Falling back to plaintext config file.\n", err)
				}
			}

Comment thread internal/cli/configure.go
Comment on lines +74 to +87
if f := cmd.Flags().Lookup("api-key"); f != nil && f.Changed {
v, _ := cmd.Flags().GetString("api-key")
if config.StoreSecret("api-key", v, &cfg.Security.ApiKey) == nil {
keychainStored = true
}
changed = true
}
if f := cmd.Flags().Lookup("access-token"); f != nil && f.Changed {
v, _ := cmd.Flags().GetString("access-token")
if config.StoreSecret("access-token", v, &cfg.Security.AccessToken) == nil {
keychainStored = true
}
changed = true
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

When configuring credentials, any error returned by config.StoreSecret is silently ignored. If the OS keychain is available but the storage operation fails, the secret falls back to being written in plaintext to config.yaml without any warning to the user.

To improve security and transparency, consider checking the returned error and printing a warning to cmd.ErrOrStderr() if the error is not config.ErrKeyringUnavailable.

Suggested change
if f := cmd.Flags().Lookup("api-key"); f != nil && f.Changed {
v, _ := cmd.Flags().GetString("api-key")
if config.StoreSecret("api-key", v, &cfg.Security.ApiKey) == nil {
keychainStored = true
}
changed = true
}
if f := cmd.Flags().Lookup("access-token"); f != nil && f.Changed {
v, _ := cmd.Flags().GetString("access-token")
if config.StoreSecret("access-token", v, &cfg.Security.AccessToken) == nil {
keychainStored = true
}
changed = true
}
if f := cmd.Flags().Lookup("api-key"); f != nil && f.Changed {
v, _ := cmd.Flags().GetString("api-key")
if err := config.StoreSecret("api-key", v, &cfg.Security.ApiKey); err == nil {
keychainStored = true
} else if err != config.ErrKeyringUnavailable {
fmt.Fprintf(cmd.ErrOrStderr(), "Warning: failed to store api-key in OS keychain: %v. Falling back to plaintext config file.\n", err)
}
changed = true
}
if f := cmd.Flags().Lookup("access-token"); f != nil && f.Changed {
v, _ := cmd.Flags().GetString("access-token")
if err := config.StoreSecret("access-token", v, &cfg.Security.AccessToken); err == nil {
keychainStored = true
} else if err != config.ErrKeyringUnavailable {
fmt.Fprintf(cmd.ErrOrStderr(), "Warning: failed to store access-token in OS keychain: %v. Falling back to plaintext config file.\n", err)
}
changed = true
}

Comment thread internal/cli/configure.go
Comment on lines +178 to +188
if authApiKey != "" {
if config.StoreSecret("api-key", authApiKey, &cfg.Security.ApiKey) == nil {
keychainStored = true
}
}

if authAccessToken != "" {
if config.StoreSecret("access-token", authAccessToken, &cfg.Security.AccessToken) == nil {
keychainStored = true
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

Similar to the non-interactive path, any error returned by config.StoreSecret when storing the credentials is silently ignored. Consider checking the error and printing a warning if the OS keychain is available but the storage operation fails.

Suggested change
if authApiKey != "" {
if config.StoreSecret("api-key", authApiKey, &cfg.Security.ApiKey) == nil {
keychainStored = true
}
}
if authAccessToken != "" {
if config.StoreSecret("access-token", authAccessToken, &cfg.Security.AccessToken) == nil {
keychainStored = true
}
}
if authApiKey != "" {
if err := config.StoreSecret("api-key", authApiKey, &cfg.Security.ApiKey); err == nil {
keychainStored = true
} else if err != config.ErrKeyringUnavailable {
fmt.Fprintf(cmd.ErrOrStderr(), "Warning: failed to store api-key in OS keychain: %v. Falling back to plaintext config file.\n", err)
}
}
if authAccessToken != "" {
if err := config.StoreSecret("access-token", authAccessToken, &cfg.Security.AccessToken); err == nil {
keychainStored = true
} else if err != config.ErrKeyringUnavailable {
fmt.Fprintf(cmd.ErrOrStderr(), "Warning: failed to store access-token in OS keychain: %v. Falling back to plaintext config file.\n", err)
}
}

Comment thread internal/cli/masking.go
Comment on lines +44 to +56
func readSecret(cmd *cobra.Command) ([]byte, error) {
if f, ok := cmd.InOrStdin().(*os.File); ok && term.IsTerminal(int(f.Fd())) {
return term.ReadPassword(int(f.Fd()))
}

// Non-terminal fallback: read a line from cmd input (supports test harness piped input)
reader := bufio.NewReader(cmd.InOrStdin())
line, err := reader.ReadString('\n')
if err != nil && line == "" {
return nil, err
}
return []byte(strings.TrimRight(line, "\r\n")), nil
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The readSecret function is defined but never used anywhere in the codebase. To keep the codebase clean and maintainable, consider removing this unused function.

PiperOrigin-RevId: 978052929
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant