From 44e07932a0582ef54728eff0e663743364324b9d Mon Sep 17 00:00:00 2001 From: Henrique Moraes Date: Wed, 12 Aug 2020 21:25:13 -0300 Subject: [PATCH 1/6] [Enhancement] Asking for credential during formula runtime Signed-off-by: Henrique Moraes [Enhancement] Ask for credential during formula runtime# --- cmd/main.go | 2 +- pkg/credential/finder.go | 2 +- pkg/env/env.go | 4 +- pkg/env/envcredential/env_credential.go | 52 +++++++++---- pkg/env/envcredential/env_credential_test.go | 81 ++++++++++++++++++++ pkg/formula/runner/inputs.go | 2 +- 6 files changed, 124 insertions(+), 19 deletions(-) create mode 100644 pkg/env/envcredential/env_credential_test.go diff --git a/cmd/main.go b/cmd/main.go index 8c32e0bee..fee684fc3 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -110,7 +110,7 @@ func buildCommands() *cobra.Command { treeManager := tree.NewTreeManager(ritchieHomeDir, repoLister, api.CoreCmds) credSettings := credential.NewSettings(fileManager, dirManager, userHomeDir) autocompleteGen := autocomplete.NewGenerator(treeManager) - credResolver := envcredential.NewResolver(credFinder) + credResolver := envcredential.NewResolver(credFinder, credSetter) envResolvers := make(env.Resolvers) envResolvers[env.Credential] = credResolver tutorialFinder := rtutorial.NewFinder(ritchieHomeDir, fileManager) diff --git a/pkg/credential/finder.go b/pkg/credential/finder.go index 9a2446fd4..d2bfe675c 100644 --- a/pkg/credential/finder.go +++ b/pkg/credential/finder.go @@ -59,7 +59,7 @@ func (f Finder) Find(provider string) (Detail, error) { cb, err := f.file.Read(File(f.homePath, ctx.Current, provider)) if err != nil { errMsg := fmt.Sprintf(errNotFoundTemplate, provider) - return Detail{}, errors.New(prompt.Red(errMsg)) + return Detail{Credential: Credential{}}, errors.New(prompt.Red(errMsg)) } cred := &Detail{} diff --git a/pkg/env/env.go b/pkg/env/env.go index 993c12aa0..19b6df8f6 100644 --- a/pkg/env/env.go +++ b/pkg/env/env.go @@ -16,6 +16,8 @@ package env +import "github.com/ZupIT/ritchie-cli/pkg/prompt" + const ( // Credential resolver Credential = "CREDENTIAL" @@ -25,5 +27,5 @@ type Resolvers map[string]Resolver // Resolver is an interface that we can use to resolve reserved envs type Resolver interface { - Resolve(name string) (string, error) + Resolve(name string, password prompt.InputPassword) (string, error) } diff --git a/pkg/env/envcredential/env_credential.go b/pkg/env/envcredential/env_credential.go index 7deeec26d..cc49a4761 100644 --- a/pkg/env/envcredential/env_credential.go +++ b/pkg/env/envcredential/env_credential.go @@ -17,7 +17,6 @@ package envcredential import ( - "errors" "fmt" "strings" @@ -27,29 +26,52 @@ import ( type CredentialResolver struct { credential.Finder + credential.Setter } -const errKeyNotFoundTemplate = `Provider %s has not the credential type %s. -Please verify formula's config.json` - // NewResolver creates a credential resolver instance of Resolver interface -func NewResolver(cf credential.Finder) CredentialResolver { - return CredentialResolver{cf} +func NewResolver(cf credential.Finder, cs credential.Setter) CredentialResolver { + return CredentialResolver{cf, cs} } -func (c CredentialResolver) Resolve(name string) (string, error) { - s := strings.Split(name, "_") - service := strings.ToLower(s[1]) +func (c CredentialResolver) Resolve(name string, passwordInput prompt.InputPassword) (string, error) { + s := strings.Split(strings.ToLower(name), "_") + service := s[1] + key := s[2] cred, err := c.Find(service) + if err != nil { + // Provider was never set + cred.Service = service + return c.PromptCredential(service, key, cred, passwordInput) + } + credValue, exists := cred.Credential[key] + if !exists { + // Provider exists but the expected key doesn't + return c.PromptCredential(service, key, cred, passwordInput) + } + + // Provider and key exist + return credValue, nil +} + +func (c CredentialResolver) PromptCredential( + provider string, + key string, + credentialDetail credential.Detail, + passwordInput prompt.InputPassword, +) (string, error) { + inputVal, err := passwordInput.Password( + fmt.Sprintf("Provider key not found, please provide a value for %s %s: ", provider, key), + ) if err != nil { return "", err } - k := strings.ToLower(s[2]) - credValue, exist := cred.Credential[k] - if !exist { - errMsg := fmt.Sprintf(errKeyNotFoundTemplate, service, strings.ToUpper(name)) - return "", errors.New(prompt.Red(errMsg)) + credentialDetail.Credential[key] = inputVal + + if err := c.Set(credentialDetail); err != nil { + return "", err } - return credValue, nil + + return inputVal, nil } diff --git a/pkg/env/envcredential/env_credential_test.go b/pkg/env/envcredential/env_credential_test.go new file mode 100644 index 000000000..d8396230e --- /dev/null +++ b/pkg/env/envcredential/env_credential_test.go @@ -0,0 +1,81 @@ +/* + * Copyright 2020 ZUP IT SERVICOS EM TECNOLOGIA E INOVACAO SA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package envcredential + +import ( + "os" + "testing" + + "github.com/ZupIT/ritchie-cli/pkg/credential" + "github.com/ZupIT/ritchie-cli/pkg/rcontext" + "github.com/ZupIT/ritchie-cli/pkg/stream" +) + +func TestCredentialResolver(t *testing.T) { + tempDirectory := os.TempDir() + defer os.Remove(tempDirectory) + + var tests = []struct { + name string + credentialField string + output string + }{ + { + name: "Test resolve new provider", + credentialField: "CREDENTIAL_PROVIDER_KEY", + output: "key", + }, + { + name: "Test resolve new key", + credentialField: "CREDENTIAL_PROVIDER_KEY2", + output: "key2", + }, + { + name: "Test resolve existing key", + credentialField: "CREDENTIAL_PROVIDER_KEY2", + output: "key2", + }, + } + + fileManager := stream.NewFileManager() + contextFinder := rcontext.NewFinder(tempDirectory, fileManager) + credentialSetter := credential.NewSetter(tempDirectory, contextFinder) + credentialFinder := credential.NewFinder(tempDirectory, contextFinder, fileManager) + credentialResolver := NewResolver(credentialFinder, credentialSetter) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + password := passwordMock{tt.output} + credentialValue, err := credentialResolver.Resolve(tt.credentialField, password) + if err != nil { + t.Errorf("Resolve credentials error = %v", err) + } + if credentialValue != tt.output { + t.Errorf("Resolve credentials failed to retrieve. Expected %v, got %v", tt.output, credentialValue) + } + + }) + } +} + +type passwordMock struct { + value string +} + +func (pass passwordMock) Password(string) (string, error) { + return pass.value, nil +} diff --git a/pkg/formula/runner/inputs.go b/pkg/formula/runner/inputs.go index d8537069b..07cebaabe 100644 --- a/pkg/formula/runner/inputs.go +++ b/pkg/formula/runner/inputs.go @@ -242,7 +242,7 @@ func (in InputManager) resolveIfReserved(input formula.Input) (string, error) { s := strings.Split(input.Type, "_") resolver := in.envResolvers[s[0]] if resolver != nil { - return resolver.Resolve(input.Type) + return resolver.Resolve(input.Type, prompt.NewSurveyPassword()) } return "", nil } From 34c161d8f530f5d79cc89ac3754b5323c27834cf Mon Sep 17 00:00:00 2001 From: Henrique Moraes Date: Wed, 12 Aug 2020 22:00:06 -0300 Subject: [PATCH 2/6] Fixing linter Signed-off-by: Henrique Moraes --- cmd/main.go | 2 +- pkg/env/env.go | 4 +--- pkg/env/envcredential/env_credential.go | 14 +++++++------- pkg/env/envcredential/env_credential_test.go | 5 ++--- pkg/formula/runner/inputs.go | 2 +- 5 files changed, 12 insertions(+), 15 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index fee684fc3..709cf8564 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -110,7 +110,7 @@ func buildCommands() *cobra.Command { treeManager := tree.NewTreeManager(ritchieHomeDir, repoLister, api.CoreCmds) credSettings := credential.NewSettings(fileManager, dirManager, userHomeDir) autocompleteGen := autocomplete.NewGenerator(treeManager) - credResolver := envcredential.NewResolver(credFinder, credSetter) + credResolver := envcredential.NewResolver(credFinder, credSetter, inputPassword) envResolvers := make(env.Resolvers) envResolvers[env.Credential] = credResolver tutorialFinder := rtutorial.NewFinder(ritchieHomeDir, fileManager) diff --git a/pkg/env/env.go b/pkg/env/env.go index 19b6df8f6..993c12aa0 100644 --- a/pkg/env/env.go +++ b/pkg/env/env.go @@ -16,8 +16,6 @@ package env -import "github.com/ZupIT/ritchie-cli/pkg/prompt" - const ( // Credential resolver Credential = "CREDENTIAL" @@ -27,5 +25,5 @@ type Resolvers map[string]Resolver // Resolver is an interface that we can use to resolve reserved envs type Resolver interface { - Resolve(name string, password prompt.InputPassword) (string, error) + Resolve(name string) (string, error) } diff --git a/pkg/env/envcredential/env_credential.go b/pkg/env/envcredential/env_credential.go index cc49a4761..c538b3bcd 100644 --- a/pkg/env/envcredential/env_credential.go +++ b/pkg/env/envcredential/env_credential.go @@ -27,14 +27,15 @@ import ( type CredentialResolver struct { credential.Finder credential.Setter + prompt.InputPassword } // NewResolver creates a credential resolver instance of Resolver interface -func NewResolver(cf credential.Finder, cs credential.Setter) CredentialResolver { - return CredentialResolver{cf, cs} +func NewResolver(cf credential.Finder, cs credential.Setter, passwordInput prompt.InputPassword) CredentialResolver { + return CredentialResolver{cf, cs, passwordInput} } -func (c CredentialResolver) Resolve(name string, passwordInput prompt.InputPassword) (string, error) { +func (c CredentialResolver) Resolve(name string) (string, error) { s := strings.Split(strings.ToLower(name), "_") service := s[1] key := s[2] @@ -42,12 +43,12 @@ func (c CredentialResolver) Resolve(name string, passwordInput prompt.InputPassw if err != nil { // Provider was never set cred.Service = service - return c.PromptCredential(service, key, cred, passwordInput) + return c.PromptCredential(service, key, cred) } credValue, exists := cred.Credential[key] if !exists { // Provider exists but the expected key doesn't - return c.PromptCredential(service, key, cred, passwordInput) + return c.PromptCredential(service, key, cred) } // Provider and key exist @@ -58,9 +59,8 @@ func (c CredentialResolver) PromptCredential( provider string, key string, credentialDetail credential.Detail, - passwordInput prompt.InputPassword, ) (string, error) { - inputVal, err := passwordInput.Password( + inputVal, err := c.Password( fmt.Sprintf("Provider key not found, please provide a value for %s %s: ", provider, key), ) if err != nil { diff --git a/pkg/env/envcredential/env_credential_test.go b/pkg/env/envcredential/env_credential_test.go index d8396230e..3e9b623bc 100644 --- a/pkg/env/envcredential/env_credential_test.go +++ b/pkg/env/envcredential/env_credential_test.go @@ -55,12 +55,11 @@ func TestCredentialResolver(t *testing.T) { contextFinder := rcontext.NewFinder(tempDirectory, fileManager) credentialSetter := credential.NewSetter(tempDirectory, contextFinder) credentialFinder := credential.NewFinder(tempDirectory, contextFinder, fileManager) - credentialResolver := NewResolver(credentialFinder, credentialSetter) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - password := passwordMock{tt.output} - credentialValue, err := credentialResolver.Resolve(tt.credentialField, password) + credentialResolver := NewResolver(credentialFinder, credentialSetter, passwordMock{tt.output}) + credentialValue, err := credentialResolver.Resolve(tt.credentialField) if err != nil { t.Errorf("Resolve credentials error = %v", err) } diff --git a/pkg/formula/runner/inputs.go b/pkg/formula/runner/inputs.go index 07cebaabe..d8537069b 100644 --- a/pkg/formula/runner/inputs.go +++ b/pkg/formula/runner/inputs.go @@ -242,7 +242,7 @@ func (in InputManager) resolveIfReserved(input formula.Input) (string, error) { s := strings.Split(input.Type, "_") resolver := in.envResolvers[s[0]] if resolver != nil { - return resolver.Resolve(input.Type, prompt.NewSurveyPassword()) + return resolver.Resolve(input.Type) } return "", nil } From 64899026060226aabd8a55483108e16c31c1a310 Mon Sep 17 00:00:00 2001 From: Henrique Moraes Date: Wed, 12 Aug 2020 22:12:42 -0300 Subject: [PATCH 3/6] Fixing unit test Signed-off-by: Henrique Moraes --- pkg/credential/finder_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/credential/finder_test.go b/pkg/credential/finder_test.go index be861d917..a9fb628cc 100644 --- a/pkg/credential/finder_test.go +++ b/pkg/credential/finder_test.go @@ -74,7 +74,7 @@ func TestFind(t *testing.T) { provider: "aws", }, out: out{ - cred: Detail{}, + cred: Detail{Credential: Credential{}}, err: errors.New(prompt.Red(fmt.Sprintf(errNotFoundTemplate, "aws"))), }, }, From 99e46291cfb2452e0ba8b7e55adbb08f933fbe67 Mon Sep 17 00:00:00 2001 From: Henrique Moraes Date: Fri, 14 Aug 2020 10:34:48 -0300 Subject: [PATCH 4/6] Fixing parameters Signed-off-by: Henrique Moraes --- pkg/env/envcredential/env_credential.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pkg/env/envcredential/env_credential.go b/pkg/env/envcredential/env_credential.go index c538b3bcd..91a8e1b05 100644 --- a/pkg/env/envcredential/env_credential.go +++ b/pkg/env/envcredential/env_credential.go @@ -55,11 +55,7 @@ func (c CredentialResolver) Resolve(name string) (string, error) { return credValue, nil } -func (c CredentialResolver) PromptCredential( - provider string, - key string, - credentialDetail credential.Detail, -) (string, error) { +func (c CredentialResolver) PromptCredential(provider, key string, credentialDetail credential.Detail) (string, error) { inputVal, err := c.Password( fmt.Sprintf("Provider key not found, please provide a value for %s %s: ", provider, key), ) From fd3dd1275b51db641af38685384d5d982dc90472 Mon Sep 17 00:00:00 2001 From: Henrique Moraes Date: Tue, 18 Aug 2020 16:32:09 -0300 Subject: [PATCH 5/6] Actually removing test files Signed-off-by: Henrique Moraes Actually removing test files --- pkg/env/envcredential/env_credential_test.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/pkg/env/envcredential/env_credential_test.go b/pkg/env/envcredential/env_credential_test.go index 3e9b623bc..eeb2fe975 100644 --- a/pkg/env/envcredential/env_credential_test.go +++ b/pkg/env/envcredential/env_credential_test.go @@ -26,8 +26,13 @@ import ( ) func TestCredentialResolver(t *testing.T) { + fileManager := stream.NewFileManager() tempDirectory := os.TempDir() - defer os.Remove(tempDirectory) + contextFinder := rcontext.NewFinder(tempDirectory, fileManager) + credentialSetter := credential.NewSetter(tempDirectory, contextFinder) + credentialFinder := credential.NewFinder(tempDirectory, contextFinder, fileManager) + + defer os.RemoveAll(credential.File(tempDirectory, "", "")) var tests = []struct { name string @@ -51,11 +56,6 @@ func TestCredentialResolver(t *testing.T) { }, } - fileManager := stream.NewFileManager() - contextFinder := rcontext.NewFinder(tempDirectory, fileManager) - credentialSetter := credential.NewSetter(tempDirectory, contextFinder) - credentialFinder := credential.NewFinder(tempDirectory, contextFinder, fileManager) - for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { credentialResolver := NewResolver(credentialFinder, credentialSetter, passwordMock{tt.output}) @@ -66,7 +66,6 @@ func TestCredentialResolver(t *testing.T) { if credentialValue != tt.output { t.Errorf("Resolve credentials failed to retrieve. Expected %v, got %v", tt.output, credentialValue) } - }) } } From 244c6e66920968e47032a52e6483f41e90d48ecf Mon Sep 17 00:00:00 2001 From: Henrique Moraes Date: Fri, 21 Aug 2020 11:21:19 -0300 Subject: [PATCH 6/6] Code review Signed-off-by: Henrique Moraes --- pkg/env/envcredential/env_credential.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/pkg/env/envcredential/env_credential.go b/pkg/env/envcredential/env_credential.go index 91a8e1b05..491c42d23 100644 --- a/pkg/env/envcredential/env_credential.go +++ b/pkg/env/envcredential/env_credential.go @@ -37,18 +37,18 @@ func NewResolver(cf credential.Finder, cs credential.Setter, passwordInput promp func (c CredentialResolver) Resolve(name string) (string, error) { s := strings.Split(strings.ToLower(name), "_") - service := s[1] + provider := s[1] key := s[2] - cred, err := c.Find(service) + cred, err := c.Find(provider) if err != nil { // Provider was never set - cred.Service = service - return c.PromptCredential(service, key, cred) + cred.Service = provider + return c.PromptCredential(provider, key, cred) } credValue, exists := cred.Credential[key] if !exists { // Provider exists but the expected key doesn't - return c.PromptCredential(service, key, cred) + return c.PromptCredential(provider, key, cred) } // Provider and key exist @@ -56,9 +56,8 @@ func (c CredentialResolver) Resolve(name string) (string, error) { } func (c CredentialResolver) PromptCredential(provider, key string, credentialDetail credential.Detail) (string, error) { - inputVal, err := c.Password( - fmt.Sprintf("Provider key not found, please provide a value for %s %s: ", provider, key), - ) + message := fmt.Sprintf("Provider key not found, please provide a value for %s %s: ", provider, key) + inputVal, err := c.Password(message) if err != nil { return "", err }