provider_test.go 26 KB

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