|
|
@@ -0,0 +1,662 @@
|
|
|
+/*
|
|
|
+Copyright © The ESO Authors
|
|
|
+
|
|
|
+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
|
|
|
+
|
|
|
+ https://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 beyondtrustworkloadcredentials
|
|
|
+
|
|
|
+import (
|
|
|
+ "context"
|
|
|
+ "encoding/json"
|
|
|
+ "fmt"
|
|
|
+ "path"
|
|
|
+ "strings"
|
|
|
+ "testing"
|
|
|
+
|
|
|
+ "github.com/google/go-cmp/cmp"
|
|
|
+
|
|
|
+ esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
|
|
|
+ "github.com/external-secrets/external-secrets/providers/v1/beyondtrustworkloadcredentials/fake"
|
|
|
+ btwcutil "github.com/external-secrets/external-secrets/providers/v1/beyondtrustworkloadcredentials/util"
|
|
|
+)
|
|
|
+
|
|
|
+const (
|
|
|
+ validSecretName = "apikey"
|
|
|
+ validFolderPath = "valid/folder/path"
|
|
|
+ invalidSecretName = "INVALID_NAME"
|
|
|
+ invalidFolderPath = "INVALID_PATH"
|
|
|
+)
|
|
|
+
|
|
|
+///////////////////////
|
|
|
+// test case structs //
|
|
|
+///////////////////////
|
|
|
+
|
|
|
+type beyondtrustworkloadcredentialsGetSecretTestCase struct {
|
|
|
+ label string
|
|
|
+ fakeBtsecretsClient *fake.BeyondtrustWorkloadCredentialsClient
|
|
|
+ ctx context.Context
|
|
|
+ name *string
|
|
|
+ folderPath *string
|
|
|
+ remoteRef esv1.ExternalSecretDataRemoteRef
|
|
|
+ fakeBtsecretsResponse *btwcutil.KV
|
|
|
+ fakeBtsecretsError *string
|
|
|
+ expectedError *string
|
|
|
+ expectedResponse []byte
|
|
|
+}
|
|
|
+
|
|
|
+type beyondtrustworkloadcredentialsGetAllSecretsTestCase struct {
|
|
|
+ label string
|
|
|
+ fakeBtsecretsClient *fake.BeyondtrustWorkloadCredentialsClient
|
|
|
+ ctx context.Context
|
|
|
+ name *string
|
|
|
+ names []string
|
|
|
+ folderPath *string
|
|
|
+ remoteRef esv1.ExternalSecretFind
|
|
|
+ fakeBtsecretsGetResponse *btwcutil.KV
|
|
|
+ fakeBtsecretsGetResponses []btwcutil.KV
|
|
|
+ fakeBtsecretsListResponse []btwcutil.KVListItem
|
|
|
+ fakeBtsecretsGetError *string
|
|
|
+ fakeBtsecretsListError *string
|
|
|
+ expectedError *string
|
|
|
+ expectedResponse map[string][]byte
|
|
|
+}
|
|
|
+
|
|
|
+////////////
|
|
|
+// makers //
|
|
|
+////////////
|
|
|
+
|
|
|
+// makeValidGetSecretTestCase creates a valid test case for GetSecret tests.
|
|
|
+func makeValidGetSecretTestCase() *beyondtrustworkloadcredentialsGetSecretTestCase {
|
|
|
+ return &beyondtrustworkloadcredentialsGetSecretTestCase{
|
|
|
+ fakeBtsecretsClient: &fake.BeyondtrustWorkloadCredentialsClient{},
|
|
|
+ ctx: context.Background(),
|
|
|
+ name: new(validSecretName),
|
|
|
+ folderPath: new(validFolderPath),
|
|
|
+ remoteRef: esv1.ExternalSecretDataRemoteRef{Key: validSecretName, Property: ""},
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// makeValidGetAllSecretsTestCase creates a valid test case for GetSecrets tests.
|
|
|
+func makeValidGetAllSecretsTestCase() *beyondtrustworkloadcredentialsGetAllSecretsTestCase {
|
|
|
+ return &beyondtrustworkloadcredentialsGetAllSecretsTestCase{
|
|
|
+ fakeBtsecretsClient: &fake.BeyondtrustWorkloadCredentialsClient{},
|
|
|
+ ctx: context.Background(),
|
|
|
+ name: new(validSecretName),
|
|
|
+ folderPath: new(validFolderPath),
|
|
|
+ remoteRef: esv1.ExternalSecretFind{},
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// makeValidGetSecretTestCaseWithValues injects values into the faked BeyondtrustWorkloadCredentialsClient for GetSecret tests.
|
|
|
+func makeValidGetSecretTestCaseWithValues(tweaks ...func(tc *beyondtrustworkloadcredentialsGetSecretTestCase)) *beyondtrustworkloadcredentialsGetSecretTestCase {
|
|
|
+ vtc := makeValidGetSecretTestCase()
|
|
|
+ for _, fn := range tweaks {
|
|
|
+ fn(vtc)
|
|
|
+ }
|
|
|
+
|
|
|
+ vtc.fakeBtsecretsClient.WithValues(vtc.ctx, vtc.name, vtc.folderPath, vtc.fakeBtsecretsResponse, nil, vtc.fakeBtsecretsError, nil)
|
|
|
+
|
|
|
+ return vtc
|
|
|
+}
|
|
|
+
|
|
|
+// makeValidGetAllSecretsTestCaseWithValues injects values into the faked BeyondtrustWorkloadCredentialsClient for GetSecrets tests.
|
|
|
+func makeValidGetAllSecretsTestCaseWithValues(tweaks ...func(tc *beyondtrustworkloadcredentialsGetAllSecretsTestCase)) *beyondtrustworkloadcredentialsGetAllSecretsTestCase {
|
|
|
+ vtc := makeValidGetAllSecretsTestCase()
|
|
|
+ for _, fn := range tweaks {
|
|
|
+ fn(vtc)
|
|
|
+ }
|
|
|
+
|
|
|
+ vtc.fakeBtsecretsClient.WithValues(vtc.ctx, vtc.name, vtc.folderPath, vtc.fakeBtsecretsGetResponse, vtc.fakeBtsecretsListResponse, vtc.fakeBtsecretsGetError, vtc.fakeBtsecretsListError)
|
|
|
+
|
|
|
+ return vtc
|
|
|
+}
|
|
|
+
|
|
|
+// makeValidGetAllSecretsTestCaseWithMultiValues injects values with multiple GET responses into the faked BeyondtrustWorkloadCredentialsClient for GetSecrets tests.
|
|
|
+func makeValidGetAllSecretsTestCaseWithMultiValues(tweaks ...func(tc *beyondtrustworkloadcredentialsGetAllSecretsTestCase)) *beyondtrustworkloadcredentialsGetAllSecretsTestCase {
|
|
|
+ vtc := makeValidGetAllSecretsTestCase()
|
|
|
+ for _, fn := range tweaks {
|
|
|
+ fn(vtc)
|
|
|
+ }
|
|
|
+
|
|
|
+ vtc.fakeBtsecretsClient.WithMultiValues(vtc.ctx, vtc.names, vtc.folderPath, vtc.fakeBtsecretsGetResponses, vtc.fakeBtsecretsListResponse, vtc.fakeBtsecretsGetError, vtc.fakeBtsecretsListError)
|
|
|
+
|
|
|
+ return vtc
|
|
|
+}
|
|
|
+
|
|
|
+///////////
|
|
|
+// tests //
|
|
|
+///////////
|
|
|
+
|
|
|
+func TestGetSecret(t *testing.T) {
|
|
|
+ // happy paths
|
|
|
+
|
|
|
+ validSecret := func(tc *beyondtrustworkloadcredentialsGetSecretTestCase) {
|
|
|
+ fakeKV := &btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s/%s", validFolderPath, validSecretName),
|
|
|
+ Secret: map[string]any{"valid": "test"},
|
|
|
+ }
|
|
|
+
|
|
|
+ fakeKVBytes, err := json.Marshal(fakeKV.Secret)
|
|
|
+ if err != nil {
|
|
|
+ t.Errorf("failed to marshal fake KV: %#v, error: %q", fakeKV, err.Error())
|
|
|
+ }
|
|
|
+
|
|
|
+ tc.label = "GetSecret - Valid"
|
|
|
+ tc.fakeBtsecretsResponse = fakeKV
|
|
|
+ tc.expectedResponse = fakeKVBytes
|
|
|
+ }
|
|
|
+
|
|
|
+ validSecretProperty := func(tc *beyondtrustworkloadcredentialsGetSecretTestCase) {
|
|
|
+ propertyValue := "test"
|
|
|
+
|
|
|
+ fakeKV := &btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s/%s", validFolderPath, validSecretName),
|
|
|
+ Secret: map[string]any{"valid": propertyValue, "doNotInclude": "this"},
|
|
|
+ }
|
|
|
+
|
|
|
+ tc.label = "GetSecret - Valid Property"
|
|
|
+ tc.remoteRef = esv1.ExternalSecretDataRemoteRef{Key: validSecretName, Property: "valid"}
|
|
|
+ tc.fakeBtsecretsResponse = fakeKV
|
|
|
+ tc.expectedResponse = []byte(propertyValue)
|
|
|
+ }
|
|
|
+
|
|
|
+ // sad paths
|
|
|
+
|
|
|
+ clientError := func(tc *beyondtrustworkloadcredentialsGetSecretTestCase) {
|
|
|
+ tc.label = "GetSecret - Client Error"
|
|
|
+ tc.name = new(invalidSecretName)
|
|
|
+ tc.folderPath = new(invalidFolderPath)
|
|
|
+ tc.remoteRef = esv1.ExternalSecretDataRemoteRef{Key: invalidSecretName}
|
|
|
+ tc.fakeBtsecretsError = new("beyondtrustworkloadcredentials error")
|
|
|
+ tc.expectedError = new("failed to get secret")
|
|
|
+ }
|
|
|
+
|
|
|
+ nilSecret := func(tc *beyondtrustworkloadcredentialsGetSecretTestCase) {
|
|
|
+ fakeKV := &btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s/%s", invalidFolderPath, invalidSecretName),
|
|
|
+ }
|
|
|
+
|
|
|
+ tc.label = "GetSecret - Nil Secret"
|
|
|
+ tc.name = new(invalidSecretName)
|
|
|
+ tc.folderPath = new(invalidFolderPath)
|
|
|
+ tc.remoteRef = esv1.ExternalSecretDataRemoteRef{Key: invalidSecretName}
|
|
|
+ tc.fakeBtsecretsResponse = fakeKV
|
|
|
+ tc.expectedError = new("secret value is nil")
|
|
|
+ }
|
|
|
+
|
|
|
+ invalidSecretProperty := func(tc *beyondtrustworkloadcredentialsGetSecretTestCase) {
|
|
|
+ fakeKV := &btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s/%s", invalidFolderPath, invalidSecretName),
|
|
|
+ Secret: map[string]any{"invalid": "test"},
|
|
|
+ }
|
|
|
+
|
|
|
+ ref := esv1.ExternalSecretDataRemoteRef{Key: invalidSecretName, Property: "nonexistant"}
|
|
|
+
|
|
|
+ tc.label = "GetSecret - Invalid Property"
|
|
|
+ tc.name = new(invalidSecretName)
|
|
|
+ tc.folderPath = new(invalidFolderPath)
|
|
|
+ tc.remoteRef = ref
|
|
|
+ tc.fakeBtsecretsResponse = fakeKV
|
|
|
+ tc.expectedError = new(fmt.Sprintf("property %s not found in secret", ref.Property))
|
|
|
+ }
|
|
|
+
|
|
|
+ invalidSecret := func(tc *beyondtrustworkloadcredentialsGetSecretTestCase) {
|
|
|
+ fakeKV := &btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s/%s", invalidFolderPath, invalidSecretName),
|
|
|
+ Secret: map[string]any{"invalid": func() {}},
|
|
|
+ }
|
|
|
+
|
|
|
+ tc.label = "GetSecret - Invalid"
|
|
|
+ tc.name = new(invalidSecretName)
|
|
|
+ tc.folderPath = new(invalidFolderPath)
|
|
|
+ tc.remoteRef = esv1.ExternalSecretDataRemoteRef{Key: invalidSecretName}
|
|
|
+ tc.fakeBtsecretsResponse = fakeKV
|
|
|
+ tc.expectedError = new("failed to marshal secret")
|
|
|
+ }
|
|
|
+
|
|
|
+ testCases := []*beyondtrustworkloadcredentialsGetSecretTestCase{
|
|
|
+ // happy paths
|
|
|
+ makeValidGetSecretTestCaseWithValues(validSecret),
|
|
|
+ makeValidGetSecretTestCaseWithValues(validSecretProperty),
|
|
|
+ // sad paths
|
|
|
+ makeValidGetSecretTestCaseWithValues(clientError),
|
|
|
+ makeValidGetSecretTestCaseWithValues(nilSecret),
|
|
|
+ makeValidGetSecretTestCaseWithValues(invalidSecretProperty),
|
|
|
+ makeValidGetSecretTestCaseWithValues(invalidSecret),
|
|
|
+ }
|
|
|
+
|
|
|
+ c := Client{store: &esv1.BeyondtrustWorkloadCredentialsProvider{}}
|
|
|
+
|
|
|
+ for i, tc := range testCases {
|
|
|
+ t.Run(tc.label, func(t *testing.T) {
|
|
|
+ c.beyondtrustWorkloadCredentialsClient = tc.fakeBtsecretsClient
|
|
|
+ c.store.FolderPath = *tc.folderPath
|
|
|
+
|
|
|
+ out, err := c.GetSecret(context.Background(), tc.remoteRef)
|
|
|
+
|
|
|
+ // assert error
|
|
|
+
|
|
|
+ if tc.expectedError == nil && err != nil {
|
|
|
+ t.Errorf("[%d] unexpected error: expected nil, got %q", i, err.Error())
|
|
|
+ }
|
|
|
+
|
|
|
+ if tc.expectedError != nil && !ErrorContains(err, *tc.expectedError) {
|
|
|
+ t.Errorf("[%d] unexpected error: expected %q, got %q", i, *tc.expectedError, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // assert response
|
|
|
+
|
|
|
+ if tc.expectedResponse == nil && out != nil {
|
|
|
+ t.Errorf("[%d] unexpected response: expected nil, got %#v", i, out)
|
|
|
+ }
|
|
|
+
|
|
|
+ if tc.expectedResponse != nil && !cmp.Equal(out, tc.expectedResponse) {
|
|
|
+ t.Errorf("[%d] unexpected response: expected %#v, got %#v", i, tc.expectedResponse, out)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func ErrorContains(out error, want string) bool {
|
|
|
+ if out == nil {
|
|
|
+ return want == ""
|
|
|
+ }
|
|
|
+ if want == "" {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ return strings.Contains(out.Error(), want)
|
|
|
+}
|
|
|
+
|
|
|
+func TestGetAllSecrets(t *testing.T) {
|
|
|
+ // happy paths
|
|
|
+
|
|
|
+ validSecretKVs := func(tc *beyondtrustworkloadcredentialsGetAllSecretsTestCase) {
|
|
|
+ fakeKV := &btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s/%s", validFolderPath, validSecretName),
|
|
|
+ Secret: map[string]any{"key1": "val1", "key2": "val2", "key3": "val3"},
|
|
|
+ }
|
|
|
+
|
|
|
+ fakeListItem := btwcutil.KVListItem{
|
|
|
+ Path: fakeKV.Path,
|
|
|
+ }
|
|
|
+
|
|
|
+ fakeKVBytes := map[string][]byte{
|
|
|
+ fakeKV.Path + "/key1": []byte("val1"),
|
|
|
+ fakeKV.Path + "/key2": []byte("val2"),
|
|
|
+ fakeKV.Path + "/key3": []byte("val3"),
|
|
|
+ }
|
|
|
+
|
|
|
+ tc.label = "GetAllSecrets - Secret KVs - Valid"
|
|
|
+ tc.remoteRef = esv1.ExternalSecretFind{Path: new(validFolderPath)}
|
|
|
+ tc.fakeBtsecretsListResponse = []btwcutil.KVListItem{fakeListItem}
|
|
|
+ tc.fakeBtsecretsGetResponse = fakeKV
|
|
|
+ tc.expectedResponse = fakeKVBytes
|
|
|
+ }
|
|
|
+
|
|
|
+ validNamedSecrets := func(tc *beyondtrustworkloadcredentialsGetAllSecretsTestCase) {
|
|
|
+ findName := fmt.Sprintf("%s-include", validSecretName)
|
|
|
+
|
|
|
+ fakeKV1 := btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s/%s-fakeKV1", validFolderPath, findName),
|
|
|
+ Secret: map[string]any{"key1": "val1", "key2": "val2", "key3": "val3"},
|
|
|
+ }
|
|
|
+
|
|
|
+ fakeKV2 := btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s/%s", validFolderPath, validSecretName),
|
|
|
+ }
|
|
|
+
|
|
|
+ fakeKV3 := btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s/%s-fakeKV3", validFolderPath, findName),
|
|
|
+ Secret: map[string]any{"key6": "val6"},
|
|
|
+ }
|
|
|
+
|
|
|
+ fakeListItem1 := btwcutil.KVListItem{
|
|
|
+ Path: fakeKV1.Path,
|
|
|
+ }
|
|
|
+
|
|
|
+ fakeListItem2 := btwcutil.KVListItem{
|
|
|
+ Path: fakeKV2.Path,
|
|
|
+ }
|
|
|
+
|
|
|
+ fakeListItem3 := btwcutil.KVListItem{
|
|
|
+ Path: fakeKV3.Path,
|
|
|
+ }
|
|
|
+
|
|
|
+ fakeResponseBytes := map[string][]byte{
|
|
|
+ fakeKV1.Path + "/key1": []byte("val1"),
|
|
|
+ fakeKV1.Path + "/key2": []byte("val2"),
|
|
|
+ fakeKV1.Path + "/key3": []byte("val3"),
|
|
|
+ fakeKV3.Path + "/key6": []byte("val6"),
|
|
|
+ }
|
|
|
+
|
|
|
+ _, name1 := path.Split(fakeListItem1.Path)
|
|
|
+ _, name3 := path.Split(fakeListItem3.Path)
|
|
|
+
|
|
|
+ tc.label = "GetAllSecrets - Secret KVs - Valid Find RegExp"
|
|
|
+ tc.names = []string{name1, name3}
|
|
|
+ tc.remoteRef = esv1.ExternalSecretFind{Name: &esv1.FindName{RegExp: fmt.Sprintf("^%s.*", findName)}}
|
|
|
+ tc.fakeBtsecretsGetResponses = []btwcutil.KV{fakeKV1, fakeKV3}
|
|
|
+ tc.fakeBtsecretsListResponse = []btwcutil.KVListItem{fakeListItem1, fakeListItem2, fakeListItem3}
|
|
|
+ tc.expectedResponse = fakeResponseBytes
|
|
|
+ }
|
|
|
+
|
|
|
+ validAllSecrets := func(tc *beyondtrustworkloadcredentialsGetAllSecretsTestCase) {
|
|
|
+ findPath := fmt.Sprintf("%s/%s-include", validFolderPath, validSecretName)
|
|
|
+
|
|
|
+ fakeKV1 := btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s-fakeKV1", findPath),
|
|
|
+ Secret: map[string]any{"key1": "val1", "key2": "val2", "key3": "val3"},
|
|
|
+ }
|
|
|
+
|
|
|
+ fakeKV2 := btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s/%s", validFolderPath, validSecretName),
|
|
|
+ Secret: map[string]any{"key4": "val4", "key5": "val5"},
|
|
|
+ }
|
|
|
+
|
|
|
+ fakeKV3 := btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s-fakeKV3", findPath),
|
|
|
+ Secret: map[string]any{"key6": "val6"},
|
|
|
+ }
|
|
|
+
|
|
|
+ fakeListItem1 := btwcutil.KVListItem{
|
|
|
+ Path: fmt.Sprintf("%s-fakeKV1", findPath),
|
|
|
+ }
|
|
|
+
|
|
|
+ fakeListItem2 := btwcutil.KVListItem{
|
|
|
+ Path: fmt.Sprintf("%s/%s", validFolderPath, validSecretName),
|
|
|
+ }
|
|
|
+
|
|
|
+ fakeListItem3 := btwcutil.KVListItem{
|
|
|
+ Path: fmt.Sprintf("%s-fakeKV3", findPath),
|
|
|
+ }
|
|
|
+
|
|
|
+ fakeResponseBytes := map[string][]byte{
|
|
|
+ fakeKV1.Path + "/key1": []byte("val1"),
|
|
|
+ fakeKV1.Path + "/key2": []byte("val2"),
|
|
|
+ fakeKV1.Path + "/key3": []byte("val3"),
|
|
|
+ fakeKV2.Path + "/key4": []byte("val4"),
|
|
|
+ fakeKV2.Path + "/key5": []byte("val5"),
|
|
|
+ fakeKV3.Path + "/key6": []byte("val6"),
|
|
|
+ }
|
|
|
+
|
|
|
+ _, name1 := path.Split(fakeListItem1.Path)
|
|
|
+ _, name2 := path.Split(fakeListItem2.Path)
|
|
|
+ _, name3 := path.Split(fakeListItem3.Path)
|
|
|
+
|
|
|
+ tc.label = "GetAllSecrets - List Secrets - Valid"
|
|
|
+ tc.names = []string{name1, name2, name3}
|
|
|
+ tc.fakeBtsecretsGetResponses = []btwcutil.KV{fakeKV1, fakeKV2, fakeKV3}
|
|
|
+ tc.fakeBtsecretsListResponse = []btwcutil.KVListItem{fakeListItem1, fakeListItem2, fakeListItem3}
|
|
|
+ tc.expectedResponse = fakeResponseBytes
|
|
|
+ }
|
|
|
+
|
|
|
+ // sad paths
|
|
|
+
|
|
|
+ clientGetError := func(tc *beyondtrustworkloadcredentialsGetAllSecretsTestCase) {
|
|
|
+ tc.label = "GetAllSecrets - Secret KVs - Client Error"
|
|
|
+ tc.name = new(invalidSecretName)
|
|
|
+ tc.folderPath = new(invalidFolderPath)
|
|
|
+ tc.remoteRef = esv1.ExternalSecretFind{Path: new(invalidFolderPath)}
|
|
|
+ tc.fakeBtsecretsListError = new("beyondtrustworkloadcredentials list error")
|
|
|
+ tc.expectedError = new("failed to list secrets:")
|
|
|
+ }
|
|
|
+
|
|
|
+ nilSecret := func(tc *beyondtrustworkloadcredentialsGetAllSecretsTestCase) {
|
|
|
+ fakeKV := &btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s/%s", invalidFolderPath, invalidSecretName),
|
|
|
+ }
|
|
|
+
|
|
|
+ fakeListItem := btwcutil.KVListItem{
|
|
|
+ Path: fakeKV.Path,
|
|
|
+ }
|
|
|
+
|
|
|
+ tc.label = "GetAllSecrets - Secret KVs - Nil Secret"
|
|
|
+ tc.name = new(invalidSecretName)
|
|
|
+ tc.folderPath = new(invalidFolderPath)
|
|
|
+ tc.remoteRef = esv1.ExternalSecretFind{Path: new(invalidFolderPath)}
|
|
|
+ tc.fakeBtsecretsListResponse = []btwcutil.KVListItem{fakeListItem}
|
|
|
+ tc.fakeBtsecretsGetResponse = fakeKV
|
|
|
+ // Provider now returns NoSecretError when no results are found
|
|
|
+ tc.expectedError = new("Secret does not exist")
|
|
|
+ }
|
|
|
+
|
|
|
+ invalidSecret := func(tc *beyondtrustworkloadcredentialsGetAllSecretsTestCase) {
|
|
|
+ fakeKV := &btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s/%s", invalidFolderPath, invalidSecretName),
|
|
|
+ Secret: map[string]any{"invalid": func() {}},
|
|
|
+ }
|
|
|
+
|
|
|
+ fakeListItem := btwcutil.KVListItem{
|
|
|
+ Path: fakeKV.Path,
|
|
|
+ }
|
|
|
+
|
|
|
+ tc.label = "GetAllSecrets - Secret KVs - Invalid Secret"
|
|
|
+ tc.name = new(invalidSecretName)
|
|
|
+ tc.folderPath = new(invalidFolderPath)
|
|
|
+ tc.remoteRef = esv1.ExternalSecretFind{Path: new(invalidFolderPath)}
|
|
|
+ tc.fakeBtsecretsListResponse = []btwcutil.KVListItem{fakeListItem}
|
|
|
+ tc.fakeBtsecretsGetResponse = fakeKV
|
|
|
+ tc.expectedError = new("failed to marshal secret value for key")
|
|
|
+ }
|
|
|
+
|
|
|
+ clientListError := func(tc *beyondtrustworkloadcredentialsGetAllSecretsTestCase) {
|
|
|
+ tc.label = "GetAllSecrets - List Secrets - Client Error"
|
|
|
+ tc.name = new(invalidSecretName)
|
|
|
+ tc.folderPath = new(invalidFolderPath)
|
|
|
+ tc.fakeBtsecretsListError = new("beyondtrustworkloadcredentials list error")
|
|
|
+ tc.expectedError = new("failed to list secrets:")
|
|
|
+ }
|
|
|
+
|
|
|
+ invalidFindRegex := func(tc *beyondtrustworkloadcredentialsGetAllSecretsTestCase) {
|
|
|
+ tc.label = "GetAllSecrets - List Secrets - Invalid Find RegExp"
|
|
|
+ tc.name = new(invalidSecretName)
|
|
|
+ tc.folderPath = new(invalidFolderPath)
|
|
|
+ tc.remoteRef = esv1.ExternalSecretFind{Name: &esv1.FindName{RegExp: "[invalid-regex"}}
|
|
|
+ tc.expectedError = new("invalid name regexp")
|
|
|
+ }
|
|
|
+
|
|
|
+ clientGetErrorInList := func(tc *beyondtrustworkloadcredentialsGetAllSecretsTestCase) {
|
|
|
+ tc.label = "GetAllSecrets - List Secrets - Get KVs - Client Error"
|
|
|
+ tc.name = new(invalidSecretName)
|
|
|
+ tc.folderPath = new(invalidFolderPath)
|
|
|
+ tc.fakeBtsecretsListResponse = []btwcutil.KVListItem{{}}
|
|
|
+ tc.fakeBtsecretsGetError = new("beyondtrustworkloadcredentials get error in list")
|
|
|
+ tc.expectedError = new("failed to get secret at path")
|
|
|
+ }
|
|
|
+
|
|
|
+ nilSecretInList := func(tc *beyondtrustworkloadcredentialsGetAllSecretsTestCase) {
|
|
|
+ fakeKV := &btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s/%s", invalidFolderPath, invalidSecretName),
|
|
|
+ }
|
|
|
+
|
|
|
+ tc.label = "GetAllSecrets - List Secrets - Get KVs - Nil Secret"
|
|
|
+ tc.name = new(invalidSecretName)
|
|
|
+ tc.folderPath = new(invalidFolderPath)
|
|
|
+ tc.fakeBtsecretsGetResponse = fakeKV
|
|
|
+ tc.fakeBtsecretsListResponse = []btwcutil.KVListItem{{Path: fakeKV.Path}}
|
|
|
+ // In list mode, skip missing entries; when no results are found, return NoSecretError
|
|
|
+ tc.expectedError = new("Secret does not exist")
|
|
|
+ }
|
|
|
+
|
|
|
+ invalidSecretInList := func(tc *beyondtrustworkloadcredentialsGetAllSecretsTestCase) {
|
|
|
+ fakeKV := &btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s/%s", invalidFolderPath, invalidSecretName),
|
|
|
+ Secret: map[string]any{"invalid": func() {}},
|
|
|
+ }
|
|
|
+
|
|
|
+ tc.label = "GetAllSecrets - List Secrets - Get KVs - Invalid"
|
|
|
+ tc.name = new(invalidSecretName)
|
|
|
+ tc.folderPath = new(invalidFolderPath)
|
|
|
+ tc.fakeBtsecretsGetResponse = fakeKV
|
|
|
+ tc.fakeBtsecretsListResponse = []btwcutil.KVListItem{{Path: fakeKV.Path}}
|
|
|
+ tc.expectedError = new("failed to marshal secret value for key")
|
|
|
+ }
|
|
|
+
|
|
|
+ testCases := []*beyondtrustworkloadcredentialsGetAllSecretsTestCase{
|
|
|
+ // happy paths
|
|
|
+ makeValidGetAllSecretsTestCaseWithValues(validSecretKVs),
|
|
|
+ makeValidGetAllSecretsTestCaseWithMultiValues(validNamedSecrets),
|
|
|
+ makeValidGetAllSecretsTestCaseWithMultiValues(validAllSecrets),
|
|
|
+ // sad paths
|
|
|
+ makeValidGetAllSecretsTestCaseWithValues(clientGetError),
|
|
|
+ makeValidGetAllSecretsTestCaseWithValues(nilSecret),
|
|
|
+ makeValidGetAllSecretsTestCaseWithValues(invalidSecret),
|
|
|
+ makeValidGetAllSecretsTestCaseWithValues(clientListError),
|
|
|
+ makeValidGetAllSecretsTestCaseWithValues(invalidFindRegex),
|
|
|
+ makeValidGetAllSecretsTestCaseWithValues(clientGetErrorInList),
|
|
|
+ makeValidGetAllSecretsTestCaseWithValues(nilSecretInList),
|
|
|
+ makeValidGetAllSecretsTestCaseWithValues(invalidSecretInList),
|
|
|
+ }
|
|
|
+
|
|
|
+ c := Client{store: &esv1.BeyondtrustWorkloadCredentialsProvider{}}
|
|
|
+
|
|
|
+ for i, tc := range testCases {
|
|
|
+ t.Run(tc.label, func(t *testing.T) {
|
|
|
+ c.beyondtrustWorkloadCredentialsClient = tc.fakeBtsecretsClient
|
|
|
+ c.store.FolderPath = *tc.folderPath
|
|
|
+
|
|
|
+ out, err := c.GetAllSecrets(context.Background(), tc.remoteRef)
|
|
|
+
|
|
|
+ // assert error
|
|
|
+
|
|
|
+ if tc.expectedError == nil && err != nil {
|
|
|
+ t.Errorf("[%d] unexpected error: expected nil, got %q", i, err.Error())
|
|
|
+ }
|
|
|
+
|
|
|
+ if tc.expectedError != nil && !ErrorContains(err, *tc.expectedError) {
|
|
|
+ t.Errorf("[%d] unexpected error: expected %q, got %q", i, *tc.expectedError, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // assert response
|
|
|
+
|
|
|
+ if tc.expectedResponse == nil && out != nil {
|
|
|
+ t.Errorf("[%d] unexpected response: expected nil, got %#v", i, out)
|
|
|
+ }
|
|
|
+
|
|
|
+ if tc.expectedResponse != nil && !cmp.Equal(out, tc.expectedResponse) {
|
|
|
+ t.Errorf("[%d] unexpected response: expected %#v, got %#v", i, tc.expectedResponse, out)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func TestGetSecretMap(t *testing.T) {
|
|
|
+ // happy paths
|
|
|
+
|
|
|
+ validSecretMap := func(tc *beyondtrustworkloadcredentialsGetSecretTestCase) {
|
|
|
+ fakeKV := &btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s/%s", validFolderPath, validSecretName),
|
|
|
+ Secret: map[string]any{"username": "admin", "password": "secret123", "port": 5432},
|
|
|
+ }
|
|
|
+
|
|
|
+ tc.label = "GetSecretMap - Valid"
|
|
|
+ tc.fakeBtsecretsResponse = fakeKV
|
|
|
+ // For GetSecretMap tests, we use a map comparison, not a single byte response
|
|
|
+ // This test will use a custom comparison below
|
|
|
+ }
|
|
|
+
|
|
|
+ validSecretMapWithTypes := func(tc *beyondtrustworkloadcredentialsGetSecretTestCase) {
|
|
|
+ fakeKV := &btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s/%s", validFolderPath, validSecretName),
|
|
|
+ Secret: map[string]any{
|
|
|
+ "username": "admin",
|
|
|
+ "config": map[string]string{"env": "prod", "region": "us-east-1"},
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ tc.label = "GetSecretMap - Valid With Complex Types"
|
|
|
+ tc.fakeBtsecretsResponse = fakeKV
|
|
|
+ }
|
|
|
+
|
|
|
+ // sad paths
|
|
|
+
|
|
|
+ clientError := func(tc *beyondtrustworkloadcredentialsGetSecretTestCase) {
|
|
|
+ tc.label = "GetSecretMap - Client Error"
|
|
|
+ tc.name = new(invalidSecretName)
|
|
|
+ tc.folderPath = new(invalidFolderPath)
|
|
|
+ tc.remoteRef = esv1.ExternalSecretDataRemoteRef{Key: invalidSecretName}
|
|
|
+ tc.fakeBtsecretsError = new("beyondtrustworkloadcredentials error")
|
|
|
+ tc.expectedError = new("failed to get secret")
|
|
|
+ }
|
|
|
+
|
|
|
+ nilSecret := func(tc *beyondtrustworkloadcredentialsGetSecretTestCase) {
|
|
|
+ fakeKV := &btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s/%s", invalidFolderPath, invalidSecretName),
|
|
|
+ }
|
|
|
+
|
|
|
+ tc.label = "GetSecretMap - Nil Secret"
|
|
|
+ tc.name = new(invalidSecretName)
|
|
|
+ tc.folderPath = new(invalidFolderPath)
|
|
|
+ tc.remoteRef = esv1.ExternalSecretDataRemoteRef{Key: invalidSecretName}
|
|
|
+ tc.fakeBtsecretsResponse = fakeKV
|
|
|
+ tc.expectedError = new("secret value is nil")
|
|
|
+ }
|
|
|
+
|
|
|
+ invalidSecret := func(tc *beyondtrustworkloadcredentialsGetSecretTestCase) {
|
|
|
+ fakeKV := &btwcutil.KV{
|
|
|
+ Path: fmt.Sprintf("%s/%s", invalidFolderPath, invalidSecretName),
|
|
|
+ Secret: map[string]any{
|
|
|
+ "valid": "test",
|
|
|
+ "invalid": func() {}, // Unmarshalable type
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ tc.label = "GetSecretMap - Invalid"
|
|
|
+ tc.name = new(invalidSecretName)
|
|
|
+ tc.folderPath = new(invalidFolderPath)
|
|
|
+ tc.remoteRef = esv1.ExternalSecretDataRemoteRef{Key: invalidSecretName}
|
|
|
+ tc.fakeBtsecretsResponse = fakeKV
|
|
|
+ tc.expectedError = new("failed to marshal secret value for key")
|
|
|
+ }
|
|
|
+
|
|
|
+ testCases := []*beyondtrustworkloadcredentialsGetSecretTestCase{
|
|
|
+ // happy paths
|
|
|
+ makeValidGetSecretTestCaseWithValues(validSecretMap),
|
|
|
+ makeValidGetSecretTestCaseWithValues(validSecretMapWithTypes),
|
|
|
+ // sad paths
|
|
|
+ makeValidGetSecretTestCaseWithValues(clientError),
|
|
|
+ makeValidGetSecretTestCaseWithValues(nilSecret),
|
|
|
+ makeValidGetSecretTestCaseWithValues(invalidSecret),
|
|
|
+ }
|
|
|
+
|
|
|
+ c := Client{store: &esv1.BeyondtrustWorkloadCredentialsProvider{}}
|
|
|
+
|
|
|
+ for i, tc := range testCases {
|
|
|
+ t.Run(tc.label, func(t *testing.T) {
|
|
|
+ c.beyondtrustWorkloadCredentialsClient = tc.fakeBtsecretsClient
|
|
|
+ c.store.FolderPath = *tc.folderPath
|
|
|
+
|
|
|
+ out, err := c.GetSecretMap(context.Background(), tc.remoteRef)
|
|
|
+
|
|
|
+ // assert error
|
|
|
+ if tc.expectedError == nil && err != nil {
|
|
|
+ t.Errorf("[%d] unexpected error: expected nil, got %q", i, err.Error())
|
|
|
+ }
|
|
|
+
|
|
|
+ if tc.expectedError != nil && !ErrorContains(err, *tc.expectedError) {
|
|
|
+ t.Errorf("[%d] unexpected error: expected %q, got %q", i, *tc.expectedError, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ // For happy path tests with complex types, just verify no error and non-nil response
|
|
|
+ if i < 2 && tc.expectedError == nil {
|
|
|
+ if out == nil {
|
|
|
+ t.Errorf("[%d] unexpected response: expected non-nil map, got nil", i)
|
|
|
+ }
|
|
|
+ if len(out) == 0 {
|
|
|
+ t.Errorf("[%d] unexpected response: expected non-empty map, got empty", i)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|