-
Notifications
You must be signed in to change notification settings - Fork 271
new(redis-cli): Add support for Redis CLI with password as environment variable and command-line flags #276
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
Open
arunsathiya
wants to merge
49
commits into
main
Choose a base branch
from
new/redis
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+449
−0
Open
Changes from all commits
Commits
Show all changes
49 commits
Select commit
Hold shift + click to select a range
be92d38
Working shell plugin with environment variable support for the passwo…
arunsathiya 0e6b425
Use NotForVersion check instead of defining each version flag one by …
arunsathiya a7bc372
Update CLI docs URL
arunsathiya 9892e54
Add test for environment variable importer
arunsathiya bed61f7
Add support for host and port, in conjunction with password as enviro…
arunsathiya 7365c78
Better description for the Redis environment variable and flags provi…
arunsathiya c065d86
Add username to the credential as well, thus allowing scoped access t…
arunsathiya 1e158f8
Use shell plugin even without args, if one wants to enter redis shell…
arunsathiya 634c9dc
Introduce second credential that'd be used only for authenticating to…
arunsathiya 90c5674
Do not use 1Password authentication when --help flag is used
arunsathiya 55ac590
Define ID for the credential selection and description for the creden…
arunsathiya 14cb2e4
Switch from credential selection to credential reference with just Us…
arunsathiya f242d43
Mark host and port as optional fields
arunsathiya 94a056f
Rename argument provision functions to AddArgsFirst and AddArgsLast
arunsathiya 68d35a5
Introduce flags provision and chained provision at the SDK level and …
arunsathiya d93ce0a
Rename flags to args
arunsathiya 1f9b41f
Describe the new arguments and chained provisioners, and better handl…
arunsathiya 26fea29
Better handling of the arguments index using a map that maps the argu…
arunsathiya 81293a9
Describe what ArgsProvisioner does better
arunsathiya e538aae
Remove unnecessary provisioner field in the ChainedProvisioner
arunsathiya a980f0c
Remove validation check that checks if multiple credentials are defin…
arunsathiya 080d6db
Switch from provisioning at a specific index to either immediately af…
arunsathiya 588f520
Address feedback to rename credential name to APIKey and credential f…
arunsathiya 1c666ed
Add ManagementURL for the Redis Cloud API Keys credential
arunsathiya c94621d
Remove length for account key and user key fields, because they don't…
arunsathiya 4911721
Remove the description that the default username will be default, bec…
arunsathiya 3f26c9d
Revert "Switch from provisioning at a specific index to either immedi…
arunsathiya 5a15a10
Rename AddArgs helper function to AddArgsAtIndex, and in the ArgsProv…
arunsathiya ca6978b
Swap around the index and args params in ArgsAtIndex function for bet…
arunsathiya 26e621c
Reintroduce AddArgs helper function and fix FileProvisioner breakage
arunsathiya 1286d92
Remove Arguments Provisioner completely and introduce redis-specific …
arunsathiya 681375e
Update redis Enterprise Cloud platform credential fields to the moder…
arunsathiya d96f43a
Remove unused AccessKey and SecretKey field names
arunsathiya 510fe41
Move executable code from redis-cli to redis_cli as snake case is mor…
arunsathiya c430598
Remove optional field in certain field name structs because the defau…
arunsathiya 3507031
Since redis CLI requires injecting arguments only at index 1, indexTo…
arunsathiya 3875a13
Remove chained provisioner and add REDISCLI_AUTH directly in custom r…
arunsathiya 472076e
Branch out rediscloud as a separate shell plugin
arunsathiya 80ad3bd
Update rediscloud platform homepage address
arunsathiya 72c737c
Since rediscloud is a separate shell plugin now, rename credential fu…
arunsathiya 3a138cd
Revert "Remove validation check that checks if multiple credentials a…
arunsathiya 8a1f3ca
Switch redis provision from map-based struct to string, because it al…
arunsathiya 6d6baf7
Update test to verify the provisioned arguments and expected command …
arunsathiya cecb2d0
Refactor argument provisioning logic to avoid string splitting
arunsathiya c015cea
Skip 1Password authentication when an user enters a custom host or po…
arunsathiya c8a216d
Fix provisoner test
arunsathiya 92e7f56
Safeguard in the arguments injection code to prevent out of bounds er…
arunsathiya c09b864
Don't skip auth for certain flags, rather use them in conjunction wit…
arunsathiya 9139722
rebasing and making some fixes
scottisloud File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| package redis | ||
|
|
||
| import ( | ||
| "github.com/1Password/shell-plugins/sdk" | ||
| "github.com/1Password/shell-plugins/sdk/schema" | ||
| ) | ||
|
|
||
| func New() schema.Plugin { | ||
| return schema.Plugin{ | ||
| Name: "redis", | ||
| Platform: schema.PlatformInfo{ | ||
| Name: "Redis", | ||
| Homepage: sdk.URL("https://redis.io/"), | ||
| }, | ||
| Credentials: []schema.CredentialType{ | ||
| UserCredentials(), | ||
| }, | ||
| Executables: []schema.Executable{ | ||
| RedisCLI(), | ||
| }, | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| package redis | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| "github.com/1Password/shell-plugins/sdk" | ||
| "github.com/1Password/shell-plugins/sdk/schema/fieldname" | ||
| ) | ||
|
|
||
| type redisArgsProvisioner struct { | ||
| } | ||
|
|
||
| func redisProvisioner() sdk.Provisioner { | ||
| return redisArgsProvisioner{} | ||
| } | ||
|
|
||
| // Redis CLI flags that, when already supplied by the user, signal that we | ||
| // should not provision the corresponding field from the 1Password item. | ||
| var ( | ||
| hostFlags = []string{"-h"} | ||
| portFlags = []string{"-p"} | ||
| userFlags = []string{"--user"} | ||
| passwordFlags = []string{"-a", "--pass"} | ||
| ) | ||
|
|
||
| func (p redisArgsProvisioner) Provision(ctx context.Context, in sdk.ProvisionInput, out *sdk.ProvisionOutput) { | ||
| suppliedFlags := flagSet(out.CommandLine) | ||
|
|
||
| // The password is passed via an environment variable so it never appears in | ||
| // the process's argument list. Skip it if the user already authenticated on | ||
| // the command line. | ||
| if value, ok := in.ItemFields[fieldname.Password]; ok && !containsAny(suppliedFlags, passwordFlags) { | ||
| out.AddEnvVar("REDISCLI_AUTH", value) | ||
| } | ||
|
|
||
| // Collect the flags to inject first, then prepend them in a single pass. | ||
| // Mutating out.CommandLine while ranging over it risks index-out-of-range | ||
| // panics and stale reads, so we never modify it during inspection. | ||
| var injected []string | ||
| if value, ok := in.ItemFields[fieldname.Host]; ok && !containsAny(suppliedFlags, hostFlags) { | ||
| injected = append(injected, "-h", value) | ||
| } | ||
| if value, ok := in.ItemFields[fieldname.Port]; ok && !containsAny(suppliedFlags, portFlags) { | ||
| injected = append(injected, "-p", value) | ||
| } | ||
| if value, ok := in.ItemFields[fieldname.Username]; ok && !containsAny(suppliedFlags, userFlags) { | ||
| injected = append(injected, "--user", value) | ||
| } | ||
|
|
||
| if len(injected) > 0 { | ||
| out.CommandLine = prependArgs(out.CommandLine, injected) | ||
| } | ||
|
arunsathiya marked this conversation as resolved.
|
||
| } | ||
|
|
||
| func (p redisArgsProvisioner) Deprovision(ctx context.Context, in sdk.DeprovisionInput, out *sdk.DeprovisionOutput) { | ||
| // Nothing to do here: credentials get wiped automatically when the process exits. | ||
| } | ||
|
|
||
| func (p redisArgsProvisioner) Description() string { | ||
| return "Provision redis secrets as command-line arguments and the password as an environment variable." | ||
| } | ||
|
|
||
| // flagSet returns the set of arguments present on the command line, excluding | ||
| // the executable name at index 0. | ||
| func flagSet(commandLine []string) map[string]bool { | ||
| set := make(map[string]bool, len(commandLine)) | ||
| for i, arg := range commandLine { | ||
| if i == 0 { | ||
| continue | ||
| } | ||
| set[arg] = true | ||
| } | ||
| return set | ||
| } | ||
|
|
||
| func containsAny(set map[string]bool, flags []string) bool { | ||
| for _, f := range flags { | ||
| if set[f] { | ||
| return true | ||
| } | ||
| } | ||
| return false | ||
| } | ||
|
|
||
| // prependArgs inserts args immediately after the executable name (index 0), | ||
| // leaving the rest of the user-supplied command line intact. | ||
| func prependArgs(commandLine []string, args []string) []string { | ||
| if len(commandLine) == 0 { | ||
| return append([]string{}, args...) | ||
| } | ||
| result := make([]string, 0, len(commandLine)+len(args)) | ||
| result = append(result, commandLine[0]) | ||
| result = append(result, args...) | ||
| result = append(result, commandLine[1:]...) | ||
| return result | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| package redis | ||
|
|
||
| import ( | ||
| "github.com/1Password/shell-plugins/sdk" | ||
| "github.com/1Password/shell-plugins/sdk/needsauth" | ||
| "github.com/1Password/shell-plugins/sdk/schema" | ||
| "github.com/1Password/shell-plugins/sdk/schema/credname" | ||
| ) | ||
|
|
||
| func RedisCLI() schema.Executable { | ||
| return schema.Executable{ | ||
| Name: "Redis CLI", | ||
| Runs: []string{"redis-cli"}, | ||
| DocsURL: sdk.URL("https://redis.io/docs/ui/cli"), | ||
| NeedsAuth: needsauth.IfAll( | ||
| needsauth.NotWhenContainsArgs("--help"), | ||
| needsauth.NotForVersion(), | ||
| ), | ||
| Uses: []schema.CredentialUsage{ | ||
| { | ||
| Name: credname.UserCredentials, | ||
| Provisioner: redisProvisioner(), | ||
| }, | ||
| }, | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| package redis | ||
|
|
||
| import ( | ||
| "github.com/1Password/shell-plugins/sdk" | ||
| "github.com/1Password/shell-plugins/sdk/importer" | ||
| "github.com/1Password/shell-plugins/sdk/provision" | ||
| "github.com/1Password/shell-plugins/sdk/schema" | ||
| "github.com/1Password/shell-plugins/sdk/schema/credname" | ||
| "github.com/1Password/shell-plugins/sdk/schema/fieldname" | ||
| ) | ||
|
|
||
| func UserCredentials() schema.CredentialType { | ||
| return schema.CredentialType{ | ||
| Name: credname.UserCredentials, | ||
| DocsURL: sdk.URL("https://redis.io/docs/ui/cli/#host-port-password-and-database"), | ||
| Fields: []schema.CredentialField{ | ||
| { | ||
| Name: fieldname.Password, | ||
| MarkdownDescription: "Password used to authenticate to Redis server.", | ||
| Secret: true, | ||
| Composition: &schema.ValueComposition{ | ||
| Charset: schema.Charset{ | ||
| Uppercase: true, | ||
| Lowercase: true, | ||
| Digits: true, | ||
| }, | ||
| }, | ||
| }, | ||
| { | ||
| Name: fieldname.Username, | ||
| MarkdownDescription: "Username used to authenticate to Redis server.", | ||
| Secret: false, | ||
| Optional: true, | ||
| Composition: &schema.ValueComposition{ | ||
| Charset: schema.Charset{ | ||
| Uppercase: true, | ||
| Lowercase: true, | ||
| Digits: true, | ||
| }, | ||
| }, | ||
| }, | ||
| { | ||
| Name: fieldname.Host, | ||
|
arunsathiya marked this conversation as resolved.
|
||
| MarkdownDescription: "Host address for the Redis server.", | ||
| Secret: false, | ||
| Optional: true, | ||
| Composition: &schema.ValueComposition{ | ||
| Charset: schema.Charset{ | ||
| Lowercase: true, | ||
| Symbols: true, | ||
| Digits: true, | ||
| }, | ||
| }, | ||
| }, | ||
| { | ||
| Name: fieldname.Port, | ||
| MarkdownDescription: "Port for the Redis server.", | ||
| Secret: false, | ||
| Optional: true, | ||
| Composition: &schema.ValueComposition{ | ||
| Charset: schema.Charset{ | ||
| Digits: true, | ||
| }, | ||
|
arunsathiya marked this conversation as resolved.
|
||
| }, | ||
| }, | ||
| }, | ||
| DefaultProvisioner: provision.EnvVars(defaultEnvVarMapping), | ||
| Importer: importer.TryAll( | ||
| importer.TryEnvVarPair(defaultEnvVarMapping), | ||
| )} | ||
| } | ||
|
|
||
| var defaultEnvVarMapping = map[string]sdk.FieldName{ | ||
| "REDISCLI_AUTH": fieldname.Password, | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| package redis | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/1Password/shell-plugins/sdk" | ||
| "github.com/1Password/shell-plugins/sdk/plugintest" | ||
| "github.com/1Password/shell-plugins/sdk/schema/fieldname" | ||
| ) | ||
|
|
||
| func TestUserCredentialsProvisioner(t *testing.T) { | ||
| plugintest.TestProvisioner(t, redisProvisioner(), map[string]plugintest.ProvisionCase{ | ||
| "default": { | ||
| ItemFields: map[sdk.FieldName]string{ | ||
| fieldname.Password: "pjtxpc2gaddifapjvalggspojexample", | ||
| fieldname.Username: "example", | ||
| fieldname.Host: "127.0.0.1", | ||
| fieldname.Port: "6379", | ||
| }, | ||
| CommandLine: []string{"redis-cli"}, | ||
| ExpectedOutput: sdk.ProvisionOutput{ | ||
| Environment: map[string]string{ | ||
| "REDISCLI_AUTH": "pjtxpc2gaddifapjvalggspojexample", | ||
| }, | ||
| CommandLine: []string{"redis-cli", "-h", "127.0.0.1", "-p", "6379", "--user", "example"}, | ||
| }, | ||
| }, | ||
| // User supplies some flags themselves: we must not duplicate them, but | ||
| // should still provision the fields they left out (and keep their args). | ||
| "user-supplied flags are respected": { | ||
| ItemFields: map[sdk.FieldName]string{ | ||
| fieldname.Password: "pjtxpc2gaddifapjvalggspojexample", | ||
| fieldname.Username: "example", | ||
| fieldname.Host: "127.0.0.1", | ||
| fieldname.Port: "6379", | ||
| }, | ||
| CommandLine: []string{"redis-cli", "-h", "myhost", "PING"}, | ||
| ExpectedOutput: sdk.ProvisionOutput{ | ||
| Environment: map[string]string{ | ||
| "REDISCLI_AUTH": "pjtxpc2gaddifapjvalggspojexample", | ||
| }, | ||
| CommandLine: []string{"redis-cli", "-p", "6379", "--user", "example", "-h", "myhost", "PING"}, | ||
| }, | ||
| }, | ||
| // A recognized flag as the final token used to cause an index-out-of-range | ||
| // panic; ensure it is handled gracefully. | ||
| "recognized flag as last token": { | ||
| ItemFields: map[sdk.FieldName]string{ | ||
| fieldname.Password: "pjtxpc2gaddifapjvalggspojexample", | ||
| fieldname.Host: "127.0.0.1", | ||
| }, | ||
| CommandLine: []string{"redis-cli", "-h"}, | ||
| ExpectedOutput: sdk.ProvisionOutput{ | ||
| Environment: map[string]string{ | ||
| "REDISCLI_AUTH": "pjtxpc2gaddifapjvalggspojexample", | ||
| }, | ||
| CommandLine: []string{"redis-cli", "-h"}, | ||
| }, | ||
| }, | ||
| // User authenticates on the command line: don't also set the env var. | ||
| "password flag skips env var": { | ||
| ItemFields: map[sdk.FieldName]string{ | ||
| fieldname.Password: "pjtxpc2gaddifapjvalggspojexample", | ||
| }, | ||
| CommandLine: []string{"redis-cli", "-a", "mypassword"}, | ||
| ExpectedOutput: sdk.ProvisionOutput{ | ||
| CommandLine: []string{"redis-cli", "-a", "mypassword"}, | ||
| }, | ||
| }, | ||
| }) | ||
| } | ||
| func TestDefaultUserCredentialsProvisioner(t *testing.T) { | ||
| plugintest.TestProvisioner(t, UserCredentials().DefaultProvisioner, map[string]plugintest.ProvisionCase{ | ||
| "default": { | ||
| ItemFields: map[sdk.FieldName]string{ | ||
| fieldname.Password: "pjtxpc2gaddifapjvalggspojexample", | ||
| }, | ||
| ExpectedOutput: sdk.ProvisionOutput{ | ||
| Environment: map[string]string{ | ||
|
AndyTitu marked this conversation as resolved.
|
||
| "REDISCLI_AUTH": "pjtxpc2gaddifapjvalggspojexample", | ||
| }, | ||
| }, | ||
| }, | ||
| }) | ||
| } | ||
|
|
||
| func TestUserCredentialsImporter(t *testing.T) { | ||
| plugintest.TestImporter(t, UserCredentials().Importer, map[string]plugintest.ImportCase{ | ||
| "environment": { | ||
| Environment: map[string]string{ | ||
| "REDISCLI_AUTH": "pjtxpc2gaddifapjvalggspojexample", | ||
| }, | ||
| ExpectedCandidates: []sdk.ImportCandidate{ | ||
| { | ||
| Fields: map[sdk.FieldName]string{ | ||
| fieldname.Password: "pjtxpc2gaddifapjvalggspojexample", | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| package rediscloud | ||
|
|
||
| import ( | ||
| "github.com/1Password/shell-plugins/sdk" | ||
| "github.com/1Password/shell-plugins/sdk/importer" | ||
| "github.com/1Password/shell-plugins/sdk/provision" | ||
| "github.com/1Password/shell-plugins/sdk/schema" | ||
| "github.com/1Password/shell-plugins/sdk/schema/credname" | ||
| "github.com/1Password/shell-plugins/sdk/schema/fieldname" | ||
| ) | ||
|
|
||
| func APIKey() schema.CredentialType { | ||
| return schema.CredentialType{ | ||
| Name: credname.APIKey, | ||
| DocsURL: sdk.URL("https://docs.redis.com/latest/rc/api/get-started/manage-api-keys/"), | ||
| ManagementURL: sdk.URL("https://app.redislabs.com/#/access-management/api-keys"), | ||
| Fields: []schema.CredentialField{ | ||
| { | ||
| Name: fieldname.AccountKey, | ||
| MarkdownDescription: "API Account key (also known as Access Key, or just API Key) to authenticate to Redis Enterprise Cloud.", | ||
| Secret: true, | ||
| Composition: &schema.ValueComposition{ | ||
| Charset: schema.Charset{ | ||
| Uppercase: true, | ||
| Lowercase: true, | ||
| Digits: true, | ||
| }, | ||
| }, | ||
| }, | ||
| { | ||
| Name: fieldname.UserKey, | ||
| MarkdownDescription: "API user key (also known as Secret Key) to authenticate to Redis Enterprise Cloud.", | ||
| Secret: true, | ||
| Composition: &schema.ValueComposition{ | ||
| Charset: schema.Charset{ | ||
| Uppercase: true, | ||
| Lowercase: true, | ||
| Digits: true, | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| DefaultProvisioner: provision.EnvVars(envVarMappingForRedisCloud), | ||
| Importer: importer.TryAll( | ||
| importer.TryEnvVarPair(envVarMappingForRedisCloud), | ||
| )} | ||
| } | ||
|
|
||
| var envVarMappingForRedisCloud = map[string]sdk.FieldName{ | ||
| "REDISCLOUD_ACCESS_KEY": fieldname.AccountKey, | ||
| "REDISCLOUD_SECRET_KEY": fieldname.UserKey, | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.