provider_test.go 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227
  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. "strconv"
  19. "strings"
  20. "testing"
  21. "time"
  22. "github.com/IBM/go-sdk-core/v5/core"
  23. sm "github.com/IBM/secrets-manager-go-sdk/v2/secretsmanagerv2"
  24. "github.com/go-openapi/strfmt"
  25. corev1 "k8s.io/api/core/v1"
  26. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  27. utilpointer "k8s.io/utils/ptr"
  28. clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
  29. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  30. v1 "github.com/external-secrets/external-secrets/apis/meta/v1"
  31. fakesm "github.com/external-secrets/external-secrets/pkg/provider/ibm/fake"
  32. )
  33. const (
  34. errExpectedErr = "wanted error got nil"
  35. secretKey = "test-secret"
  36. secretUUID = "d5deb37a-7883-4fe2-a5e7-3c15420adc76"
  37. iamCredentialsSecret = "iam_credentials/"
  38. )
  39. type secretManagerTestCase struct {
  40. name string
  41. mockClient *fakesm.IBMMockClient
  42. apiInput *sm.GetSecretOptions
  43. apiOutput sm.SecretIntf
  44. listInput *sm.ListSecretsOptions
  45. listOutput *sm.SecretMetadataPaginatedCollection
  46. listError error
  47. getByNameInput *sm.GetSecretByNameTypeOptions
  48. getByNameOutput sm.SecretIntf
  49. getByNameError error
  50. ref *esv1beta1.ExternalSecretDataRemoteRef
  51. serviceURL *string
  52. apiErr error
  53. expectError string
  54. expectedSecret string
  55. // for testing secretmap
  56. expectedData map[string][]byte
  57. }
  58. func makeValidSecretManagerTestCase() *secretManagerTestCase {
  59. smtc := secretManagerTestCase{
  60. mockClient: &fakesm.IBMMockClient{},
  61. apiInput: makeValidAPIInput(),
  62. ref: makeValidRef(),
  63. apiOutput: makeValidAPIOutput(),
  64. listInput: makeValidListInput(),
  65. listOutput: makeValidListSecretsOutput(),
  66. listError: nil,
  67. getByNameInput: makeValidGetByNameInput(),
  68. getByNameOutput: makeValidGetByNameOutput(),
  69. getByNameError: nil,
  70. serviceURL: nil,
  71. apiErr: nil,
  72. expectError: "",
  73. expectedSecret: "",
  74. expectedData: map[string][]byte{},
  75. }
  76. mcParams := fakesm.IBMMockClientParams{
  77. GetSecretOptions: smtc.apiInput,
  78. GetSecretOutput: smtc.apiOutput,
  79. GetSecretErr: smtc.apiErr,
  80. ListSecretsOptions: smtc.listInput,
  81. ListSecretsOutput: smtc.listOutput,
  82. ListSecretsErr: smtc.listError,
  83. GetSecretByNameOptions: smtc.getByNameInput,
  84. GetSecretByNameOutput: smtc.getByNameOutput,
  85. GetSecretByNameErr: smtc.getByNameError,
  86. }
  87. smtc.mockClient.WithValue(mcParams)
  88. return &smtc
  89. }
  90. func makeValidRef() *esv1beta1.ExternalSecretDataRemoteRef {
  91. return &esv1beta1.ExternalSecretDataRemoteRef{
  92. Key: secretUUID,
  93. Version: "default",
  94. }
  95. }
  96. func makeValidAPIInput() *sm.GetSecretOptions {
  97. return &sm.GetSecretOptions{
  98. ID: utilpointer.To(secretUUID),
  99. }
  100. }
  101. func makeValidAPIOutput() sm.SecretIntf {
  102. secret := &sm.Secret{
  103. SecretType: utilpointer.To(sm.Secret_SecretType_Arbitrary),
  104. Name: utilpointer.To("testyname"),
  105. ID: utilpointer.To(secretUUID),
  106. }
  107. var i sm.SecretIntf = secret
  108. return i
  109. }
  110. func makeValidGetByNameInput() *sm.GetSecretByNameTypeOptions {
  111. return &sm.GetSecretByNameTypeOptions{}
  112. }
  113. func makeValidGetByNameOutput() sm.SecretIntf {
  114. secret := &sm.Secret{
  115. SecretType: utilpointer.To(sm.Secret_SecretType_Arbitrary),
  116. Name: utilpointer.To("testyname"),
  117. ID: utilpointer.To(secretUUID),
  118. }
  119. var i sm.SecretIntf = secret
  120. return i
  121. }
  122. func makeValidListSecretsOutput() *sm.SecretMetadataPaginatedCollection {
  123. list := sm.SecretMetadataPaginatedCollection{}
  124. return &list
  125. }
  126. func makeValidListInput() *sm.ListSecretsOptions {
  127. listOpt := sm.ListSecretsOptions{}
  128. return &listOpt
  129. }
  130. func makeValidSecretManagerTestCaseCustom(tweaks ...func(smtc *secretManagerTestCase)) *secretManagerTestCase {
  131. smtc := makeValidSecretManagerTestCase()
  132. for _, fn := range tweaks {
  133. fn(smtc)
  134. }
  135. mcParams := fakesm.IBMMockClientParams{
  136. GetSecretOptions: smtc.apiInput,
  137. GetSecretOutput: smtc.apiOutput,
  138. GetSecretErr: smtc.apiErr,
  139. ListSecretsOptions: smtc.listInput,
  140. ListSecretsOutput: smtc.listOutput,
  141. ListSecretsErr: smtc.listError,
  142. GetSecretByNameOptions: smtc.getByNameInput,
  143. GetSecretByNameOutput: smtc.getByNameOutput,
  144. GetSecretByNameErr: smtc.apiErr,
  145. }
  146. smtc.mockClient.WithValue(mcParams)
  147. return smtc
  148. }
  149. // This case can be shared by both GetSecret and GetSecretMap tests.
  150. // bad case: set apiErr.
  151. var setAPIErr = func(smtc *secretManagerTestCase) {
  152. smtc.apiErr = fmt.Errorf("oh no")
  153. smtc.expectError = "oh no"
  154. }
  155. var setNilMockClient = func(smtc *secretManagerTestCase) {
  156. smtc.mockClient = nil
  157. smtc.expectError = errUninitalizedIBMProvider
  158. }
  159. // simple tests for Validate Store.
  160. func TestValidateStore(t *testing.T) {
  161. p := providerIBM{}
  162. store := &esv1beta1.SecretStore{
  163. Spec: esv1beta1.SecretStoreSpec{
  164. Provider: &esv1beta1.SecretStoreProvider{
  165. IBM: &esv1beta1.IBMProvider{},
  166. },
  167. },
  168. }
  169. err := p.ValidateStore(store)
  170. if err == nil {
  171. t.Errorf(errExpectedErr)
  172. } else if err.Error() != "serviceURL is required" {
  173. t.Errorf("service URL test failed")
  174. }
  175. url := "my-url"
  176. store.Spec.Provider.IBM.ServiceURL = &url
  177. err = p.ValidateStore(store)
  178. if err == nil {
  179. t.Errorf(errExpectedErr)
  180. } else if err.Error() != "missing auth method" {
  181. t.Errorf("KeySelector test failed: expected missing auth method, got %v", err)
  182. }
  183. ns := "ns-one"
  184. store.Spec.Provider.IBM.Auth.SecretRef = &esv1beta1.IBMAuthSecretRef{
  185. SecretAPIKey: v1.SecretKeySelector{
  186. Name: "foo",
  187. Key: "bar",
  188. Namespace: &ns,
  189. },
  190. }
  191. err = p.ValidateStore(store)
  192. if err == nil {
  193. t.Errorf(errExpectedErr)
  194. } else if err.Error() != "namespace not allowed with namespaced SecretStore" {
  195. t.Errorf("KeySelector test failed: expected namespace not allowed, got %v", err)
  196. }
  197. // add container auth test
  198. store = &esv1beta1.SecretStore{
  199. Spec: esv1beta1.SecretStoreSpec{
  200. Provider: &esv1beta1.SecretStoreProvider{
  201. IBM: &esv1beta1.IBMProvider{
  202. ServiceURL: &url,
  203. Auth: esv1beta1.IBMAuth{
  204. ContainerAuth: &esv1beta1.IBMAuthContainerAuth{
  205. Profile: "Trusted IAM Profile",
  206. TokenLocation: "/a/path/to/nowhere/that/should/exist",
  207. },
  208. },
  209. },
  210. },
  211. },
  212. }
  213. err = p.ValidateStore(store)
  214. expected := "cannot read container auth token"
  215. if !ErrorContains(err, expected) {
  216. t.Errorf("ProfileSelector test failed: %s, expected: '%s'", err.Error(), expected)
  217. }
  218. }
  219. // test the sm<->gcp interface
  220. // make sure correct values are passed and errors are handled accordingly.
  221. func TestIBMSecretManagerGetSecret(t *testing.T) {
  222. secretString := "changedvalue"
  223. secretUsername := "userName"
  224. secretPassword := "P@ssw0rd"
  225. secretAPIKey := "01234567890"
  226. secretCertificate := "certificate_value"
  227. // good case: default version is set
  228. // key is passed in, output is sent back
  229. setSecretString := func(smtc *secretManagerTestCase) {
  230. secret := &sm.ArbitrarySecret{
  231. SecretType: utilpointer.To(sm.Secret_SecretType_Arbitrary),
  232. Name: utilpointer.To("testyname"),
  233. ID: utilpointer.To(secretUUID),
  234. Payload: &secretString,
  235. }
  236. smtc.name = "good case: default version is set"
  237. smtc.apiOutput = secret
  238. smtc.apiInput.ID = utilpointer.To(secretUUID)
  239. smtc.expectedSecret = secretString
  240. }
  241. // good case: custom version set
  242. setCustomKey := func(smtc *secretManagerTestCase) {
  243. secret := &sm.ArbitrarySecret{
  244. SecretType: utilpointer.To(sm.Secret_SecretType_Arbitrary),
  245. Name: utilpointer.To("testyname"),
  246. ID: utilpointer.To(secretUUID),
  247. Payload: &secretString,
  248. }
  249. smtc.name = "good case: custom version set"
  250. smtc.ref.Key = "arbitrary/" + secretUUID
  251. smtc.apiInput.ID = utilpointer.To(secretUUID)
  252. smtc.apiOutput = secret
  253. smtc.expectedSecret = secretString
  254. }
  255. // bad case: arbitrary type secret which is destroyed
  256. badArbitSecret := func(smtc *secretManagerTestCase) {
  257. secret := &sm.UsernamePasswordSecret{
  258. SecretType: utilpointer.To(sm.Secret_SecretType_UsernamePassword),
  259. Name: utilpointer.To("testyname"),
  260. ID: utilpointer.To(secretUUID),
  261. }
  262. smtc.name = "bad case: username_password type without property"
  263. smtc.apiInput.ID = utilpointer.To(secretUUID)
  264. smtc.apiOutput = secret
  265. smtc.ref.Key = secretUUID
  266. smtc.expectError = "key payload does not exist in secret " + secretUUID
  267. }
  268. // bad case: username_password type without property
  269. secretUserPass := "username_password/" + secretUUID
  270. badSecretUserPass := func(smtc *secretManagerTestCase) {
  271. secret := &sm.UsernamePasswordSecret{
  272. SecretType: utilpointer.To(sm.Secret_SecretType_UsernamePassword),
  273. Name: utilpointer.To("testyname"),
  274. ID: utilpointer.To(secretUUID),
  275. Username: &secretUsername,
  276. Password: &secretPassword,
  277. }
  278. smtc.name = "bad case: username_password type without property"
  279. smtc.apiInput.ID = utilpointer.To(secretUUID)
  280. smtc.apiOutput = secret
  281. smtc.ref.Key = secretUserPass
  282. smtc.expectError = "remoteRef.property required for secret type username_password"
  283. }
  284. // good case: username_password type with property
  285. funcSetUserPass := func(secretName, property, name string) func(smtc *secretManagerTestCase) {
  286. return func(smtc *secretManagerTestCase) {
  287. secret := &sm.UsernamePasswordSecret{
  288. SecretType: utilpointer.To(sm.Secret_SecretType_UsernamePassword),
  289. Name: utilpointer.To("testyname"),
  290. ID: utilpointer.To(secretUUID),
  291. Username: &secretUsername,
  292. Password: &secretPassword,
  293. }
  294. secretMetadata := &sm.UsernamePasswordSecretMetadata{
  295. Name: utilpointer.To("testyname"),
  296. ID: utilpointer.To(secretUUID),
  297. }
  298. smtc.name = name
  299. smtc.apiInput.ID = utilpointer.To(secretUUID)
  300. smtc.apiOutput = secret
  301. smtc.listInput.Search = utilpointer.To("testyname")
  302. smtc.listOutput.Secrets = make([]sm.SecretMetadataIntf, 1)
  303. smtc.listOutput.Secrets[0] = secretMetadata
  304. smtc.ref.Key = "username_password/" + secretName
  305. smtc.ref.Property = property
  306. if property == "username" {
  307. smtc.expectedSecret = secretUsername
  308. } else {
  309. smtc.expectedSecret = secretPassword
  310. }
  311. }
  312. }
  313. setSecretUserPassByID := funcSetUserPass(secretUUID, "username", "good case: username_password type - get username by ID")
  314. setSecretUserPassUsername := funcSetUserPass("testyname", "username", "good case: username_password type - get username by secret name")
  315. setSecretUserPassPassword := funcSetUserPass("testyname", "password", "good case: username_password type - get password by secret name")
  316. // good case: iam_credentials type
  317. funcSetSecretIam := func(secretName, name string) func(*secretManagerTestCase) {
  318. return func(smtc *secretManagerTestCase) {
  319. secret := &sm.IAMCredentialsSecret{
  320. SecretType: utilpointer.To(sm.Secret_SecretType_IamCredentials),
  321. Name: utilpointer.To("testyname"),
  322. ID: utilpointer.To(secretUUID),
  323. ApiKey: utilpointer.To(secretAPIKey),
  324. }
  325. secretMetadata := &sm.IAMCredentialsSecretMetadata{
  326. Name: utilpointer.To("testyname"),
  327. ID: utilpointer.To(secretUUID),
  328. }
  329. smtc.apiInput.ID = utilpointer.To(secretUUID)
  330. smtc.name = name
  331. smtc.apiOutput = secret
  332. smtc.listInput.Search = utilpointer.To("testyname")
  333. smtc.listOutput.Secrets = make([]sm.SecretMetadataIntf, 1)
  334. smtc.listOutput.Secrets[0] = secretMetadata
  335. smtc.ref.Key = iamCredentialsSecret + secretName
  336. smtc.expectedSecret = secretAPIKey
  337. }
  338. }
  339. setSecretIamByID := funcSetSecretIam(secretUUID, "good case: iam_credenatials type - get API Key by ID")
  340. setSecretIamByName := funcSetSecretIam("testyname", "good case: iam_credenatials type - get API Key by name")
  341. funcSetSecretIamNew := func(secretName, groupName, name string) func(*secretManagerTestCase) {
  342. return func(smtc *secretManagerTestCase) {
  343. secret := &sm.IAMCredentialsSecret{
  344. SecretType: utilpointer.To(sm.Secret_SecretType_IamCredentials),
  345. Name: utilpointer.To("testyname"),
  346. ID: utilpointer.To(secretUUID),
  347. ApiKey: utilpointer.To(secretAPIKey),
  348. }
  349. smtc.getByNameInput.Name = &secretName
  350. smtc.getByNameInput.SecretGroupName = &groupName
  351. smtc.getByNameInput.SecretType = utilpointer.To(sm.Secret_SecretType_IamCredentials)
  352. smtc.name = name
  353. smtc.getByNameOutput = secret
  354. smtc.ref.Key = groupName + "/" + iamCredentialsSecret + secretName
  355. smtc.expectedSecret = secretAPIKey
  356. }
  357. }
  358. setSecretIamByNameNew := funcSetSecretIamNew("testyname", "testGroup", "good case: iam_credenatials type - get API Key by name - new mechanism")
  359. funcSetCertSecretTest := func(secret sm.SecretIntf, name, certType string, good bool) func(*secretManagerTestCase) {
  360. return func(smtc *secretManagerTestCase) {
  361. smtc.name = name
  362. smtc.apiInput.ID = utilpointer.To(secretUUID)
  363. smtc.apiOutput = secret
  364. smtc.ref.Key = certType + "/" + secretUUID
  365. if good {
  366. smtc.ref.Property = "certificate"
  367. smtc.expectedSecret = secretCertificate
  368. } else {
  369. smtc.expectError = "remoteRef.property required for secret type " + certType
  370. }
  371. }
  372. }
  373. // good case: imported_cert type with property
  374. importedCert := &sm.ImportedCertificate{
  375. SecretType: utilpointer.To(sm.Secret_SecretType_ImportedCert),
  376. Name: utilpointer.To("testyname"),
  377. ID: utilpointer.To(secretUUID),
  378. Certificate: utilpointer.To(secretCertificate),
  379. Intermediate: utilpointer.To("intermediate"),
  380. PrivateKey: utilpointer.To("private_key"),
  381. }
  382. setSecretCert := funcSetCertSecretTest(importedCert, "good case: imported_cert type with property", sm.Secret_SecretType_ImportedCert, true)
  383. // good case: imported_cert type without a private_key
  384. importedCertNoPvtKey := func(smtc *secretManagerTestCase) {
  385. secret := &sm.ImportedCertificate{
  386. SecretType: utilpointer.To(sm.Secret_SecretType_ImportedCert),
  387. Name: utilpointer.To("testyname"),
  388. ID: utilpointer.To(secretUUID),
  389. Certificate: utilpointer.To(secretCertificate),
  390. }
  391. smtc.name = "good case: imported cert without private key"
  392. smtc.apiInput.ID = utilpointer.To(secretUUID)
  393. smtc.apiOutput = secret
  394. smtc.ref.Key = "imported_cert/" + secretUUID
  395. smtc.ref.Property = "private_key"
  396. smtc.expectedSecret = ""
  397. }
  398. // bad case: imported_cert type without property
  399. badSecretCert := funcSetCertSecretTest(importedCert, "bad case: imported_cert type without property", sm.Secret_SecretType_ImportedCert, false)
  400. // good case: public_cert type with property
  401. publicCert := &sm.PublicCertificate{
  402. SecretType: utilpointer.To(sm.Secret_SecretType_PublicCert),
  403. Name: utilpointer.To("testyname"),
  404. ID: utilpointer.To(secretUUID),
  405. Certificate: utilpointer.To(secretCertificate),
  406. Intermediate: utilpointer.To("intermediate"),
  407. PrivateKey: utilpointer.To("private_key"),
  408. }
  409. setSecretPublicCert := funcSetCertSecretTest(publicCert, "good case: public_cert type with property", sm.Secret_SecretType_PublicCert, true)
  410. // bad case: public_cert type without property
  411. badSecretPublicCert := funcSetCertSecretTest(publicCert, "bad case: public_cert type without property", sm.Secret_SecretType_PublicCert, false)
  412. // good case: private_cert type with property
  413. privateCert := &sm.PrivateCertificate{
  414. SecretType: utilpointer.To(sm.Secret_SecretType_PublicCert),
  415. Name: utilpointer.To("testyname"),
  416. ID: utilpointer.To(secretUUID),
  417. Certificate: utilpointer.To(secretCertificate),
  418. PrivateKey: utilpointer.To("private_key"),
  419. }
  420. setSecretPrivateCert := funcSetCertSecretTest(privateCert, "good case: private_cert type with property", sm.Secret_SecretType_PrivateCert, true)
  421. // bad case: private_cert type without property
  422. badSecretPrivateCert := funcSetCertSecretTest(privateCert, "bad case: private_cert type without property", sm.Secret_SecretType_PrivateCert, false)
  423. secretDataKV := make(map[string]interface{})
  424. secretDataKV["key1"] = "val1"
  425. secretDataKVComplex := make(map[string]interface{})
  426. secretKVComplex := `{"key1":"val1","key2":"val2","key3":"val3","keyC":{"keyC1":"valC1","keyC2":"valC2"},"special.log":"file-content"}`
  427. json.Unmarshal([]byte(secretKVComplex), &secretDataKVComplex)
  428. secretKV := "kv/" + secretUUID
  429. // bad case: kv type with key which is not in payload
  430. badSecretKV := func(smtc *secretManagerTestCase) {
  431. secret := &sm.KVSecret{
  432. SecretType: utilpointer.To(sm.Secret_SecretType_Kv),
  433. Name: utilpointer.To("testyname"),
  434. ID: utilpointer.To(secretUUID),
  435. Data: secretDataKV,
  436. }
  437. smtc.name = "bad case: kv type with key which is not in payload"
  438. smtc.apiInput.ID = utilpointer.To(secretUUID)
  439. smtc.apiOutput = secret
  440. smtc.ref.Key = secretKV
  441. smtc.ref.Property = "other-key"
  442. smtc.expectError = "key other-key does not exist in secret kv/" + secretUUID
  443. }
  444. // good case: kv type with property
  445. setSecretKV := func(smtc *secretManagerTestCase) {
  446. secret := &sm.KVSecret{
  447. SecretType: utilpointer.To(sm.Secret_SecretType_Kv),
  448. Name: utilpointer.To("testyname"),
  449. ID: utilpointer.To(secretUUID),
  450. Data: secretDataKV,
  451. }
  452. smtc.name = "good case: kv type with property"
  453. smtc.apiInput.ID = utilpointer.To(secretUUID)
  454. smtc.apiOutput = secret
  455. smtc.ref.Key = secretKV
  456. smtc.ref.Property = "key1"
  457. smtc.expectedSecret = "val1"
  458. }
  459. // good case: kv type with property, returns specific value
  460. setSecretKVWithKey := func(smtc *secretManagerTestCase) {
  461. secret := &sm.KVSecret{
  462. SecretType: utilpointer.To(sm.Secret_SecretType_Kv),
  463. Name: utilpointer.To("testyname"),
  464. ID: utilpointer.To(secretUUID),
  465. Data: secretDataKVComplex,
  466. }
  467. smtc.name = "good case: kv type with property, returns specific value"
  468. smtc.apiInput.ID = utilpointer.To(secretUUID)
  469. smtc.apiOutput = secret
  470. smtc.ref.Key = secretKV
  471. smtc.ref.Property = "key2"
  472. smtc.expectedSecret = "val2"
  473. }
  474. // good case: kv type with property and path, returns specific value
  475. setSecretKVWithKeyPath := func(smtc *secretManagerTestCase) {
  476. secret := &sm.KVSecret{
  477. SecretType: utilpointer.To(sm.Secret_SecretType_Kv),
  478. Name: utilpointer.To("testyname"),
  479. ID: utilpointer.To(secretUUID),
  480. Data: secretDataKVComplex,
  481. }
  482. smtc.name = "good case: kv type with property and path, returns specific value"
  483. smtc.apiInput.ID = utilpointer.To(secretUUID)
  484. smtc.apiOutput = secret
  485. smtc.ref.Key = secretKV
  486. smtc.ref.Property = "keyC.keyC2"
  487. smtc.expectedSecret = "valC2"
  488. }
  489. // good case: kv type with property and dot, returns specific value
  490. setSecretKVWithKeyDot := func(smtc *secretManagerTestCase) {
  491. secret := &sm.KVSecret{
  492. SecretType: utilpointer.To(sm.Secret_SecretType_Kv),
  493. Name: utilpointer.To("testyname"),
  494. ID: utilpointer.To(secretUUID),
  495. Data: secretDataKVComplex,
  496. }
  497. smtc.name = "good case: kv type with property and dot, returns specific value"
  498. smtc.apiInput.ID = utilpointer.To(secretUUID)
  499. smtc.apiOutput = secret
  500. smtc.ref.Key = secretKV
  501. smtc.ref.Property = "special.log"
  502. smtc.expectedSecret = "file-content"
  503. }
  504. // good case: kv type without property, returns all
  505. setSecretKVWithOutKey := func(smtc *secretManagerTestCase) {
  506. secret := &sm.KVSecret{
  507. SecretType: utilpointer.To(sm.Secret_SecretType_Kv),
  508. Name: utilpointer.To("testyname"),
  509. ID: utilpointer.To(secretUUID),
  510. Data: secretDataKVComplex,
  511. }
  512. smtc.name = "good case: kv type without property, returns all"
  513. smtc.apiInput.ID = utilpointer.To(secretUUID)
  514. smtc.apiOutput = secret
  515. smtc.ref.Key = secretKV
  516. smtc.expectedSecret = secretKVComplex
  517. }
  518. successCases := []*secretManagerTestCase{
  519. makeValidSecretManagerTestCaseCustom(setSecretString),
  520. makeValidSecretManagerTestCaseCustom(setCustomKey),
  521. makeValidSecretManagerTestCaseCustom(badArbitSecret),
  522. makeValidSecretManagerTestCaseCustom(setAPIErr),
  523. makeValidSecretManagerTestCaseCustom(setNilMockClient),
  524. makeValidSecretManagerTestCaseCustom(badSecretUserPass),
  525. makeValidSecretManagerTestCaseCustom(setSecretUserPassByID),
  526. makeValidSecretManagerTestCaseCustom(setSecretUserPassUsername),
  527. makeValidSecretManagerTestCaseCustom(setSecretUserPassPassword),
  528. makeValidSecretManagerTestCaseCustom(setSecretIamByID),
  529. makeValidSecretManagerTestCaseCustom(setSecretIamByName),
  530. makeValidSecretManagerTestCaseCustom(setSecretCert),
  531. makeValidSecretManagerTestCaseCustom(setSecretKV),
  532. makeValidSecretManagerTestCaseCustom(setSecretKVWithKey),
  533. makeValidSecretManagerTestCaseCustom(setSecretKVWithKeyPath),
  534. makeValidSecretManagerTestCaseCustom(setSecretKVWithKeyDot),
  535. makeValidSecretManagerTestCaseCustom(setSecretKVWithOutKey),
  536. makeValidSecretManagerTestCaseCustom(badSecretKV),
  537. makeValidSecretManagerTestCaseCustom(badSecretCert),
  538. makeValidSecretManagerTestCaseCustom(importedCertNoPvtKey),
  539. makeValidSecretManagerTestCaseCustom(setSecretPublicCert),
  540. makeValidSecretManagerTestCaseCustom(badSecretPublicCert),
  541. makeValidSecretManagerTestCaseCustom(setSecretPrivateCert),
  542. makeValidSecretManagerTestCaseCustom(badSecretPrivateCert),
  543. makeValidSecretManagerTestCaseCustom(setSecretIamByNameNew),
  544. }
  545. sm := providerIBM{}
  546. for _, v := range successCases {
  547. t.Run(v.name, func(t *testing.T) {
  548. sm.IBMClient = v.mockClient
  549. sm.cache = NewCache(10, 1*time.Minute)
  550. out, err := sm.GetSecret(context.Background(), *v.ref)
  551. if !ErrorContains(err, v.expectError) {
  552. t.Errorf("unexpected error:\n%s, expected:\n'%s'", err.Error(), v.expectError)
  553. }
  554. if string(out) != v.expectedSecret {
  555. t.Errorf("unexpected secret: expected:\n%s\ngot:\n%s", v.expectedSecret, string(out))
  556. }
  557. })
  558. }
  559. }
  560. func TestGetSecretMap(t *testing.T) {
  561. secretUsername := "user1"
  562. secretPassword := "P@ssw0rd"
  563. secretAPIKey := "01234567890"
  564. nilValue := "<nil>"
  565. secretCertificate := "certificate_value"
  566. secretPrivateKey := "private_key_value"
  567. secretIntermediate := "intermediate_value"
  568. timeValue := "0001-01-01T00:00:00.000Z"
  569. secretComplex := map[string]interface{}{
  570. "key1": "val1",
  571. "key2": "val2",
  572. "keyC": map[string]interface{}{
  573. "keyC1": map[string]string{
  574. "keyA": "valA",
  575. "keyB": "valB",
  576. },
  577. },
  578. }
  579. // good case: arbitrary
  580. setArbitrary := func(smtc *secretManagerTestCase) {
  581. payload := `{"foo":"bar"}`
  582. secret := &sm.ArbitrarySecret{
  583. Name: utilpointer.To("testyname"),
  584. ID: utilpointer.To(secretUUID),
  585. SecretType: utilpointer.To(sm.Secret_SecretType_Arbitrary),
  586. Payload: &payload,
  587. }
  588. smtc.name = "good case: arbitrary"
  589. smtc.apiInput.ID = utilpointer.To(secretUUID)
  590. smtc.apiOutput = secret
  591. smtc.ref.Key = secretUUID
  592. smtc.expectedData["arbitrary"] = []byte(payload)
  593. }
  594. // good case: username_password
  595. setSecretUserPass := func(smtc *secretManagerTestCase) {
  596. secret := &sm.UsernamePasswordSecret{
  597. Name: utilpointer.To("testyname"),
  598. ID: utilpointer.To(secretUUID),
  599. SecretType: utilpointer.To(sm.Secret_SecretType_UsernamePassword),
  600. Username: &secretUsername,
  601. Password: &secretPassword,
  602. }
  603. smtc.name = "good case: username_password"
  604. smtc.apiInput.ID = utilpointer.To(secretUUID)
  605. smtc.apiOutput = secret
  606. smtc.ref.Key = "username_password/" + secretUUID
  607. smtc.expectedData["username"] = []byte(secretUsername)
  608. smtc.expectedData["password"] = []byte(secretPassword)
  609. }
  610. // good case: iam_credentials
  611. setSecretIam := func(smtc *secretManagerTestCase) {
  612. secret := &sm.IAMCredentialsSecret{
  613. Name: utilpointer.To("testyname"),
  614. ID: utilpointer.To(secretUUID),
  615. SecretType: utilpointer.To(sm.Secret_SecretType_IamCredentials),
  616. ApiKey: utilpointer.To(secretAPIKey),
  617. }
  618. smtc.name = "good case: iam_credentials"
  619. smtc.apiInput.ID = utilpointer.To(secretUUID)
  620. smtc.apiOutput = secret
  621. smtc.ref.Key = iamCredentialsSecret + secretUUID
  622. smtc.expectedData["apikey"] = []byte(secretAPIKey)
  623. }
  624. // good case: iam_credentials by name using new mechanism
  625. setSecretIamByName := func(smtc *secretManagerTestCase) {
  626. secret := &sm.IAMCredentialsSecret{
  627. Name: utilpointer.To("testyname"),
  628. ID: utilpointer.To(secretUUID),
  629. SecretType: utilpointer.To(sm.Secret_SecretType_IamCredentials),
  630. ApiKey: utilpointer.To(secretAPIKey),
  631. }
  632. smtc.name = "good case: iam_credentials by name using new mechanism"
  633. smtc.getByNameInput.Name = utilpointer.To("testyname")
  634. smtc.getByNameInput.SecretGroupName = utilpointer.To("groupName")
  635. smtc.getByNameInput.SecretType = utilpointer.To(sm.Secret_SecretType_IamCredentials)
  636. smtc.getByNameOutput = secret
  637. smtc.apiOutput = secret
  638. smtc.ref.Key = "groupName/" + iamCredentialsSecret + "testyname"
  639. smtc.expectedData["apikey"] = []byte(secretAPIKey)
  640. }
  641. // bad case: iam_credentials of a destroyed secret
  642. badSecretIam := func(smtc *secretManagerTestCase) {
  643. secret := &sm.IAMCredentialsSecret{
  644. Name: utilpointer.To("testyname"),
  645. ID: utilpointer.To(secretUUID),
  646. SecretType: utilpointer.To(sm.Secret_SecretType_IamCredentials),
  647. }
  648. smtc.name = "bad case: iam_credentials of a destroyed secret"
  649. smtc.apiInput.ID = utilpointer.To(secretUUID)
  650. smtc.apiOutput = secret
  651. smtc.ref.Key = iamCredentialsSecret + secretUUID
  652. smtc.expectError = "key api_key does not exist in secret " + secretUUID
  653. }
  654. funcCertTest := func(secret sm.SecretIntf, name, certType string) func(*secretManagerTestCase) {
  655. return func(smtc *secretManagerTestCase) {
  656. smtc.name = name
  657. smtc.apiInput.ID = utilpointer.To(secretUUID)
  658. smtc.apiOutput = secret
  659. smtc.ref.Key = certType + "/" + secretUUID
  660. smtc.expectedData["certificate"] = []byte(secretCertificate)
  661. smtc.expectedData["private_key"] = []byte(secretPrivateKey)
  662. smtc.expectedData["intermediate"] = []byte(secretIntermediate)
  663. }
  664. }
  665. // good case: imported_cert
  666. importedCert := &sm.ImportedCertificate{
  667. SecretType: utilpointer.To(sm.Secret_SecretType_ImportedCert),
  668. Name: utilpointer.To("testyname"),
  669. ID: utilpointer.To(secretUUID),
  670. Certificate: utilpointer.To(secretCertificate),
  671. Intermediate: utilpointer.To(secretIntermediate),
  672. PrivateKey: utilpointer.To(secretPrivateKey),
  673. }
  674. setSecretCert := funcCertTest(importedCert, "good case: imported_cert", sm.Secret_SecretType_ImportedCert)
  675. // good case: public_cert
  676. publicCert := &sm.PublicCertificate{
  677. SecretType: utilpointer.To(sm.Secret_SecretType_PublicCert),
  678. Name: utilpointer.To("testyname"),
  679. ID: utilpointer.To(secretUUID),
  680. Certificate: utilpointer.To(secretCertificate),
  681. Intermediate: utilpointer.To(secretIntermediate),
  682. PrivateKey: utilpointer.To(secretPrivateKey),
  683. }
  684. setSecretPublicCert := funcCertTest(publicCert, "good case: public_cert", sm.Secret_SecretType_PublicCert)
  685. // good case: private_cert
  686. setSecretPrivateCert := func(smtc *secretManagerTestCase) {
  687. secret := &sm.PrivateCertificate{
  688. Name: utilpointer.To("testyname"),
  689. ID: utilpointer.To(secretUUID),
  690. SecretType: utilpointer.To(sm.Secret_SecretType_PrivateCert),
  691. Certificate: &secretCertificate,
  692. PrivateKey: &secretPrivateKey,
  693. }
  694. smtc.name = "good case: private_cert"
  695. smtc.apiInput.ID = utilpointer.To(secretUUID)
  696. smtc.apiOutput = secret
  697. smtc.ref.Key = "private_cert/" + secretUUID
  698. smtc.expectedData["certificate"] = []byte(secretCertificate)
  699. smtc.expectedData["private_key"] = []byte(secretPrivateKey)
  700. }
  701. // good case: arbitrary with metadata
  702. setArbitraryWithMetadata := func(smtc *secretManagerTestCase) {
  703. payload := `{"foo":"bar"}`
  704. secret := &sm.ArbitrarySecret{
  705. CreatedBy: utilpointer.To("testCreatedBy"),
  706. CreatedAt: &strfmt.DateTime{},
  707. Downloaded: utilpointer.To(false),
  708. Labels: []string{"abc", "def", "xyz"},
  709. LocksTotal: utilpointer.To(int64(20)),
  710. Payload: &payload,
  711. }
  712. smtc.name = "good case: arbitrary with metadata"
  713. smtc.apiInput.ID = utilpointer.To(secretUUID)
  714. smtc.apiOutput = secret
  715. smtc.ref.Key = secretUUID
  716. smtc.ref.MetadataPolicy = esv1beta1.ExternalSecretMetadataPolicyFetch
  717. smtc.expectedData = map[string][]byte{
  718. "arbitrary": []byte(payload),
  719. "created_at": []byte(timeValue),
  720. "created_by": []byte(*secret.CreatedBy),
  721. "crn": []byte(nilValue),
  722. "downloaded": []byte(strconv.FormatBool(*secret.Downloaded)),
  723. "id": []byte(nilValue),
  724. "labels": []byte("[" + strings.Join(secret.Labels, " ") + "]"),
  725. "locks_total": []byte(strconv.Itoa(int(*secret.LocksTotal))),
  726. "payload": []byte(payload),
  727. "secret_group_id": []byte(nilValue),
  728. "secret_type": []byte(nilValue),
  729. "updated_at": []byte(nilValue),
  730. "versions_total": []byte(nilValue),
  731. }
  732. }
  733. // good case: iam_credentials with metadata
  734. setSecretIamWithMetadata := func(smtc *secretManagerTestCase) {
  735. secret := &sm.IAMCredentialsSecret{
  736. CreatedBy: utilpointer.To("testCreatedBy"),
  737. CreatedAt: &strfmt.DateTime{},
  738. Downloaded: utilpointer.To(false),
  739. Labels: []string{"abc", "def", "xyz"},
  740. LocksTotal: utilpointer.To(int64(20)),
  741. ApiKey: utilpointer.To(secretAPIKey),
  742. }
  743. smtc.name = "good case: iam_credentials with metadata"
  744. smtc.apiInput.ID = utilpointer.To(secretUUID)
  745. smtc.apiOutput = secret
  746. smtc.ref.Key = iamCredentialsSecret + secretUUID
  747. smtc.ref.MetadataPolicy = esv1beta1.ExternalSecretMetadataPolicyFetch
  748. smtc.expectedData = map[string][]byte{
  749. "api_key": []byte(secretAPIKey),
  750. "apikey": []byte(secretAPIKey),
  751. "created_at": []byte(timeValue),
  752. "created_by": []byte(*secret.CreatedBy),
  753. "crn": []byte(nilValue),
  754. "downloaded": []byte(strconv.FormatBool(*secret.Downloaded)),
  755. "id": []byte(nilValue),
  756. "labels": []byte("[" + strings.Join(secret.Labels, " ") + "]"),
  757. "locks_total": []byte(strconv.Itoa(int(*secret.LocksTotal))),
  758. "reuse_api_key": []byte(nilValue),
  759. "secret_group_id": []byte(nilValue),
  760. "secret_type": []byte(nilValue),
  761. "ttl": []byte(nilValue),
  762. "updated_at": []byte(nilValue),
  763. "versions_total": []byte(nilValue),
  764. }
  765. }
  766. // "good case: username_password with metadata
  767. setSecretUserPassWithMetadata := func(smtc *secretManagerTestCase) {
  768. secret := &sm.UsernamePasswordSecret{
  769. CreatedBy: utilpointer.To("testCreatedBy"),
  770. CreatedAt: &strfmt.DateTime{},
  771. Downloaded: utilpointer.To(false),
  772. Labels: []string{"abc", "def", "xyz"},
  773. LocksTotal: utilpointer.To(int64(20)),
  774. Username: &secretUsername,
  775. Password: &secretPassword,
  776. }
  777. smtc.name = "good case: username_password with metadata"
  778. smtc.apiInput.ID = utilpointer.To(secretUUID)
  779. smtc.apiOutput = secret
  780. smtc.ref.Key = "username_password/" + secretUUID
  781. smtc.expectedData["username"] = []byte(secretUsername)
  782. smtc.expectedData["password"] = []byte(secretPassword)
  783. smtc.ref.MetadataPolicy = esv1beta1.ExternalSecretMetadataPolicyFetch
  784. smtc.expectedData = map[string][]byte{
  785. "created_at": []byte(timeValue),
  786. "created_by": []byte(*secret.CreatedBy),
  787. "crn": []byte(nilValue),
  788. "downloaded": []byte(strconv.FormatBool(*secret.Downloaded)),
  789. "id": []byte(nilValue),
  790. "labels": []byte("[" + strings.Join(secret.Labels, " ") + "]"),
  791. "locks_total": []byte(strconv.Itoa(int(*secret.LocksTotal))),
  792. "password": []byte(secretPassword),
  793. "rotation": []byte(nilValue),
  794. "secret_group_id": []byte(nilValue),
  795. "secret_type": []byte(nilValue),
  796. "updated_at": []byte(nilValue),
  797. "username": []byte(secretUsername),
  798. "versions_total": []byte(nilValue),
  799. }
  800. }
  801. // good case: imported_cert with metadata
  802. setimportedCertWithMetadata := func(smtc *secretManagerTestCase) {
  803. secret := &sm.ImportedCertificate{
  804. CreatedBy: utilpointer.To("testCreatedBy"),
  805. CreatedAt: &strfmt.DateTime{},
  806. Downloaded: utilpointer.To(false),
  807. Labels: []string{"abc", "def", "xyz"},
  808. LocksTotal: utilpointer.To(int64(20)),
  809. Certificate: utilpointer.To(secretCertificate),
  810. Intermediate: utilpointer.To(secretIntermediate),
  811. PrivateKey: utilpointer.To(secretPrivateKey),
  812. }
  813. smtc.name = "good case: imported_cert with metadata"
  814. smtc.apiInput.ID = utilpointer.To(secretUUID)
  815. smtc.apiOutput = secret
  816. smtc.ref.Key = "imported_cert" + "/" + secretUUID
  817. smtc.ref.MetadataPolicy = esv1beta1.ExternalSecretMetadataPolicyFetch
  818. smtc.expectedData = map[string][]byte{
  819. "certificate": []byte(secretCertificate),
  820. "created_at": []byte(timeValue),
  821. "created_by": []byte(*secret.CreatedBy),
  822. "crn": []byte(nilValue),
  823. "downloaded": []byte(strconv.FormatBool(*secret.Downloaded)),
  824. "expiration_date": []byte(nilValue),
  825. "id": []byte(nilValue),
  826. "intermediate": []byte(secretIntermediate),
  827. "intermediate_included": []byte(nilValue),
  828. "issuer": []byte(nilValue),
  829. "labels": []byte("[" + strings.Join(secret.Labels, " ") + "]"),
  830. "locks_total": []byte(strconv.Itoa(int(*secret.LocksTotal))),
  831. "private_key": []byte(secretPrivateKey),
  832. "private_key_included": []byte(nilValue),
  833. "secret_group_id": []byte(nilValue),
  834. "secret_type": []byte(nilValue),
  835. "serial_number": []byte(nilValue),
  836. "signing_algorithm": []byte(nilValue),
  837. "updated_at": []byte(nilValue),
  838. "validity": []byte(nilValue),
  839. "versions_total": []byte(nilValue),
  840. }
  841. }
  842. // good case: imported_cert without a private_key
  843. setimportedCertWithNoPvtKey := func(smtc *secretManagerTestCase) {
  844. secret := &sm.ImportedCertificate{
  845. CreatedBy: utilpointer.To("testCreatedBy"),
  846. CreatedAt: &strfmt.DateTime{},
  847. Downloaded: utilpointer.To(false),
  848. Labels: []string{"abc", "def", "xyz"},
  849. LocksTotal: utilpointer.To(int64(20)),
  850. Certificate: utilpointer.To(secretCertificate),
  851. Intermediate: utilpointer.To(secretIntermediate),
  852. }
  853. smtc.name = "good case: imported_cert without private key"
  854. smtc.apiInput.ID = utilpointer.To(secretUUID)
  855. smtc.apiOutput = secret
  856. smtc.ref.Key = "imported_cert/" + secretUUID
  857. smtc.expectedData = map[string][]byte{
  858. "certificate": []byte(secretCertificate),
  859. "intermediate": []byte(secretIntermediate),
  860. "private_key": []byte(""),
  861. }
  862. }
  863. // good case: public_cert with metadata
  864. setPublicCertWithMetadata := func(smtc *secretManagerTestCase) {
  865. secret := &sm.PublicCertificate{
  866. CreatedBy: utilpointer.To("testCreatedBy"),
  867. CreatedAt: &strfmt.DateTime{},
  868. Downloaded: utilpointer.To(false),
  869. Labels: []string{"abc", "def", "xyz"},
  870. LocksTotal: utilpointer.To(int64(20)),
  871. Certificate: utilpointer.To(secretCertificate),
  872. Intermediate: utilpointer.To(secretIntermediate),
  873. PrivateKey: utilpointer.To(secretPrivateKey),
  874. }
  875. smtc.name = "good case: public_cert with metadata"
  876. smtc.apiInput.ID = utilpointer.To(secretUUID)
  877. smtc.apiOutput = secret
  878. smtc.ref.Key = "public_cert" + "/" + secretUUID
  879. smtc.ref.MetadataPolicy = esv1beta1.ExternalSecretMetadataPolicyFetch
  880. smtc.expectedData = map[string][]byte{
  881. "certificate": []byte(secretCertificate),
  882. "common_name": []byte(nilValue),
  883. "created_at": []byte(timeValue),
  884. "created_by": []byte(*secret.CreatedBy),
  885. "crn": []byte(nilValue),
  886. "downloaded": []byte(strconv.FormatBool(*secret.Downloaded)),
  887. "id": []byte(nilValue),
  888. "intermediate": []byte(secretIntermediate),
  889. "key_algorithm": []byte(nilValue),
  890. "labels": []byte("[" + strings.Join(secret.Labels, " ") + "]"),
  891. "locks_total": []byte(strconv.Itoa(int(*secret.LocksTotal))),
  892. "private_key": []byte(secretPrivateKey),
  893. "rotation": []byte(nilValue),
  894. "secret_group_id": []byte(nilValue),
  895. "secret_type": []byte(nilValue),
  896. "updated_at": []byte(nilValue),
  897. "versions_total": []byte(nilValue),
  898. }
  899. }
  900. // good case: private_cert with metadata
  901. setPrivateCertWithMetadata := func(smtc *secretManagerTestCase) {
  902. secret := &sm.PrivateCertificate{
  903. CreatedBy: utilpointer.To("testCreatedBy"),
  904. CreatedAt: &strfmt.DateTime{},
  905. Downloaded: utilpointer.To(false),
  906. Labels: []string{"abc", "def", "xyz"},
  907. LocksTotal: utilpointer.To(int64(20)),
  908. Certificate: utilpointer.To(secretCertificate),
  909. PrivateKey: utilpointer.To(secretPrivateKey),
  910. }
  911. smtc.name = "good case: private_cert with metadata"
  912. smtc.apiInput.ID = utilpointer.To(secretUUID)
  913. smtc.apiOutput = secret
  914. smtc.ref.Key = "private_cert" + "/" + secretUUID
  915. smtc.ref.MetadataPolicy = esv1beta1.ExternalSecretMetadataPolicyFetch
  916. smtc.expectedData = map[string][]byte{
  917. "certificate": []byte(secretCertificate),
  918. "certificate_template": []byte(nilValue),
  919. "common_name": []byte(nilValue),
  920. "created_at": []byte(timeValue),
  921. "created_by": []byte(*secret.CreatedBy),
  922. "crn": []byte(nilValue),
  923. "downloaded": []byte(strconv.FormatBool(*secret.Downloaded)),
  924. "expiration_date": []byte(nilValue),
  925. "id": []byte(nilValue),
  926. "issuer": []byte(nilValue),
  927. "labels": []byte("[" + strings.Join(secret.Labels, " ") + "]"),
  928. "locks_total": []byte(strconv.Itoa(int(*secret.LocksTotal))),
  929. "private_key": []byte(secretPrivateKey),
  930. "secret_group_id": []byte(nilValue),
  931. "secret_type": []byte(nilValue),
  932. "serial_number": []byte(nilValue),
  933. "signing_algorithm": []byte(nilValue),
  934. "updated_at": []byte(nilValue),
  935. "validity": []byte(nilValue),
  936. "versions_total": []byte(nilValue),
  937. }
  938. }
  939. // good case: kv with property and metadata
  940. setSecretKVWithMetadata := func(smtc *secretManagerTestCase) {
  941. secret := &sm.KVSecret{
  942. CreatedBy: utilpointer.To("testCreatedBy"),
  943. CreatedAt: &strfmt.DateTime{},
  944. Downloaded: utilpointer.To(false),
  945. Labels: []string{"abc", "def", "xyz"},
  946. LocksTotal: utilpointer.To(int64(20)),
  947. Data: secretComplex,
  948. }
  949. smtc.name = "good case: kv, with property and with metadata"
  950. smtc.apiInput.ID = core.StringPtr(secretUUID)
  951. smtc.apiOutput = secret
  952. smtc.ref.Key = "kv/" + secretUUID
  953. smtc.ref.MetadataPolicy = esv1beta1.ExternalSecretMetadataPolicyFetch
  954. smtc.expectedData = map[string][]byte{
  955. "created_at": []byte(timeValue),
  956. "created_by": []byte(*secret.CreatedBy),
  957. "crn": []byte(nilValue),
  958. "data": []byte("map[key1:val1 key2:val2 keyC:map[keyC1:map[keyA:valA keyB:valB]]]"),
  959. "downloaded": []byte(strconv.FormatBool(*secret.Downloaded)),
  960. "id": []byte(nilValue),
  961. "key1": []byte("val1"),
  962. "key2": []byte("val2"),
  963. "keyC": []byte(`{"keyC1":{"keyA":"valA","keyB":"valB"}}`),
  964. "labels": []byte("[" + strings.Join(secret.Labels, " ") + "]"),
  965. "locks_total": []byte(strconv.Itoa(int(*secret.LocksTotal))),
  966. "secret_group_id": []byte(nilValue),
  967. "secret_type": []byte(nilValue),
  968. "updated_at": []byte(nilValue),
  969. "versions_total": []byte(nilValue),
  970. }
  971. }
  972. // good case: iam_credentials without metadata
  973. setSecretIamWithoutMetadata := func(smtc *secretManagerTestCase) {
  974. secret := &sm.IAMCredentialsSecret{
  975. CreatedBy: utilpointer.To("testCreatedBy"),
  976. CreatedAt: &strfmt.DateTime{},
  977. Downloaded: utilpointer.To(false),
  978. Labels: []string{"abc", "def", "xyz"},
  979. LocksTotal: utilpointer.To(int64(20)),
  980. ApiKey: utilpointer.To(secretAPIKey),
  981. }
  982. smtc.name = "good case: iam_credentials without metadata"
  983. smtc.apiInput.ID = utilpointer.To(secretUUID)
  984. smtc.apiOutput = secret
  985. smtc.ref.Key = iamCredentialsSecret + secretUUID
  986. smtc.ref.MetadataPolicy = esv1beta1.ExternalSecretMetadataPolicyNone
  987. smtc.expectedData = map[string][]byte{
  988. "apikey": []byte(secretAPIKey),
  989. }
  990. }
  991. secretKeyKV := "kv/" + secretUUID
  992. // good case: kv, no property, return entire payload as key:value pairs
  993. setSecretKV := func(smtc *secretManagerTestCase) {
  994. secret := &sm.KVSecret{
  995. Name: utilpointer.To("testyname"),
  996. ID: utilpointer.To(secretUUID),
  997. SecretType: utilpointer.To(sm.Secret_SecretType_Kv),
  998. Data: secretComplex,
  999. }
  1000. smtc.name = "good case: kv, no property, return entire payload as key:value pairs"
  1001. smtc.apiInput.ID = core.StringPtr(secretUUID)
  1002. smtc.apiOutput = secret
  1003. smtc.ref.Key = secretKeyKV
  1004. smtc.expectedData["key1"] = []byte("val1")
  1005. smtc.expectedData["key2"] = []byte("val2")
  1006. smtc.expectedData["keyC"] = []byte(`{"keyC1":{"keyA":"valA","keyB":"valB"}}`)
  1007. }
  1008. // good case: kv, with property
  1009. setSecretKVWithProperty := func(smtc *secretManagerTestCase) {
  1010. secret := &sm.KVSecret{
  1011. Name: utilpointer.To("d5deb37a-7883-4fe2-a5e7-3c15420adc76"),
  1012. ID: utilpointer.To(secretUUID),
  1013. SecretType: utilpointer.To(sm.Secret_SecretType_Kv),
  1014. Data: secretComplex,
  1015. }
  1016. smtc.name = "good case: kv, with property"
  1017. smtc.apiInput.ID = core.StringPtr(secretUUID)
  1018. smtc.ref.Property = "keyC"
  1019. smtc.apiOutput = secret
  1020. smtc.ref.Key = secretKeyKV
  1021. smtc.expectedData["keyC1"] = []byte(`{"keyA":"valA","keyB":"valB"}`)
  1022. }
  1023. // good case: kv, with property and path
  1024. setSecretKVWithPathAndProperty := func(smtc *secretManagerTestCase) {
  1025. secret := &sm.KVSecret{
  1026. Name: utilpointer.To(secretUUID),
  1027. ID: utilpointer.To(secretUUID),
  1028. SecretType: utilpointer.To(sm.Secret_SecretType_Kv),
  1029. Data: secretComplex,
  1030. }
  1031. smtc.name = "good case: kv, with property and path"
  1032. smtc.apiInput.ID = core.StringPtr(secretUUID)
  1033. smtc.ref.Property = "keyC.keyC1"
  1034. smtc.apiOutput = secret
  1035. smtc.ref.Key = secretKeyKV
  1036. smtc.expectedData["keyA"] = []byte("valA")
  1037. smtc.expectedData["keyB"] = []byte("valB")
  1038. }
  1039. // bad case: kv, with property and path
  1040. badSecretKVWithUnknownProperty := func(smtc *secretManagerTestCase) {
  1041. secret := &sm.KVSecret{
  1042. Name: utilpointer.To("testyname"),
  1043. ID: utilpointer.To(secretUUID),
  1044. SecretType: utilpointer.To(sm.Secret_SecretType_Kv),
  1045. Data: secretComplex,
  1046. }
  1047. smtc.name = "bad case: kv, with property and path"
  1048. smtc.apiInput.ID = core.StringPtr(secretUUID)
  1049. smtc.ref.Property = "unknown.property"
  1050. smtc.apiOutput = secret
  1051. smtc.ref.Key = secretKeyKV
  1052. smtc.expectError = "key unknown.property does not exist in secret " + secretKeyKV
  1053. }
  1054. successCases := []*secretManagerTestCase{
  1055. makeValidSecretManagerTestCaseCustom(badSecretIam),
  1056. makeValidSecretManagerTestCaseCustom(setArbitrary),
  1057. makeValidSecretManagerTestCaseCustom(setNilMockClient),
  1058. makeValidSecretManagerTestCaseCustom(setAPIErr),
  1059. makeValidSecretManagerTestCaseCustom(setSecretUserPass),
  1060. makeValidSecretManagerTestCaseCustom(setSecretIam),
  1061. makeValidSecretManagerTestCaseCustom(setSecretCert),
  1062. makeValidSecretManagerTestCaseCustom(setSecretKV),
  1063. makeValidSecretManagerTestCaseCustom(setSecretKVWithProperty),
  1064. makeValidSecretManagerTestCaseCustom(setSecretKVWithPathAndProperty),
  1065. makeValidSecretManagerTestCaseCustom(badSecretKVWithUnknownProperty),
  1066. makeValidSecretManagerTestCaseCustom(setSecretPublicCert),
  1067. makeValidSecretManagerTestCaseCustom(setSecretPrivateCert),
  1068. makeValidSecretManagerTestCaseCustom(setimportedCertWithNoPvtKey),
  1069. makeValidSecretManagerTestCaseCustom(setSecretIamWithMetadata),
  1070. makeValidSecretManagerTestCaseCustom(setArbitraryWithMetadata),
  1071. makeValidSecretManagerTestCaseCustom(setSecretUserPassWithMetadata),
  1072. makeValidSecretManagerTestCaseCustom(setimportedCertWithMetadata),
  1073. makeValidSecretManagerTestCaseCustom(setPublicCertWithMetadata),
  1074. makeValidSecretManagerTestCaseCustom(setPrivateCertWithMetadata),
  1075. makeValidSecretManagerTestCaseCustom(setSecretKVWithMetadata),
  1076. makeValidSecretManagerTestCaseCustom(setSecretIamWithoutMetadata),
  1077. makeValidSecretManagerTestCaseCustom(setSecretIamByName),
  1078. }
  1079. sm := providerIBM{}
  1080. for _, v := range successCases {
  1081. t.Run(v.name, func(t *testing.T) {
  1082. sm.IBMClient = v.mockClient
  1083. out, err := sm.GetSecretMap(context.Background(), *v.ref)
  1084. if !ErrorContains(err, v.expectError) {
  1085. t.Errorf("unexpected error: %s, expected: '%s'", err.Error(), v.expectError)
  1086. }
  1087. if err == nil && !reflect.DeepEqual(out, v.expectedData) {
  1088. t.Errorf("unexpected secret data: expected:\n%+v\ngot:\n%+v", v.expectedData, out)
  1089. }
  1090. })
  1091. }
  1092. }
  1093. func TestValidRetryInput(t *testing.T) {
  1094. sm := providerIBM{}
  1095. invalid := "Invalid"
  1096. serviceURL := "http://fake-service-url.cool"
  1097. spec := &esv1beta1.SecretStore{
  1098. Spec: esv1beta1.SecretStoreSpec{
  1099. Provider: &esv1beta1.SecretStoreProvider{
  1100. IBM: &esv1beta1.IBMProvider{
  1101. Auth: esv1beta1.IBMAuth{
  1102. SecretRef: &esv1beta1.IBMAuthSecretRef{
  1103. SecretAPIKey: v1.SecretKeySelector{
  1104. Name: "fake-secret",
  1105. Key: "fake-key",
  1106. },
  1107. },
  1108. },
  1109. ServiceURL: &serviceURL,
  1110. },
  1111. },
  1112. RetrySettings: &esv1beta1.SecretStoreRetrySettings{
  1113. RetryInterval: &invalid,
  1114. },
  1115. },
  1116. }
  1117. expected := fmt.Sprintf("cannot setup new ibm client: time: invalid duration %q", invalid)
  1118. ctx := context.TODO()
  1119. kube := clientfake.NewClientBuilder().WithObjects(&corev1.Secret{
  1120. ObjectMeta: metav1.ObjectMeta{
  1121. Name: "fake-secret",
  1122. Namespace: "default",
  1123. },
  1124. Data: map[string][]byte{
  1125. "fake-key": []byte("ImAFakeApiKey"),
  1126. },
  1127. }).Build()
  1128. _, err := sm.NewClient(ctx, spec, kube, "default")
  1129. if !ErrorContains(err, expected) {
  1130. t.Errorf("CheckValidRetryInput unexpected error: %s, expected: '%s'", err.Error(), expected)
  1131. }
  1132. }
  1133. func ErrorContains(out error, want string) bool {
  1134. if out == nil {
  1135. return want == ""
  1136. }
  1137. if want == "" {
  1138. return false
  1139. }
  1140. return strings.Contains(out.Error(), want)
  1141. }