provider_test.go 45 KB

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