Skip to content

Commit 7d1c69f

Browse files
Read API key from environment (#17)
## Problem Currently, there are two methods of authenticating with Pinecone when using the CLI: - Manually logging in to generate an auth token with `pinecone login`. - Manually configuring an API key for the CLI to use with `pinecone config set-api-key "YOUR_KEY"`. There is also one method of swapping the environment that the CLI is targeting ("production" vs. "staging"): - Manually configuring your environment using `pinecone config set-environment "production"`. We've gotten feedback that it would be helpful to allow configuring both API key and the environment value through environment variables rather than needing to explicitly configure them through commands. ## Solution - Update `SecretsViper` and `ConfigViper` to properly bind to environment variables. In both cases we use `viper.SetEnvPrefix("pinecone")` and `viper.BindEnv()` to bind the associated `KeyName`. You can find details about how Viper works here: - https://pkg.go.dev/github.com/spf13/viper#SetEnvPrefix - https://pkg.go.dev/github.com/spf13/viper#BindEnv - What the above does is allows the specific configuration values to read from `PINECONE_API_KEY` and `PINECONE_ENVIRONMENT` as needed. If a user calls `pinecone config set-environment` or `pinecone config set-api-key`, that value will take precedence over the environment value. - Update `README` to be a bit more explicit about different ways of authenticating with the CLI, and which takes precedence. ## Type of Change - [ ] Bug fix (non-breaking change which fixes an issue) - [X] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update - [ ] Infrastructure change (CI configs, etc) - [ ] Non-code change (docs, etc) - [ ] None of the above: (explain here) ## Test Plan Pull this branch down, use `goreleaser` to build, and try various options for authenticating with the CLI. ``` # build CLI locally goreleaser build --single-target --snapshot --clean # try with environment API key export PINECONE_API_KEY="MY_KEY" ./dist/pinecone_darwin_arm64/pinecone index list # try with config API key ./dist/pinecone_darwin_arm64/pinecone config set-api-key "MY_KEY" ./dist/pinecone_darwin_arm64/pinecone index list # try setting the environment export PINECONE_ENVIRONMENT="staging" ./dist/pinecone_darwin_arm64/pinecone index list # above should fail if you haven't swapped your API key to a staging API key unset PINECONE_ENVIRONMENT # clear things and try with login flow ./dist/pinecone_darwin_arm64/pinecone logout unset PINECONE_API_KEY ./dist/pinecone_darwin_arm64/pinecone login ``` --- - To see the specific tasks where the Asana app for GitHub is being used, see below: - https://app.asana.com/0/0/1207872106532407
1 parent a9a6066 commit 7d1c69f

File tree

4 files changed

+57
-5
lines changed

4 files changed

+57
-5
lines changed

README.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Pinecone CLI
22

3-
`pinecone` is Pinecone on the command line.
3+
`pinecone` is Pinecone on the command line.
44

55
This CLI is still in an alpha state and does not support every operation available through our REST apis. Please try it out and give us your feedback, but also be prepared to upgrade as we continue building out the feature set and improving the UX.
66

@@ -34,12 +34,28 @@ To learn about the steps involved in building from source, see [CONTRIBUTING](./
3434

3535
## Usage
3636

37+
In order to use the Pinecone CLI you will need to authenticate with Pinecone services. This can be done either with an API key, or using the `pinecone login` flow to authenticate with a Pinecone account via your browser.
38+
3739
```shell
3840
pinecone --help
3941

42+
# If you have PINECONE_API_KEY set in your environment you can begin working with the CLI
43+
pinecone index list
44+
45+
# To set an API key manually, you can use the config command
46+
pinecone config set-api-key "YOUR_API_KEY"
47+
48+
# Additionally, you can authenticate through the browser using the login command
4049
pinecone login
50+
51+
# To clear your current login state or configured API key, you can use the logout command
52+
pinecone logout
4153
```
4254

55+
If an API key is configured along with using `pinecone login`, the CLI will default to using the API key over the authentication token.
56+
57+
If there has been an API key set using `pinecone config set-api-key`, and `PINECONE_API_KEY` is also present in the environment, the API set in the CLI config will be used over the environment key.
58+
4359
### Managing indexes
4460

4561
```sh

internal/pkg/utils/configuration/config/config.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package config
22

33
import (
4+
"fmt"
5+
"strings"
6+
47
"github.com/pinecone-io/cli/internal/pkg/utils/configuration"
8+
"github.com/pinecone-io/cli/internal/pkg/utils/exit"
59
"github.com/spf13/viper"
610
)
711

@@ -33,4 +37,30 @@ var configFile = configuration.ConfigFile{
3337

3438
func init() {
3539
configFile.Init()
40+
41+
ConfigViper.SetEnvPrefix("pinecone")
42+
err := ConfigViper.BindEnv(Environment.KeyName)
43+
if err != nil {
44+
exit.Error(err)
45+
}
46+
47+
err = validateEnvironment(Environment.Get())
48+
fmt.Printf("ERROR? %v\n", err)
49+
if err != nil {
50+
exit.Error(err)
51+
}
52+
}
53+
54+
func validateEnvironment(env string) error {
55+
validEnvs := []string{"production", "staging"}
56+
for _, validEnv := range validEnvs {
57+
if env == validEnv {
58+
return nil
59+
}
60+
}
61+
quotedEnvs := make([]string, len(validEnvs))
62+
for i, validEnv := range validEnvs {
63+
quotedEnvs[i] = fmt.Sprintf("\"%s\"", validEnv)
64+
}
65+
return fmt.Errorf("invalid environment: \"%s\", must be one of %s", env, strings.Join(quotedEnvs, ", "))
3666
}

internal/pkg/utils/configuration/secrets/secrets.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package secrets
22

33
import (
44
"github.com/pinecone-io/cli/internal/pkg/utils/configuration"
5+
"github.com/pinecone-io/cli/internal/pkg/utils/exit"
56
"github.com/spf13/viper"
67
"golang.org/x/oauth2"
78
)
@@ -36,4 +37,10 @@ var ConfigFile = configuration.ConfigFile{
3637

3738
func init() {
3839
ConfigFile.Init()
40+
41+
SecretsViper.SetEnvPrefix("pinecone")
42+
err := SecretsViper.BindEnv(ApiKey.KeyName)
43+
if err != nil {
44+
exit.Error(err)
45+
}
3946
}

internal/pkg/utils/sdk/client.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,15 @@ func newClientForUserFromTarget() *pinecone.Client {
4343
Str("targetProjectId", targetProjectId).
4444
Msg("Loading target context")
4545

46-
apiKey := secrets.ApiKey.Get()
4746
oauth2Token := secrets.OAuth2Token.Get()
4847

49-
if apiKey != "" {
48+
if secrets.ApiKey.Get() != "" {
5049
if oauth2Token.AccessToken != "" {
51-
msg.WarnMsg("You are currently logged in and also have an API key set in your configuration. The API key (which is linked to a specific project) will be used in preference to any user authentication and target context that may be present.\n")
50+
msg.WarnMsg("You are currently logged in and also have an API key set in your environment and/or local configuration. The API key (which is linked to a specific project) will be used in preference to any user authentication and target context that may be present.\n")
5251
}
5352

5453
log.Debug().Msg("Creating client for machine using stored API key")
55-
return NewClientForMachine(apiKey)
54+
return NewClientForMachine(secrets.ApiKey.Get())
5655
}
5756

5857
log.Debug().Msg("No API key is stored in configuration, so attempting to create a client using user access token")

0 commit comments

Comments
 (0)