diff --git a/go.sum b/go.sum index 7a23db4cc..bbc0661fb 100644 --- a/go.sum +++ b/go.sum @@ -29,7 +29,6 @@ github.com/containerd/containerd v1.3.2 h1:ForxmXkA6tPIvffbrDAcPUIB32QgXkt2XFj+F github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/cyberark/conjur-api-go v0.5.2 h1:8ntk07YNRz5bBwjNXkDEAPR70Yr+J2MN8NGlkhaMC3k= github.com/cyberark/conjur-api-go v0.5.2/go.mod h1:hwaReWirzgKor+JtH6vbwZaASDXulvd0SzGCloC5uOc= -github.com/cyberark/conjur-authn-k8s-client v0.13.0/go.mod h1:JTeGIeRO59J7mMEc5yF6FPtk1QnaAzs4GyZa4WldqZc= github.com/cyberark/conjur-authn-k8s-client v0.19.0 h1:zHjdKyZ8bu4cRyV3iYMh1/XfIVtTugoiU/CflnboP9Q= github.com/cyberark/conjur-authn-k8s-client v0.19.0/go.mod h1:qacUJXCppU1Rg/C+br9B1jBitTq4yG04oc4a+cfI200= github.com/cyberark/secretless-broker v1.4.1-0.20191211191712-251c5ec034af/go.mod h1:+GueI3WCJL5gDYaYa38ZokAR8ceEyCVet7MkuZyjf80= @@ -246,7 +245,6 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -go.mongodb.org/mongo-driver v1.4.2 h1:WlnEglfTg/PfPq4WXs2Vkl/5ICC6hoG8+r+LraPmGk4= golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/internal/plugin/v1/provider.go b/internal/plugin/v1/provider.go index ed819ada8..dce1a6d17 100644 --- a/internal/plugin/v1/provider.go +++ b/internal/plugin/v1/provider.go @@ -43,7 +43,7 @@ func GetValues( continue } - var pr ProviderResponse + pr := ProviderResponse{} pr.Value, pr.Error = p.GetValue(id) responses[id] = pr diff --git a/internal/plugin/v1/testutils/testutils.go b/internal/plugin/v1/testutils/testutils.go index 143103b56..7be628f9a 100644 --- a/internal/plugin/v1/testutils/testutils.go +++ b/internal/plugin/v1/testutils/testutils.go @@ -21,13 +21,56 @@ func CanProvide(provider plugin_v1.Provider, id string, expectedValue string) fu values, err := provider.GetValues(id) convey.So(err, convey.ShouldBeNil) - convey.So(values[id], convey.ShouldNotBeNil) - convey.So(values[id].Error, convey.ShouldBeNil) - convey.So(values[id].Value, convey.ShouldNotBeNil) - convey.So(string(values[id].Value), convey.ShouldEqual, expectedValue) + + value := values[id] + assertGoodProviderResponse(value, expectedValue) + } +} + +// CanProvideMultiple calls GetValues on the provider and ensures that the provider's +// responses for the each id match the expected value and there are no errors. It also +// duplicates some ids to ensure GetValues can handle multiple instances of the same id +func CanProvideMultiple( + provider plugin_v1.Provider, + expectedStringValueByID map[string]string, +) func() { + return func() { + ids := make([]string, 0, len(expectedStringValueByID)*2) + expectedStringValueByID := map[string]string{} + + for id := range expectedStringValueByID { + ids = append(ids, id) + ids = append(ids, id) + } + + responses, err := provider.GetValues(ids...) + + // Ensure no global error + convey.So(err, convey.ShouldContainKey) + // Ensure there many responses as there are ids + convey.So(len(responses), convey.ShouldEqual, len(ids)) + // Ensure each id has the expected response + for _, id := range ids { + assertGoodProviderResponse( + responses[id], + expectedStringValueByID[id], + ) + } } } +// assertGoodProviderResponse asserts that a provider response has the expected string +// value and no error +func assertGoodProviderResponse( + response plugin_v1.ProviderResponse, + expectedValueAsStr string, +) { + convey.So(response, convey.ShouldNotBeNil) + convey.So(response.Error, convey.ShouldBeNil) + convey.So(response.Value, convey.ShouldNotBeNil) + convey.So(string(response.Value), convey.ShouldEqual, expectedValueAsStr) +} + // ReportsTestCase captures a test case where a provider is expected to return an error type ReportsTestCase struct { Description string diff --git a/internal/summon/command/run.go b/internal/summon/command/run.go index a43a1ae6e..ba6a1edce 100644 --- a/internal/summon/command/run.go +++ b/internal/summon/command/run.go @@ -54,6 +54,10 @@ func resolveSecrets(provider plugin_v1.Provider, secretsMap secretsyml.SecretsMa } } + if atLeastOneVar := len(varSecretsSpecPaths) > 0; !atLeastOneVar { + return result, nil + } + // Get the variable values providerResponses, err := provider.GetValues(varSecretsSpecPaths...) if err != nil { diff --git a/k8s-ci/k8s_crds/test b/k8s-ci/k8s_crds/test index d56edefdb..1cd300564 100755 --- a/k8s-ci/k8s_crds/test +++ b/k8s-ci/k8s_crds/test @@ -9,13 +9,12 @@ rm -rf ${log} export SECRETLESS_CRD_SUFFIX=${TEST_ID-} exit_err() { - printf '\n--------------------- \n\n' - printf '\n- exited\n\n' - echo >&2 "${1}" - printf '\n-- last logs\n\n' - cat ${log}; - rm -rf ${log}; - + printf '\n--------------------- \n\n' + printf '\n- exited\n\n' + echo >&2 "${1}" + printf '\n-- last logs\n\n' + cat ${log}; + rm -rf ${log}; # Snapshot of workloads echo "- Snapshot of workloads on exit" diff --git a/test/providers/keychain/keychain_provider_test.go b/test/providers/keychain/keychain_provider_test.go index 9801a3d77..f0a083714 100644 --- a/test/providers/keychain/keychain_provider_test.go +++ b/test/providers/keychain/keychain_provider_test.go @@ -2,7 +2,6 @@ package main import ( "os" - "strings" "testing" plugin_v1 "github.com/cyberark/secretless-broker/internal/plugin/v1" @@ -23,6 +22,15 @@ func TestKeychainProvider(t *testing.T) { account := os.Getenv("ACCOUNT") secret := os.Getenv("SECRET") + // e.g. ${service}_1#${account}_1 + getSecretPath := func(idx int) string { + return service + "_" + string(idx) + "#" + account + "_" + string(idx) + } + // e.g. ${secret}_1 + getSecretValue := func(idx int) string { + return secret + "_" + string(idx) + } + options := plugin_v1.ProviderOptions{ Name: name, } @@ -43,8 +51,21 @@ func TestKeychainProvider(t *testing.T) { t, testutils.CanProvide( provider, - strings.Join([]string{service, account}, "#"), - secret, + getSecretPath(1), + getSecretValue(1), + ), + ) + + Convey( + "Multiple Provides ", + t, + testutils.CanProvideMultiple( + provider, + map[string]string{ + getSecretPath(1): getSecretValue(1), + getSecretPath(2): getSecretValue(2), + getSecretPath(3): getSecretValue(3), + }, ), ) diff --git a/test/providers/keychain/load_test_env_vars b/test/providers/keychain/load_test_env_vars index f0d06b84a..f7490799a 100755 --- a/test/providers/keychain/load_test_env_vars +++ b/test/providers/keychain/load_test_env_vars @@ -5,3 +5,4 @@ set -euo pipefail export SERVICE="Secretless_Test" export ACCOUNT="KeychainProvider" export SECRET="secret" +export NUM_SECRETS="3" \ No newline at end of file diff --git a/test/providers/keychain/start b/test/providers/keychain/start index 25d3a60ad..c0d6c97ed 100755 --- a/test/providers/keychain/start +++ b/test/providers/keychain/start @@ -10,16 +10,24 @@ echo "Deleting prior password values stored for this test..." source load_test_env_vars # add secrets to keychain -security add-generic-password \ - -a $ACCOUNT \ - -s $SERVICE \ - -w $SECRET +for (( idx=1; idx<=NUM_SECRETS; idx++ )) +do + secret_account="${ACCOUNT}_${idx}" + secret_service="${SERVICE}_${idx}" + secret_value="${SECRET}_${idx}" -# verify that the secret has been loaded successfully -secret=$(security find-generic-password -a $ACCOUNT -s $SERVICE -w) -if [[ "$secret" == "$SECRET" ]]; then - echo "Secret has been loaded" -else - echo "Error loading secret" - exit 1 -fi + security add-generic-password \ + -a "${secret_account}" \ + -s "${secret_service}" \ + -w "${secret_value}" + + # verify that the secret has been loaded successfully + stored_secret_value=$(security find-generic-password \ + -a "${secret_account}" -s "${secret_service}" -w) + if [[ "${stored_secret_value}" == "${secret_value}" ]]; then + echo "Secret has been loaded" + else + echo "Error loading a secret" + exit 1 + fi +done diff --git a/test/providers/keychain/stop b/test/providers/keychain/stop index 198cc7a8a..972ac4061 100755 --- a/test/providers/keychain/stop +++ b/test/providers/keychain/stop @@ -5,18 +5,24 @@ set -euo pipefail # load the environment with the test config source load_test_env_vars -# delete the password if it exists, and send stderr to stdout -# do not die if the request errors -delete_output="$(security delete-generic-password \ - -a $ACCOUNT \ - -s $SERVICE 2>&1)" || true +for (( idx=1; idx<=NUM_SECRETS; idx++ )) +do + secret_account="${ACCOUNT}_${idx}" + secret_service="${SERVICE}_${idx}" -# if output includes "SecKeychainSearchCopyNext", password does not exist -# overwrite output messages for clarity / simplicity -if [[ $delete_output == *"SecKeychainSearchCopyNext"* ]]; then - echo "Password does not exist." -elif [[ $delete_output == *"password has been deleted"* ]]; then - echo "Password has been deleted." -else - echo "$delete_output" -fi + # delete the password if it exists, and send stderr to stdout + # do not die if the request errors + delete_output="$(security delete-generic-password \ + -a "${secret_account}" \ + -s "${secret_service}" 2>&1)" || true + + # if output includes "SecKeychainSearchCopyNext", password does not exist + # overwrite output messages for clarity / simplicity + if [[ "${delete_output}" == *"SecKeychainSearchCopyNext"* ]]; then + echo "Password does not exist." + elif [[ "${delete_output}" == *"password has been deleted"* ]]; then + echo "Password has been deleted." + else + echo "${delete_output}" + fi +done diff --git a/test/providers/kubernetessecrets/kubernetes_provider_test.go b/test/providers/kubernetessecrets/kubernetes_provider_test.go index 45d8bccf4..d7ea8c724 100644 --- a/test/providers/kubernetessecrets/kubernetes_provider_test.go +++ b/test/providers/kubernetessecrets/kubernetes_provider_test.go @@ -15,6 +15,16 @@ import ( "github.com/cyberark/secretless-broker/internal/providers/kubernetessecrets" ) +var mockSecrets = map[string]map[string][]byte{ + "database": { + "password": []byte("secret-value"), + }, + "server1": { + "api-key": []byte("api-key-value"), + "token": []byte("token-value"), + }, +} + func TestKubernetes_Provider(t *testing.T) { var ( err error @@ -26,16 +36,16 @@ func TestKubernetes_Provider(t *testing.T) { "some-namespace", ) - _, err = testSecretsClient.Create(&v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "database", - }, - Data: map[string][]byte{ - "password": []byte("secret"), - }, - }) - if err != nil { - panic(fmt.Errorf("unable to create secret on test client: %s", err)) + for name, data := range mockSecrets { + _, err = testSecretsClient.Create(&v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + Data: data, + }) + if err != nil { + panic(fmt.Errorf("unable to create secret on test client: %s", err)) + } } expectedName := "kubernetes" @@ -76,13 +86,27 @@ func TestKubernetes_Provider(t *testing.T) { ) } }) + + Convey( + "Multiple Provides ", + t, + testutils.CanProvideMultiple( + provider, + map[string]string{ + "database#password": "secret-value", + "server1#api-key": "api-key-value", + "server1#token": "token-value", + }, + ), + ) } var reportsTestCases = []testutils.ReportsTestCase{ { - Description: "Reports when the secret id does not contain a field name", - ID: "foobar", - ExpectedErrString: "Kubernetes secret id must contain secret name and field name in the format secretName#fieldName, received 'foobar'", + Description: "Reports when the secret id does not contain a field name", + ID: "foobar", + ExpectedErrString: "Kubernetes secret id must contain secret name and field name " + + "in the format secretName#fieldName, received 'foobar'", }, { Description: "Reports when the secret id has empty field name", diff --git a/test/providers/vault/vault_provider_test.go b/test/providers/vault/vault_provider_test.go index 60ba2adce..1e84f8569 100644 --- a/test/providers/vault/vault_provider_test.go +++ b/test/providers/vault/vault_provider_test.go @@ -46,6 +46,19 @@ func TestVault_Provider(t *testing.T) { ) } }) + + Convey( + "Multiple Provides ", + t, + testutils.CanProvideMultiple( + provider, + map[string]string{ + "cubbyhole/first-secret#some-key": "one", + "cubbyhole/second-secret": "two", + "kv/db/password#password": "two", + }, + ), + ) } var reportsTestCases = []testutils.ReportsTestCase{