provider_test.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  1. /*
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. package ibm
  13. import (
  14. "context"
  15. "fmt"
  16. "reflect"
  17. "strings"
  18. "testing"
  19. "github.com/IBM/go-sdk-core/v5/core"
  20. sm "github.com/IBM/secrets-manager-go-sdk/secretsmanagerv1"
  21. "github.com/crossplane/crossplane-runtime/pkg/test"
  22. corev1 "k8s.io/api/core/v1"
  23. utilpointer "k8s.io/utils/pointer"
  24. kclient "sigs.k8s.io/controller-runtime/pkg/client"
  25. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  26. v1 "github.com/external-secrets/external-secrets/apis/meta/v1"
  27. fakesm "github.com/external-secrets/external-secrets/pkg/provider/ibm/fake"
  28. )
  29. const (
  30. errExpectedErr = "wanted error got nil"
  31. secretKey = "test-secret"
  32. )
  33. type secretManagerTestCase struct {
  34. mockClient *fakesm.IBMMockClient
  35. apiInput *sm.GetSecretOptions
  36. apiOutput *sm.GetSecret
  37. ref *esv1beta1.ExternalSecretDataRemoteRef
  38. serviceURL *string
  39. apiErr error
  40. expectError string
  41. expectedSecret string
  42. // for testing secretmap
  43. expectedData map[string][]byte
  44. }
  45. func makeValidSecretManagerTestCase() *secretManagerTestCase {
  46. smtc := secretManagerTestCase{
  47. mockClient: &fakesm.IBMMockClient{},
  48. apiInput: makeValidAPIInput(),
  49. ref: makeValidRef(),
  50. apiOutput: makeValidAPIOutput(),
  51. serviceURL: nil,
  52. apiErr: nil,
  53. expectError: "",
  54. expectedSecret: "",
  55. expectedData: map[string][]byte{},
  56. }
  57. smtc.mockClient.WithValue(smtc.apiInput, smtc.apiOutput, smtc.apiErr)
  58. return &smtc
  59. }
  60. func makeValidRef() *esv1beta1.ExternalSecretDataRemoteRef {
  61. return &esv1beta1.ExternalSecretDataRemoteRef{
  62. Key: secretKey,
  63. Version: "default",
  64. }
  65. }
  66. func makeValidAPIInput() *sm.GetSecretOptions {
  67. return &sm.GetSecretOptions{
  68. SecretType: core.StringPtr(sm.GetSecretOptionsSecretTypeArbitraryConst),
  69. ID: utilpointer.StringPtr(secretKey),
  70. }
  71. }
  72. func makeValidAPIOutput() *sm.GetSecret {
  73. secretData := make(map[string]interface{})
  74. secretData["payload"] = ""
  75. return &sm.GetSecret{
  76. Resources: []sm.SecretResourceIntf{
  77. &sm.SecretResource{
  78. SecretType: utilpointer.StringPtr("testytype"),
  79. Name: utilpointer.StringPtr("testyname"),
  80. SecretData: secretData,
  81. },
  82. },
  83. }
  84. }
  85. func makeValidSecretManagerTestCaseCustom(tweaks ...func(smtc *secretManagerTestCase)) *secretManagerTestCase {
  86. smtc := makeValidSecretManagerTestCase()
  87. for _, fn := range tweaks {
  88. fn(smtc)
  89. }
  90. smtc.mockClient.WithValue(smtc.apiInput, smtc.apiOutput, smtc.apiErr)
  91. return smtc
  92. }
  93. // This case can be shared by both GetSecret and GetSecretMap tests.
  94. // bad case: set apiErr.
  95. var setAPIErr = func(smtc *secretManagerTestCase) {
  96. smtc.apiErr = fmt.Errorf("oh no")
  97. smtc.expectError = "oh no"
  98. }
  99. var setNilMockClient = func(smtc *secretManagerTestCase) {
  100. smtc.mockClient = nil
  101. smtc.expectError = errUninitalizedIBMProvider
  102. }
  103. // simple tests for Validate Store.
  104. func TestValidateStore(t *testing.T) {
  105. p := providerIBM{}
  106. store := &esv1beta1.SecretStore{
  107. Spec: esv1beta1.SecretStoreSpec{
  108. Provider: &esv1beta1.SecretStoreProvider{
  109. IBM: &esv1beta1.IBMProvider{},
  110. },
  111. },
  112. }
  113. err := p.ValidateStore(store)
  114. if err == nil {
  115. t.Errorf(errExpectedErr)
  116. } else if err.Error() != "serviceURL is required" {
  117. t.Errorf("service URL test failed")
  118. }
  119. url := "my-url"
  120. store.Spec.Provider.IBM.ServiceURL = &url
  121. err = p.ValidateStore(store)
  122. if err == nil {
  123. t.Errorf(errExpectedErr)
  124. } else if err.Error() != "secretAPIKey.name cannot be empty" {
  125. t.Errorf("KeySelector test failed: expected secret name is required, got %v", err)
  126. }
  127. store.Spec.Provider.IBM.Auth.SecretRef.SecretAPIKey.Name = "foo"
  128. store.Spec.Provider.IBM.Auth.SecretRef.SecretAPIKey.Key = "bar"
  129. ns := "ns-one"
  130. store.Spec.Provider.IBM.Auth.SecretRef.SecretAPIKey.Namespace = &ns
  131. err = p.ValidateStore(store)
  132. if err == nil {
  133. t.Errorf(errExpectedErr)
  134. } else if err.Error() != "namespace not allowed with namespaced SecretStore" {
  135. t.Errorf("KeySelector test failed: expected namespace not allowed, got %v", err)
  136. }
  137. }
  138. // test the sm<->gcp interface
  139. // make sure correct values are passed and errors are handled accordingly.
  140. func TestIBMSecretManagerGetSecret(t *testing.T) {
  141. secretData := make(map[string]interface{})
  142. secretString := "changedvalue"
  143. secretPassword := "P@ssw0rd"
  144. secretAPIKey := "01234567890"
  145. secretCertificate := "certificate_value"
  146. secretData["payload"] = secretString
  147. secretData["password"] = secretPassword
  148. secretData["certificate"] = secretCertificate
  149. // good case: default version is set
  150. // key is passed in, output is sent back
  151. setSecretString := func(smtc *secretManagerTestCase) {
  152. resources := []sm.SecretResourceIntf{
  153. &sm.SecretResource{
  154. SecretType: utilpointer.StringPtr("testytype"),
  155. Name: utilpointer.StringPtr("testyname"),
  156. SecretData: secretData,
  157. }}
  158. smtc.apiOutput.Resources = resources
  159. smtc.expectedSecret = secretString
  160. }
  161. // good case: custom version set
  162. setCustomKey := func(smtc *secretManagerTestCase) {
  163. resources := []sm.SecretResourceIntf{
  164. &sm.SecretResource{
  165. SecretType: utilpointer.StringPtr("testytype"),
  166. Name: utilpointer.StringPtr("testyname"),
  167. SecretData: secretData,
  168. }}
  169. smtc.ref.Key = "testyname"
  170. smtc.apiInput.ID = utilpointer.StringPtr("testyname")
  171. smtc.apiOutput.Resources = resources
  172. smtc.expectedSecret = secretString
  173. }
  174. // bad case: username_password type without property
  175. secretUserPass := "username_password/test-secret"
  176. badSecretUserPass := func(smtc *secretManagerTestCase) {
  177. resources := []sm.SecretResourceIntf{
  178. &sm.SecretResource{
  179. SecretType: utilpointer.StringPtr(sm.CreateSecretOptionsSecretTypeUsernamePasswordConst),
  180. Name: utilpointer.StringPtr("testyname"),
  181. SecretData: secretData,
  182. }}
  183. smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeUsernamePasswordConst)
  184. smtc.apiOutput.Resources = resources
  185. smtc.ref.Key = secretUserPass
  186. smtc.expectError = "remoteRef.property required for secret type username_password"
  187. }
  188. // good case: username_password type with property
  189. setSecretUserPass := func(smtc *secretManagerTestCase) {
  190. resources := []sm.SecretResourceIntf{
  191. &sm.SecretResource{
  192. SecretType: utilpointer.StringPtr(sm.CreateSecretOptionsSecretTypeUsernamePasswordConst),
  193. Name: utilpointer.StringPtr("testyname"),
  194. SecretData: secretData,
  195. }}
  196. smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeUsernamePasswordConst)
  197. smtc.apiOutput.Resources = resources
  198. smtc.ref.Key = secretUserPass
  199. smtc.ref.Property = "password"
  200. smtc.expectedSecret = secretPassword
  201. }
  202. // good case: iam_credenatials type
  203. setSecretIam := func(smtc *secretManagerTestCase) {
  204. resources := []sm.SecretResourceIntf{
  205. &sm.SecretResource{
  206. SecretType: utilpointer.StringPtr(sm.CreateSecretOptionsSecretTypeIamCredentialsConst),
  207. Name: utilpointer.StringPtr("testyname"),
  208. APIKey: utilpointer.StringPtr(secretAPIKey),
  209. }}
  210. smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeIamCredentialsConst)
  211. smtc.apiOutput.Resources = resources
  212. smtc.ref.Key = "iam_credentials/test-secret"
  213. smtc.expectedSecret = secretAPIKey
  214. }
  215. funcSetCertSecretTest := func(certType string, good bool) func(*secretManagerTestCase) {
  216. return func(smtc *secretManagerTestCase) {
  217. resources := []sm.SecretResourceIntf{
  218. &sm.SecretResource{
  219. SecretType: utilpointer.StringPtr(certType),
  220. Name: utilpointer.StringPtr("testyname"),
  221. SecretData: secretData,
  222. }}
  223. smtc.apiInput.SecretType = core.StringPtr(certType)
  224. smtc.apiOutput.Resources = resources
  225. smtc.ref.Key = certType + "/" + secretKey
  226. if good {
  227. smtc.ref.Property = "certificate"
  228. smtc.expectedSecret = secretCertificate
  229. } else {
  230. smtc.expectError = "remoteRef.property required for secret type " + certType
  231. }
  232. }
  233. }
  234. // good case: imported_cert type with property
  235. setSecretCert := funcSetCertSecretTest(sm.CreateSecretOptionsSecretTypeImportedCertConst, true)
  236. // bad case: imported_cert type without property
  237. badSecretCert := funcSetCertSecretTest(sm.CreateSecretOptionsSecretTypeImportedCertConst, false)
  238. // good case: public_cert type with property
  239. setSecretPublicCert := funcSetCertSecretTest(sm.CreateSecretOptionsSecretTypePublicCertConst, true)
  240. // bad case: public_cert type without property
  241. badSecretPublicCert := funcSetCertSecretTest(sm.CreateSecretOptionsSecretTypePublicCertConst, false)
  242. // good case: private_cert type with property
  243. setSecretPrivateCert := funcSetCertSecretTest(sm.CreateSecretOptionsSecretTypePrivateCertConst, true)
  244. // bad case: private_cert type without property
  245. badSecretPrivateCert := funcSetCertSecretTest(sm.CreateSecretOptionsSecretTypePrivateCertConst, false)
  246. secretDataKV := make(map[string]interface{})
  247. secretKVPayload := make(map[string]interface{})
  248. secretKVPayload["key1"] = "val1"
  249. secretDataKV["payload"] = secretKVPayload
  250. secretDataKVComplex := make(map[string]interface{})
  251. secretKVComplex := `{"key1":"val1","key2":"val2","key3":"val3","keyC":{"keyC1":"valC1", "keyC2":"valC2"}, "special.log": "file-content"}`
  252. secretDataKVComplex["payload"] = secretKVComplex
  253. secretKV := "kv/test-secret"
  254. // bad case: kv type with key which is not in payload
  255. badSecretKV := func(smtc *secretManagerTestCase) {
  256. resources := []sm.SecretResourceIntf{
  257. &sm.SecretResource{
  258. SecretType: utilpointer.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst),
  259. Name: utilpointer.StringPtr("testyname"),
  260. SecretData: secretDataKV,
  261. }}
  262. smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
  263. smtc.apiOutput.Resources = resources
  264. smtc.ref.Key = secretKV
  265. smtc.ref.Property = "other-key"
  266. smtc.expectError = "key other-key does not exist in secret kv/test-secret"
  267. }
  268. // good case: kv type with property
  269. setSecretKV := func(smtc *secretManagerTestCase) {
  270. resources := []sm.SecretResourceIntf{
  271. &sm.SecretResource{
  272. SecretType: utilpointer.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst),
  273. Name: utilpointer.StringPtr("testyname"),
  274. SecretData: secretDataKV,
  275. }}
  276. smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
  277. smtc.apiOutput.Resources = resources
  278. smtc.ref.Key = secretKV
  279. smtc.ref.Property = "key1"
  280. smtc.expectedSecret = "val1"
  281. }
  282. // good case: kv type with property, returns specific value
  283. setSecretKVWithKey := func(smtc *secretManagerTestCase) {
  284. resources := []sm.SecretResourceIntf{
  285. &sm.SecretResource{
  286. SecretType: utilpointer.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst),
  287. Name: utilpointer.StringPtr("testyname"),
  288. SecretData: secretDataKVComplex,
  289. }}
  290. smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
  291. smtc.apiOutput.Resources = resources
  292. smtc.ref.Key = secretKV
  293. smtc.ref.Property = "key2"
  294. smtc.expectedSecret = "val2"
  295. }
  296. // good case: kv type with property and path, returns specific value
  297. setSecretKVWithKeyPath := func(smtc *secretManagerTestCase) {
  298. resources := []sm.SecretResourceIntf{
  299. &sm.SecretResource{
  300. SecretType: utilpointer.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst),
  301. Name: utilpointer.StringPtr("testyname"),
  302. SecretData: secretDataKVComplex,
  303. }}
  304. smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
  305. smtc.apiOutput.Resources = resources
  306. smtc.ref.Key = secretKV
  307. smtc.ref.Property = "keyC.keyC2"
  308. smtc.expectedSecret = "valC2"
  309. }
  310. // good case: kv type with property and dot, returns specific value
  311. setSecretKVWithKeyDot := func(smtc *secretManagerTestCase) {
  312. resources := []sm.SecretResourceIntf{
  313. &sm.SecretResource{
  314. SecretType: utilpointer.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst),
  315. Name: utilpointer.StringPtr("testyname"),
  316. SecretData: secretDataKVComplex,
  317. }}
  318. smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
  319. smtc.apiOutput.Resources = resources
  320. smtc.ref.Key = secretKV
  321. smtc.ref.Property = "special.log"
  322. smtc.expectedSecret = "file-content"
  323. }
  324. // good case: kv type without property, returns all
  325. setSecretKVWithOutKey := func(smtc *secretManagerTestCase) {
  326. resources := []sm.SecretResourceIntf{
  327. &sm.SecretResource{
  328. SecretType: utilpointer.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst),
  329. Name: utilpointer.StringPtr("testyname"),
  330. SecretData: secretDataKVComplex,
  331. }}
  332. smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
  333. smtc.apiOutput.Resources = resources
  334. smtc.ref.Key = secretKV
  335. smtc.expectedSecret = secretKVComplex
  336. }
  337. successCases := []*secretManagerTestCase{
  338. makeValidSecretManagerTestCase(),
  339. makeValidSecretManagerTestCaseCustom(setSecretString),
  340. makeValidSecretManagerTestCaseCustom(setCustomKey),
  341. makeValidSecretManagerTestCaseCustom(setAPIErr),
  342. makeValidSecretManagerTestCaseCustom(setNilMockClient),
  343. makeValidSecretManagerTestCaseCustom(badSecretUserPass),
  344. makeValidSecretManagerTestCaseCustom(setSecretUserPass),
  345. makeValidSecretManagerTestCaseCustom(setSecretIam),
  346. makeValidSecretManagerTestCaseCustom(setSecretCert),
  347. makeValidSecretManagerTestCaseCustom(badSecretCert),
  348. makeValidSecretManagerTestCaseCustom(setSecretKV),
  349. makeValidSecretManagerTestCaseCustom(setSecretKVWithKey),
  350. makeValidSecretManagerTestCaseCustom(setSecretKVWithKeyPath),
  351. makeValidSecretManagerTestCaseCustom(setSecretKVWithKeyDot),
  352. makeValidSecretManagerTestCaseCustom(setSecretKVWithOutKey),
  353. makeValidSecretManagerTestCaseCustom(badSecretKV),
  354. makeValidSecretManagerTestCaseCustom(setSecretPublicCert),
  355. makeValidSecretManagerTestCaseCustom(badSecretPublicCert),
  356. makeValidSecretManagerTestCaseCustom(setSecretPrivateCert),
  357. makeValidSecretManagerTestCaseCustom(badSecretPrivateCert),
  358. }
  359. sm := providerIBM{}
  360. for k, v := range successCases {
  361. sm.IBMClient = v.mockClient
  362. out, err := sm.GetSecret(context.Background(), *v.ref)
  363. if !ErrorContains(err, v.expectError) {
  364. t.Errorf("[%d] unexpected error: %s, expected: '%s'", k, err.Error(), v.expectError)
  365. }
  366. if string(out) != v.expectedSecret {
  367. t.Errorf("[%d] unexpected secret: expected %s, got %s", k, v.expectedSecret, string(out))
  368. }
  369. }
  370. }
  371. func TestGetSecretMap(t *testing.T) {
  372. secretKeyName := "kv/test-secret"
  373. secretUsername := "user1"
  374. secretPassword := "P@ssw0rd"
  375. secretAPIKey := "01234567890"
  376. secretCertificate := "certificate_value"
  377. secretPrivateKey := "private_key_value"
  378. secretIntermediate := "intermediate_value"
  379. secretComplex := map[string]interface{}{
  380. "key1": "val1",
  381. "key2": "val2",
  382. "keyC": map[string]interface{}{
  383. "keyC1": map[string]string{
  384. "keyA": "valA",
  385. "keyB": "valB",
  386. },
  387. },
  388. }
  389. // good case: default version & deserialization
  390. setDeserialization := func(smtc *secretManagerTestCase) {
  391. secretData := make(map[string]interface{})
  392. secretData["payload"] = `{"foo":"bar"}`
  393. resources := []sm.SecretResourceIntf{
  394. &sm.SecretResource{
  395. SecretType: utilpointer.StringPtr("testytype"),
  396. Name: utilpointer.StringPtr("testyname"),
  397. SecretData: secretData,
  398. }}
  399. smtc.apiOutput.Resources = resources
  400. smtc.expectedData["foo"] = []byte("bar")
  401. }
  402. // bad case: invalid json
  403. setInvalidJSON := func(smtc *secretManagerTestCase) {
  404. secretData := make(map[string]interface{})
  405. secretData["payload"] = `-----------------`
  406. resources := []sm.SecretResourceIntf{
  407. &sm.SecretResource{
  408. SecretType: utilpointer.StringPtr("testytype"),
  409. Name: utilpointer.StringPtr("testyname"),
  410. SecretData: secretData,
  411. }}
  412. smtc.apiOutput.Resources = resources
  413. smtc.expectError = "unable to unmarshal secret: invalid character '-' in numeric literal"
  414. }
  415. // good case: username_password
  416. setSecretUserPass := func(smtc *secretManagerTestCase) {
  417. secretData := make(map[string]interface{})
  418. secretData["username"] = secretUsername
  419. secretData["password"] = secretPassword
  420. resources := []sm.SecretResourceIntf{
  421. &sm.SecretResource{
  422. SecretType: utilpointer.StringPtr(sm.CreateSecretOptionsSecretTypeUsernamePasswordConst),
  423. Name: utilpointer.StringPtr("testyname"),
  424. SecretData: secretData,
  425. }}
  426. smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeUsernamePasswordConst)
  427. smtc.apiOutput.Resources = resources
  428. smtc.ref.Key = "username_password/test-secret"
  429. smtc.expectedData["username"] = []byte(secretUsername)
  430. smtc.expectedData["password"] = []byte(secretPassword)
  431. }
  432. // good case: iam_credentials
  433. setSecretIam := func(smtc *secretManagerTestCase) {
  434. resources := []sm.SecretResourceIntf{
  435. &sm.SecretResource{
  436. SecretType: utilpointer.StringPtr(sm.CreateSecretOptionsSecretTypeIamCredentialsConst),
  437. Name: utilpointer.StringPtr("testyname"),
  438. APIKey: utilpointer.StringPtr(secretAPIKey),
  439. }}
  440. smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeIamCredentialsConst)
  441. smtc.apiOutput.Resources = resources
  442. smtc.ref.Key = "iam_credentials/test-secret"
  443. smtc.expectedData["apikey"] = []byte(secretAPIKey)
  444. }
  445. funcCertTest := func(certType string) func(*secretManagerTestCase) {
  446. return func(smtc *secretManagerTestCase) {
  447. secretData := make(map[string]interface{})
  448. secretData["certificate"] = secretCertificate
  449. secretData["private_key"] = secretPrivateKey
  450. secretData["intermediate"] = secretIntermediate
  451. resources := []sm.SecretResourceIntf{
  452. &sm.SecretResource{
  453. SecretType: utilpointer.StringPtr(certType),
  454. Name: utilpointer.StringPtr("testyname"),
  455. SecretData: secretData,
  456. }}
  457. smtc.apiInput.SecretType = core.StringPtr(certType)
  458. smtc.apiOutput.Resources = resources
  459. smtc.ref.Key = certType + "/test-secret"
  460. smtc.expectedData["certificate"] = []byte(secretCertificate)
  461. smtc.expectedData["private_key"] = []byte(secretPrivateKey)
  462. smtc.expectedData["intermediate"] = []byte(secretIntermediate)
  463. }
  464. }
  465. // good case: imported_cert
  466. setSecretCert := funcCertTest(sm.CreateSecretOptionsSecretTypeImportedCertConst)
  467. // good case: public_cert
  468. setSecretPublicCert := funcCertTest(sm.CreateSecretOptionsSecretTypePublicCertConst)
  469. // good case: public_cert
  470. setSecretPrivateCert := funcCertTest(sm.CreateSecretOptionsSecretTypePrivateCertConst)
  471. // good case: kv, no property, return entire payload as key:value pairs
  472. setSecretKV := func(smtc *secretManagerTestCase) {
  473. secretData := make(map[string]interface{})
  474. secretData["payload"] = secretComplex
  475. resources := []sm.SecretResourceIntf{
  476. &sm.SecretResource{
  477. SecretType: utilpointer.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst),
  478. Name: utilpointer.StringPtr("testyname"),
  479. SecretData: secretData,
  480. }}
  481. smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
  482. smtc.apiOutput.Resources = resources
  483. smtc.ref.Key = secretKeyName
  484. smtc.expectedData["key1"] = []byte("val1")
  485. smtc.expectedData["key2"] = []byte("val2")
  486. smtc.expectedData["keyC"] = []byte(`{"keyC1":{"keyA":"valA","keyB":"valB"}}`)
  487. }
  488. // good case: kv, with property
  489. setSecretKVWithProperty := func(smtc *secretManagerTestCase) {
  490. secretData := make(map[string]interface{})
  491. secretData["payload"] = secretComplex
  492. resources := []sm.SecretResourceIntf{
  493. &sm.SecretResource{
  494. SecretType: utilpointer.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst),
  495. Name: utilpointer.StringPtr("testyname"),
  496. SecretData: secretData,
  497. }}
  498. smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
  499. smtc.ref.Property = "keyC"
  500. smtc.apiOutput.Resources = resources
  501. smtc.ref.Key = secretKeyName
  502. smtc.expectedData["keyC1"] = []byte(`{"keyA":"valA","keyB":"valB"}`)
  503. }
  504. // good case: kv, with property and path
  505. setSecretKVWithPathAndProperty := func(smtc *secretManagerTestCase) {
  506. secretData := make(map[string]interface{})
  507. secretData["payload"] = secretComplex
  508. resources := []sm.SecretResourceIntf{
  509. &sm.SecretResource{
  510. SecretType: utilpointer.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst),
  511. Name: utilpointer.StringPtr("testyname"),
  512. SecretData: secretData,
  513. }}
  514. smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
  515. smtc.ref.Property = "keyC.keyC1"
  516. smtc.apiOutput.Resources = resources
  517. smtc.ref.Key = secretKeyName
  518. smtc.expectedData["keyA"] = []byte("valA")
  519. smtc.expectedData["keyB"] = []byte("valB")
  520. }
  521. // bad case: kv, with property and path
  522. badSecretKVWithUnknownProperty := func(smtc *secretManagerTestCase) {
  523. secretData := make(map[string]interface{})
  524. secretData["payload"] = secretComplex
  525. resources := []sm.SecretResourceIntf{
  526. &sm.SecretResource{
  527. SecretType: utilpointer.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst),
  528. Name: utilpointer.StringPtr("testyname"),
  529. SecretData: secretData,
  530. }}
  531. smtc.apiInput.SecretType = core.StringPtr(sm.CreateSecretOptionsSecretTypeKvConst)
  532. smtc.ref.Property = "unknown.property"
  533. smtc.apiOutput.Resources = resources
  534. smtc.ref.Key = secretKeyName
  535. smtc.expectError = "key unknown.property does not exist in secret kv/test-secret"
  536. }
  537. successCases := []*secretManagerTestCase{
  538. makeValidSecretManagerTestCaseCustom(setDeserialization),
  539. makeValidSecretManagerTestCaseCustom(setInvalidJSON),
  540. makeValidSecretManagerTestCaseCustom(setNilMockClient),
  541. makeValidSecretManagerTestCaseCustom(setAPIErr),
  542. makeValidSecretManagerTestCaseCustom(setSecretUserPass),
  543. makeValidSecretManagerTestCaseCustom(setSecretIam),
  544. makeValidSecretManagerTestCaseCustom(setSecretCert),
  545. makeValidSecretManagerTestCaseCustom(setSecretKV),
  546. makeValidSecretManagerTestCaseCustom(setSecretKVWithProperty),
  547. makeValidSecretManagerTestCaseCustom(setSecretKVWithPathAndProperty),
  548. makeValidSecretManagerTestCaseCustom(badSecretKVWithUnknownProperty),
  549. makeValidSecretManagerTestCaseCustom(setSecretPublicCert),
  550. makeValidSecretManagerTestCaseCustom(setSecretPrivateCert),
  551. }
  552. sm := providerIBM{}
  553. for k, v := range successCases {
  554. sm.IBMClient = v.mockClient
  555. out, err := sm.GetSecretMap(context.Background(), *v.ref)
  556. if !ErrorContains(err, v.expectError) {
  557. t.Errorf("[%d] unexpected error: %s, expected: '%s'", k, err.Error(), v.expectError)
  558. }
  559. if err == nil && !reflect.DeepEqual(out, v.expectedData) {
  560. t.Errorf("[%d] unexpected secret data: expected %#v, got %#v", k, v.expectedData, out)
  561. }
  562. }
  563. }
  564. func TestValidRetryInput(t *testing.T) {
  565. sm := providerIBM{}
  566. invalid := "Invalid"
  567. serviceURL := "http://fake-service-url.cool"
  568. spec := &esv1beta1.SecretStore{
  569. Spec: esv1beta1.SecretStoreSpec{
  570. Provider: &esv1beta1.SecretStoreProvider{
  571. IBM: &esv1beta1.IBMProvider{
  572. Auth: esv1beta1.IBMAuth{
  573. SecretRef: esv1beta1.IBMAuthSecretRef{
  574. SecretAPIKey: v1.SecretKeySelector{
  575. Name: "fake-secret",
  576. Key: "fake-key",
  577. },
  578. },
  579. },
  580. ServiceURL: &serviceURL,
  581. },
  582. },
  583. RetrySettings: &esv1beta1.SecretStoreRetrySettings{
  584. RetryInterval: &invalid,
  585. },
  586. },
  587. }
  588. expected := fmt.Sprintf("cannot setup new ibm client: time: invalid duration %q", invalid)
  589. ctx := context.TODO()
  590. kube := &test.MockClient{
  591. MockGet: test.NewMockGetFn(nil, func(obj kclient.Object) error {
  592. if o, ok := obj.(*corev1.Secret); ok {
  593. o.Data = map[string][]byte{
  594. "fake-key": []byte("ImAFakeApiKey"),
  595. }
  596. return nil
  597. }
  598. return nil
  599. }),
  600. }
  601. _, err := sm.NewClient(ctx, spec, kube, "default")
  602. if !ErrorContains(err, expected) {
  603. t.Errorf("CheckValidRetryInput unexpected error: %s, expected: '%s'", err.Error(), expected)
  604. }
  605. }
  606. func ErrorContains(out error, want string) bool {
  607. if out == nil {
  608. return want == ""
  609. }
  610. if want == "" {
  611. return false
  612. }
  613. return strings.Contains(out.Error(), want)
  614. }