mirror of
https://github.com/external-secrets/external-secrets.git
synced 2024-12-15 17:51:01 +00:00
ed173dcf77
Signed-off-by: Gustavo Carvalho <gusfcarvalho@gmail.com> Signed-off-by: Gustavo Carvalho <gusfcarvalho@gmail.com>
714 lines
24 KiB
Go
714 lines
24 KiB
Go
/*
|
|
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 ibm
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/IBM/go-sdk-core/v5/core"
|
|
sm "github.com/IBM/secrets-manager-go-sdk/secretsmanagerv1"
|
|
corev1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
utilpointer "k8s.io/utils/pointer"
|
|
clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
|
|
|
|
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
|
v1 "github.com/external-secrets/external-secrets/apis/meta/v1"
|
|
fakesm "github.com/external-secrets/external-secrets/pkg/provider/ibm/fake"
|
|
)
|
|
|
|
const (
|
|
errExpectedErr = "wanted error got nil"
|
|
secretKey = "test-secret"
|
|
)
|
|
|
|
type secretManagerTestCase struct {
|
|
mockClient *fakesm.IBMMockClient
|
|
apiInput *sm.GetSecretOptions
|
|
apiOutput *sm.GetSecret
|
|
ref *esv1beta1.ExternalSecretDataRemoteRef
|
|
serviceURL *string
|
|
apiErr error
|
|
expectError string
|
|
expectedSecret string
|
|
// for testing secretmap
|
|
expectedData map[string][]byte
|
|
}
|
|
|
|
func makeValidSecretManagerTestCase() *secretManagerTestCase {
|
|
smtc := secretManagerTestCase{
|
|
mockClient: &fakesm.IBMMockClient{},
|
|
apiInput: makeValidAPIInput(),
|
|
ref: makeValidRef(),
|
|
apiOutput: makeValidAPIOutput(),
|
|
serviceURL: nil,
|
|
apiErr: nil,
|
|
expectError: "",
|
|
expectedSecret: "",
|
|
expectedData: map[string][]byte{},
|
|
}
|
|
smtc.mockClient.WithValue(smtc.apiInput, smtc.apiOutput, smtc.apiErr)
|
|
return &smtc
|
|
}
|
|
|
|
func makeValidRef() *esv1beta1.ExternalSecretDataRemoteRef {
|
|
return &esv1beta1.ExternalSecretDataRemoteRef{
|
|
Key: secretKey,
|
|
Version: "default",
|
|
}
|
|
}
|
|
|
|
func makeValidAPIInput() *sm.GetSecretOptions {
|
|
return &sm.GetSecretOptions{
|
|
SecretType: core.StringPtr(sm.GetSecretOptionsSecretTypeArbitraryConst),
|
|
ID: utilpointer.String(secretKey),
|
|
}
|
|
}
|
|
|
|
func makeValidAPIOutput() *sm.GetSecret {
|
|
secretData := make(map[string]interface{})
|
|
secretData["payload"] = ""
|
|
|
|
return &sm.GetSecret{
|
|
Resources: []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String("testytype"),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretData,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func makeValidSecretManagerTestCaseCustom(tweaks ...func(smtc *secretManagerTestCase)) *secretManagerTestCase {
|
|
smtc := makeValidSecretManagerTestCase()
|
|
for _, fn := range tweaks {
|
|
fn(smtc)
|
|
}
|
|
smtc.mockClient.WithValue(smtc.apiInput, smtc.apiOutput, smtc.apiErr)
|
|
return smtc
|
|
}
|
|
|
|
// This case can be shared by both GetSecret and GetSecretMap tests.
|
|
// bad case: set apiErr.
|
|
var setAPIErr = func(smtc *secretManagerTestCase) {
|
|
smtc.apiErr = fmt.Errorf("oh no")
|
|
smtc.expectError = "oh no"
|
|
}
|
|
|
|
var setNilMockClient = func(smtc *secretManagerTestCase) {
|
|
smtc.mockClient = nil
|
|
smtc.expectError = errUninitalizedIBMProvider
|
|
}
|
|
|
|
// simple tests for Validate Store.
|
|
func TestValidateStore(t *testing.T) {
|
|
p := providerIBM{}
|
|
store := &esv1beta1.SecretStore{
|
|
Spec: esv1beta1.SecretStoreSpec{
|
|
Provider: &esv1beta1.SecretStoreProvider{
|
|
IBM: &esv1beta1.IBMProvider{},
|
|
},
|
|
},
|
|
}
|
|
err := p.ValidateStore(store)
|
|
if err == nil {
|
|
t.Errorf(errExpectedErr)
|
|
} else if err.Error() != "serviceURL is required" {
|
|
t.Errorf("service URL test failed")
|
|
}
|
|
url := "my-url"
|
|
store.Spec.Provider.IBM.ServiceURL = &url
|
|
var nilProfile esv1beta1.IBMAuthContainerAuth
|
|
store.Spec.Provider.IBM.Auth.ContainerAuth = nilProfile
|
|
err = p.ValidateStore(store)
|
|
if err == nil {
|
|
t.Errorf(errExpectedErr)
|
|
} else if err.Error() != "secretAPIKey.name cannot be empty" {
|
|
t.Errorf("KeySelector test failed: expected secret name is required, got %v", err)
|
|
}
|
|
store.Spec.Provider.IBM.Auth.SecretRef.SecretAPIKey.Name = "foo"
|
|
store.Spec.Provider.IBM.Auth.SecretRef.SecretAPIKey.Key = "bar"
|
|
ns := "ns-one"
|
|
store.Spec.Provider.IBM.Auth.SecretRef.SecretAPIKey.Namespace = &ns
|
|
err = p.ValidateStore(store)
|
|
if err == nil {
|
|
t.Errorf(errExpectedErr)
|
|
} else if err.Error() != "namespace not allowed with namespaced SecretStore" {
|
|
t.Errorf("KeySelector test failed: expected namespace not allowed, got %v", err)
|
|
}
|
|
|
|
// add container auth test
|
|
store.Spec.Provider.IBM = &esv1beta1.IBMProvider{}
|
|
store.Spec.Provider.IBM.ServiceURL = &url
|
|
store.Spec.Provider.IBM.Auth.ContainerAuth.Profile = "Trusted IAM Profile"
|
|
store.Spec.Provider.IBM.Auth.ContainerAuth.TokenLocation = "/a/path/to/nowhere/that/should/exist"
|
|
err = p.ValidateStore(store)
|
|
expected := "cannot read container auth token"
|
|
if !ErrorContains(err, expected) {
|
|
t.Errorf("ProfileSelector test failed: %s, expected: '%s'", err.Error(), expected)
|
|
}
|
|
}
|
|
|
|
// test the sm<->gcp interface
|
|
// make sure correct values are passed and errors are handled accordingly.
|
|
func TestIBMSecretManagerGetSecret(t *testing.T) {
|
|
secretData := make(map[string]interface{})
|
|
secretString := "changedvalue"
|
|
secretPassword := "P@ssw0rd"
|
|
secretAPIKey := "01234567890"
|
|
secretCertificate := "certificate_value"
|
|
|
|
secretData["payload"] = secretString
|
|
secretData["password"] = secretPassword
|
|
secretData["certificate"] = secretCertificate
|
|
|
|
// good case: default version is set
|
|
// key is passed in, output is sent back
|
|
setSecretString := func(smtc *secretManagerTestCase) {
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String("testytype"),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretData,
|
|
}}
|
|
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.expectedSecret = secretString
|
|
}
|
|
|
|
// good case: custom version set
|
|
setCustomKey := func(smtc *secretManagerTestCase) {
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String("testytype"),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretData,
|
|
}}
|
|
smtc.ref.Key = "testyname"
|
|
smtc.apiInput.ID = utilpointer.String("testyname")
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.expectedSecret = secretString
|
|
}
|
|
|
|
// bad case: username_password type without property
|
|
secretUserPass := "username_password/test-secret"
|
|
badSecretUserPass := func(smtc *secretManagerTestCase) {
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String(sm.CreateSecretOptionsSecretTypeUsernamePasswordConst),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretData,
|
|
}}
|
|
|
|
smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeUsernamePasswordConst)
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.ref.Key = secretUserPass
|
|
smtc.expectError = "remoteRef.property required for secret type username_password"
|
|
}
|
|
|
|
// good case: username_password type with property
|
|
setSecretUserPass := func(smtc *secretManagerTestCase) {
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String(sm.CreateSecretOptionsSecretTypeUsernamePasswordConst),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretData,
|
|
}}
|
|
|
|
smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeUsernamePasswordConst)
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.ref.Key = secretUserPass
|
|
smtc.ref.Property = "password"
|
|
smtc.expectedSecret = secretPassword
|
|
}
|
|
|
|
// good case: iam_credenatials type
|
|
setSecretIam := func(smtc *secretManagerTestCase) {
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String(sm.CreateSecretOptionsSecretTypeIamCredentialsConst),
|
|
Name: utilpointer.String("testyname"),
|
|
APIKey: utilpointer.String(secretAPIKey),
|
|
}}
|
|
|
|
smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeIamCredentialsConst)
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.ref.Key = "iam_credentials/test-secret"
|
|
smtc.expectedSecret = secretAPIKey
|
|
}
|
|
|
|
funcSetCertSecretTest := func(certType string, good bool) func(*secretManagerTestCase) {
|
|
return func(smtc *secretManagerTestCase) {
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String(certType),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretData,
|
|
}}
|
|
|
|
smtc.apiInput.SecretType = core.StringPtr(certType)
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.ref.Key = certType + "/" + secretKey
|
|
if good {
|
|
smtc.ref.Property = "certificate"
|
|
smtc.expectedSecret = secretCertificate
|
|
} else {
|
|
smtc.expectError = "remoteRef.property required for secret type " + certType
|
|
}
|
|
}
|
|
}
|
|
|
|
// good case: imported_cert type with property
|
|
setSecretCert := funcSetCertSecretTest(sm.CreateSecretOptionsSecretTypeImportedCertConst, true)
|
|
|
|
// bad case: imported_cert type without property
|
|
badSecretCert := funcSetCertSecretTest(sm.CreateSecretOptionsSecretTypeImportedCertConst, false)
|
|
|
|
// good case: public_cert type with property
|
|
setSecretPublicCert := funcSetCertSecretTest(sm.CreateSecretOptionsSecretTypePublicCertConst, true)
|
|
|
|
// bad case: public_cert type without property
|
|
badSecretPublicCert := funcSetCertSecretTest(sm.CreateSecretOptionsSecretTypePublicCertConst, false)
|
|
|
|
// good case: private_cert type with property
|
|
setSecretPrivateCert := funcSetCertSecretTest(sm.CreateSecretOptionsSecretTypePrivateCertConst, true)
|
|
|
|
// bad case: private_cert type without property
|
|
badSecretPrivateCert := funcSetCertSecretTest(sm.CreateSecretOptionsSecretTypePrivateCertConst, false)
|
|
|
|
secretDataKV := make(map[string]interface{})
|
|
secretKVPayload := make(map[string]interface{})
|
|
secretKVPayload["key1"] = "val1"
|
|
secretDataKV["payload"] = secretKVPayload
|
|
|
|
secretDataKVComplex := make(map[string]interface{})
|
|
secretKVComplex := `{"key1":"val1","key2":"val2","key3":"val3","keyC":{"keyC1":"valC1", "keyC2":"valC2"}, "special.log": "file-content"}`
|
|
|
|
secretDataKVComplex["payload"] = secretKVComplex
|
|
|
|
secretKV := "kv/test-secret"
|
|
// bad case: kv type with key which is not in payload
|
|
badSecretKV := func(smtc *secretManagerTestCase) {
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String(sm.CreateSecretOptionsSecretTypeKvConst),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretDataKV,
|
|
}}
|
|
|
|
smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.ref.Key = secretKV
|
|
smtc.ref.Property = "other-key"
|
|
smtc.expectError = "key other-key does not exist in secret kv/test-secret"
|
|
}
|
|
|
|
// good case: kv type with property
|
|
setSecretKV := func(smtc *secretManagerTestCase) {
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String(sm.CreateSecretOptionsSecretTypeKvConst),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretDataKV,
|
|
}}
|
|
|
|
smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.ref.Key = secretKV
|
|
smtc.ref.Property = "key1"
|
|
smtc.expectedSecret = "val1"
|
|
}
|
|
|
|
// good case: kv type with property, returns specific value
|
|
setSecretKVWithKey := func(smtc *secretManagerTestCase) {
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String(sm.CreateSecretOptionsSecretTypeKvConst),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretDataKVComplex,
|
|
}}
|
|
|
|
smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.ref.Key = secretKV
|
|
smtc.ref.Property = "key2"
|
|
smtc.expectedSecret = "val2"
|
|
}
|
|
|
|
// good case: kv type with property and path, returns specific value
|
|
setSecretKVWithKeyPath := func(smtc *secretManagerTestCase) {
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String(sm.CreateSecretOptionsSecretTypeKvConst),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretDataKVComplex,
|
|
}}
|
|
|
|
smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.ref.Key = secretKV
|
|
smtc.ref.Property = "keyC.keyC2"
|
|
smtc.expectedSecret = "valC2"
|
|
}
|
|
|
|
// good case: kv type with property and dot, returns specific value
|
|
setSecretKVWithKeyDot := func(smtc *secretManagerTestCase) {
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String(sm.CreateSecretOptionsSecretTypeKvConst),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretDataKVComplex,
|
|
}}
|
|
|
|
smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.ref.Key = secretKV
|
|
smtc.ref.Property = "special.log"
|
|
smtc.expectedSecret = "file-content"
|
|
}
|
|
|
|
// good case: kv type without property, returns all
|
|
setSecretKVWithOutKey := func(smtc *secretManagerTestCase) {
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String(sm.CreateSecretOptionsSecretTypeKvConst),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretDataKVComplex,
|
|
}}
|
|
|
|
smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.ref.Key = secretKV
|
|
smtc.expectedSecret = secretKVComplex
|
|
}
|
|
|
|
successCases := []*secretManagerTestCase{
|
|
makeValidSecretManagerTestCase(),
|
|
makeValidSecretManagerTestCaseCustom(setSecretString),
|
|
makeValidSecretManagerTestCaseCustom(setCustomKey),
|
|
makeValidSecretManagerTestCaseCustom(setAPIErr),
|
|
makeValidSecretManagerTestCaseCustom(setNilMockClient),
|
|
makeValidSecretManagerTestCaseCustom(badSecretUserPass),
|
|
makeValidSecretManagerTestCaseCustom(setSecretUserPass),
|
|
makeValidSecretManagerTestCaseCustom(setSecretIam),
|
|
makeValidSecretManagerTestCaseCustom(setSecretCert),
|
|
makeValidSecretManagerTestCaseCustom(badSecretCert),
|
|
makeValidSecretManagerTestCaseCustom(setSecretKV),
|
|
makeValidSecretManagerTestCaseCustom(setSecretKVWithKey),
|
|
makeValidSecretManagerTestCaseCustom(setSecretKVWithKeyPath),
|
|
makeValidSecretManagerTestCaseCustom(setSecretKVWithKeyDot),
|
|
makeValidSecretManagerTestCaseCustom(setSecretKVWithOutKey),
|
|
makeValidSecretManagerTestCaseCustom(badSecretKV),
|
|
makeValidSecretManagerTestCaseCustom(setSecretPublicCert),
|
|
makeValidSecretManagerTestCaseCustom(badSecretPublicCert),
|
|
makeValidSecretManagerTestCaseCustom(setSecretPrivateCert),
|
|
makeValidSecretManagerTestCaseCustom(badSecretPrivateCert),
|
|
}
|
|
|
|
sm := providerIBM{}
|
|
for k, v := range successCases {
|
|
sm.IBMClient = v.mockClient
|
|
out, err := sm.GetSecret(context.Background(), *v.ref)
|
|
if !ErrorContains(err, v.expectError) {
|
|
t.Errorf("[%d] unexpected error: %s, expected: '%s'", k, err.Error(), v.expectError)
|
|
}
|
|
if string(out) != v.expectedSecret {
|
|
t.Errorf("[%d] unexpected secret: expected %s, got %s", k, v.expectedSecret, string(out))
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetSecretMap(t *testing.T) {
|
|
secretKeyName := "kv/test-secret"
|
|
secretUsername := "user1"
|
|
secretPassword := "P@ssw0rd"
|
|
secretAPIKey := "01234567890"
|
|
secretCertificate := "certificate_value"
|
|
secretPrivateKey := "private_key_value"
|
|
secretIntermediate := "intermediate_value"
|
|
|
|
secretComplex := map[string]interface{}{
|
|
"key1": "val1",
|
|
"key2": "val2",
|
|
"keyC": map[string]interface{}{
|
|
"keyC1": map[string]string{
|
|
"keyA": "valA",
|
|
"keyB": "valB",
|
|
},
|
|
},
|
|
}
|
|
|
|
// good case: default version & deserialization
|
|
setDeserialization := func(smtc *secretManagerTestCase) {
|
|
secretData := make(map[string]interface{})
|
|
secretData["payload"] = `{"foo":"bar"}`
|
|
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String("testytype"),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretData,
|
|
}}
|
|
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.expectedData["foo"] = []byte("bar")
|
|
}
|
|
|
|
// bad case: invalid json
|
|
setInvalidJSON := func(smtc *secretManagerTestCase) {
|
|
secretData := make(map[string]interface{})
|
|
secretData["payload"] = `-----------------`
|
|
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String("testytype"),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretData,
|
|
}}
|
|
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.expectError = "unable to unmarshal secret: invalid character '-' in numeric literal"
|
|
}
|
|
|
|
// good case: username_password
|
|
setSecretUserPass := func(smtc *secretManagerTestCase) {
|
|
secretData := make(map[string]interface{})
|
|
secretData["username"] = secretUsername
|
|
secretData["password"] = secretPassword
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String(sm.CreateSecretOptionsSecretTypeUsernamePasswordConst),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretData,
|
|
}}
|
|
|
|
smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeUsernamePasswordConst)
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.ref.Key = "username_password/test-secret"
|
|
smtc.expectedData["username"] = []byte(secretUsername)
|
|
smtc.expectedData["password"] = []byte(secretPassword)
|
|
}
|
|
|
|
// good case: iam_credentials
|
|
setSecretIam := func(smtc *secretManagerTestCase) {
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String(sm.CreateSecretOptionsSecretTypeIamCredentialsConst),
|
|
Name: utilpointer.String("testyname"),
|
|
APIKey: utilpointer.String(secretAPIKey),
|
|
}}
|
|
|
|
smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeIamCredentialsConst)
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.ref.Key = "iam_credentials/test-secret"
|
|
smtc.expectedData["apikey"] = []byte(secretAPIKey)
|
|
}
|
|
|
|
funcCertTest := func(certType string) func(*secretManagerTestCase) {
|
|
return func(smtc *secretManagerTestCase) {
|
|
secretData := make(map[string]interface{})
|
|
secretData["certificate"] = secretCertificate
|
|
secretData["private_key"] = secretPrivateKey
|
|
secretData["intermediate"] = secretIntermediate
|
|
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String(certType),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretData,
|
|
}}
|
|
|
|
smtc.apiInput.SecretType = core.StringPtr(certType)
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.ref.Key = certType + "/test-secret"
|
|
smtc.expectedData["certificate"] = []byte(secretCertificate)
|
|
smtc.expectedData["private_key"] = []byte(secretPrivateKey)
|
|
smtc.expectedData["intermediate"] = []byte(secretIntermediate)
|
|
}
|
|
}
|
|
|
|
// good case: imported_cert
|
|
setSecretCert := funcCertTest(sm.CreateSecretOptionsSecretTypeImportedCertConst)
|
|
// good case: public_cert
|
|
setSecretPublicCert := funcCertTest(sm.CreateSecretOptionsSecretTypePublicCertConst)
|
|
// good case: public_cert
|
|
setSecretPrivateCert := funcCertTest(sm.CreateSecretOptionsSecretTypePrivateCertConst)
|
|
|
|
// good case: kv, no property, return entire payload as key:value pairs
|
|
setSecretKV := func(smtc *secretManagerTestCase) {
|
|
secretData := make(map[string]interface{})
|
|
secretData["payload"] = secretComplex
|
|
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String(sm.CreateSecretOptionsSecretTypeKvConst),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretData,
|
|
}}
|
|
|
|
smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.ref.Key = secretKeyName
|
|
smtc.expectedData["key1"] = []byte("val1")
|
|
smtc.expectedData["key2"] = []byte("val2")
|
|
smtc.expectedData["keyC"] = []byte(`{"keyC1":{"keyA":"valA","keyB":"valB"}}`)
|
|
}
|
|
|
|
// good case: kv, with property
|
|
setSecretKVWithProperty := func(smtc *secretManagerTestCase) {
|
|
secretData := make(map[string]interface{})
|
|
secretData["payload"] = secretComplex
|
|
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String(sm.CreateSecretOptionsSecretTypeKvConst),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretData,
|
|
}}
|
|
|
|
smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
|
|
smtc.ref.Property = "keyC"
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.ref.Key = secretKeyName
|
|
smtc.expectedData["keyC1"] = []byte(`{"keyA":"valA","keyB":"valB"}`)
|
|
}
|
|
|
|
// good case: kv, with property and path
|
|
setSecretKVWithPathAndProperty := func(smtc *secretManagerTestCase) {
|
|
secretData := make(map[string]interface{})
|
|
secretData["payload"] = secretComplex
|
|
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String(sm.CreateSecretOptionsSecretTypeKvConst),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretData,
|
|
}}
|
|
|
|
smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
|
|
smtc.ref.Property = "keyC.keyC1"
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.ref.Key = secretKeyName
|
|
smtc.expectedData["keyA"] = []byte("valA")
|
|
smtc.expectedData["keyB"] = []byte("valB")
|
|
}
|
|
|
|
// bad case: kv, with property and path
|
|
badSecretKVWithUnknownProperty := func(smtc *secretManagerTestCase) {
|
|
secretData := make(map[string]interface{})
|
|
secretData["payload"] = secretComplex
|
|
|
|
resources := []sm.SecretResourceIntf{
|
|
&sm.SecretResource{
|
|
SecretType: utilpointer.String(sm.CreateSecretOptionsSecretTypeKvConst),
|
|
Name: utilpointer.String("testyname"),
|
|
SecretData: secretData,
|
|
}}
|
|
|
|
smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
|
|
smtc.ref.Property = "unknown.property"
|
|
smtc.apiOutput.Resources = resources
|
|
smtc.ref.Key = secretKeyName
|
|
smtc.expectError = "key unknown.property does not exist in secret kv/test-secret"
|
|
}
|
|
|
|
successCases := []*secretManagerTestCase{
|
|
makeValidSecretManagerTestCaseCustom(setDeserialization),
|
|
makeValidSecretManagerTestCaseCustom(setInvalidJSON),
|
|
makeValidSecretManagerTestCaseCustom(setNilMockClient),
|
|
makeValidSecretManagerTestCaseCustom(setAPIErr),
|
|
makeValidSecretManagerTestCaseCustom(setSecretUserPass),
|
|
makeValidSecretManagerTestCaseCustom(setSecretIam),
|
|
makeValidSecretManagerTestCaseCustom(setSecretCert),
|
|
makeValidSecretManagerTestCaseCustom(setSecretKV),
|
|
makeValidSecretManagerTestCaseCustom(setSecretKVWithProperty),
|
|
makeValidSecretManagerTestCaseCustom(setSecretKVWithPathAndProperty),
|
|
makeValidSecretManagerTestCaseCustom(badSecretKVWithUnknownProperty),
|
|
makeValidSecretManagerTestCaseCustom(setSecretPublicCert),
|
|
makeValidSecretManagerTestCaseCustom(setSecretPrivateCert),
|
|
}
|
|
|
|
sm := providerIBM{}
|
|
for k, v := range successCases {
|
|
sm.IBMClient = v.mockClient
|
|
out, err := sm.GetSecretMap(context.Background(), *v.ref)
|
|
if !ErrorContains(err, v.expectError) {
|
|
t.Errorf("[%d] unexpected error: %s, expected: '%s'", k, err.Error(), v.expectError)
|
|
}
|
|
if err == nil && !reflect.DeepEqual(out, v.expectedData) {
|
|
t.Errorf("[%d] unexpected secret data: expected %#v, got %#v", k, v.expectedData, out)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestValidRetryInput(t *testing.T) {
|
|
sm := providerIBM{}
|
|
|
|
invalid := "Invalid"
|
|
serviceURL := "http://fake-service-url.cool"
|
|
|
|
spec := &esv1beta1.SecretStore{
|
|
Spec: esv1beta1.SecretStoreSpec{
|
|
Provider: &esv1beta1.SecretStoreProvider{
|
|
IBM: &esv1beta1.IBMProvider{
|
|
Auth: esv1beta1.IBMAuth{
|
|
SecretRef: esv1beta1.IBMAuthSecretRef{
|
|
SecretAPIKey: v1.SecretKeySelector{
|
|
Name: "fake-secret",
|
|
Key: "fake-key",
|
|
},
|
|
},
|
|
},
|
|
ServiceURL: &serviceURL,
|
|
},
|
|
},
|
|
RetrySettings: &esv1beta1.SecretStoreRetrySettings{
|
|
RetryInterval: &invalid,
|
|
},
|
|
},
|
|
}
|
|
|
|
expected := fmt.Sprintf("cannot setup new ibm client: time: invalid duration %q", invalid)
|
|
ctx := context.TODO()
|
|
kube := clientfake.NewClientBuilder().WithObjects(&corev1.Secret{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "fake-secret",
|
|
Namespace: "default",
|
|
},
|
|
Data: map[string][]byte{
|
|
"fake-key": []byte("ImAFakeApiKey"),
|
|
},
|
|
}).Build()
|
|
|
|
_, err := sm.NewClient(ctx, spec, kube, "default")
|
|
|
|
if !ErrorContains(err, expected) {
|
|
t.Errorf("CheckValidRetryInput unexpected error: %s, expected: '%s'", err.Error(), expected)
|
|
}
|
|
}
|
|
|
|
func ErrorContains(out error, want string) bool {
|
|
if out == nil {
|
|
return want == ""
|
|
}
|
|
if want == "" {
|
|
return false
|
|
}
|
|
return strings.Contains(out.Error(), want)
|
|
}
|