client_test.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920
  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 bitwarden
  13. import (
  14. "context"
  15. "reflect"
  16. "testing"
  17. "github.com/stretchr/testify/assert"
  18. corev1 "k8s.io/api/core/v1"
  19. "sigs.k8s.io/controller-runtime/pkg/client"
  20. "sigs.k8s.io/controller-runtime/pkg/client/fake"
  21. "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
  22. "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  23. )
  24. var projectID = "e8fc8f9c-2208-446e-9e89-9bc358f39b47"
  25. func TestProviderDeleteSecret(t *testing.T) {
  26. type fields struct {
  27. kube client.Client
  28. namespace string
  29. store v1beta1.GenericStore
  30. mock func(c *FakeClient)
  31. assertMock func(t *testing.T, c *FakeClient)
  32. }
  33. type args struct {
  34. ctx context.Context
  35. ref v1beta1.PushSecretRemoteRef
  36. }
  37. tests := []struct {
  38. name string
  39. fields fields
  40. args args
  41. wantErr bool
  42. }{
  43. {
  44. name: "delete secret is successfully with UUID",
  45. fields: fields{
  46. namespace: "default",
  47. store: &v1beta1.SecretStore{
  48. Spec: v1beta1.SecretStoreSpec{
  49. Provider: &v1beta1.SecretStoreProvider{
  50. BitwardenSecretsManager: &v1beta1.BitwardenSecretsManagerProvider{
  51. OrganizationID: "orgid",
  52. ProjectID: projectID,
  53. },
  54. },
  55. },
  56. },
  57. mock: func(c *FakeClient) {
  58. c.DeleteSecretReturnsOnCallN(0, &SecretsDeleteResponse{})
  59. },
  60. assertMock: func(t *testing.T, c *FakeClient) {
  61. assert.Equal(t, 1, c.deleteSecretCalledN)
  62. },
  63. },
  64. args: args{
  65. ctx: context.TODO(),
  66. ref: v1alpha1.PushSecretRemoteRef{
  67. RemoteKey: "d8f29773-3019-4973-9bbc-66327d077fe2",
  68. },
  69. },
  70. },
  71. {
  72. name: "delete secret by name",
  73. fields: fields{
  74. namespace: "default",
  75. store: &v1beta1.SecretStore{
  76. Spec: v1beta1.SecretStoreSpec{
  77. Provider: &v1beta1.SecretStoreProvider{
  78. BitwardenSecretsManager: &v1beta1.BitwardenSecretsManagerProvider{
  79. OrganizationID: "orgid",
  80. ProjectID: projectID,
  81. },
  82. },
  83. },
  84. },
  85. mock: func(c *FakeClient) {
  86. c.ListSecretReturnsOnCallN(0, &SecretIdentifiersResponse{
  87. Data: []SecretIdentifierResponse{
  88. {
  89. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  90. Key: "this-is-a-name",
  91. OrganizationID: "orgid",
  92. },
  93. },
  94. })
  95. c.GetSecretReturnsOnCallN(0, &SecretResponse{
  96. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  97. Key: "key",
  98. Note: "note",
  99. OrganizationID: "org",
  100. Value: "value",
  101. ProjectID: &projectID,
  102. })
  103. c.DeleteSecretReturnsOnCallN(0, &SecretsDeleteResponse{})
  104. },
  105. assertMock: func(t *testing.T, c *FakeClient) {
  106. assert.Equal(t, 1, c.deleteSecretCalledN)
  107. },
  108. },
  109. args: args{
  110. ctx: context.TODO(),
  111. ref: v1alpha1.PushSecretRemoteRef{
  112. RemoteKey: "d8f29773-3019-4973-9bbc-66327d077fe2",
  113. },
  114. },
  115. },
  116. {
  117. name: "delete secret by name will not delete if something doesn't match",
  118. fields: fields{
  119. namespace: "default",
  120. store: &v1beta1.SecretStore{
  121. Spec: v1beta1.SecretStoreSpec{
  122. Provider: &v1beta1.SecretStoreProvider{
  123. BitwardenSecretsManager: &v1beta1.BitwardenSecretsManagerProvider{
  124. OrganizationID: "orgid",
  125. ProjectID: projectID,
  126. },
  127. },
  128. },
  129. },
  130. mock: func(c *FakeClient) {
  131. c.ListSecretReturnsOnCallN(0, &SecretIdentifiersResponse{
  132. Data: []SecretIdentifierResponse{
  133. {
  134. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  135. Key: "this-is-a-name",
  136. OrganizationID: "orgid",
  137. },
  138. },
  139. })
  140. projectID := "another-project"
  141. c.GetSecretReturnsOnCallN(0, &SecretResponse{
  142. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  143. Key: "this-is-a-name",
  144. Note: "note",
  145. OrganizationID: "orgid",
  146. Value: "value",
  147. ProjectID: &projectID,
  148. })
  149. },
  150. assertMock: func(t *testing.T, c *FakeClient) {
  151. assert.Equal(t, 0, c.deleteSecretCalledN)
  152. },
  153. },
  154. wantErr: true, // no secret found
  155. args: args{
  156. ctx: context.TODO(),
  157. ref: v1alpha1.PushSecretRemoteRef{
  158. RemoteKey: "this-is-a-name",
  159. },
  160. },
  161. },
  162. }
  163. for _, tt := range tests {
  164. t.Run(tt.name, func(t *testing.T) {
  165. fakeClient := &FakeClient{}
  166. tt.fields.mock(fakeClient)
  167. p := &Provider{
  168. kube: tt.fields.kube,
  169. namespace: tt.fields.namespace,
  170. store: tt.fields.store,
  171. bitwardenSdkClient: fakeClient,
  172. }
  173. if err := p.DeleteSecret(tt.args.ctx, tt.args.ref); (err != nil) != tt.wantErr {
  174. t.Errorf("DeleteSecret() error = %v, wantErr %v", err, tt.wantErr)
  175. }
  176. tt.fields.assertMock(t, fakeClient)
  177. })
  178. }
  179. }
  180. func TestProviderGetAllSecrets(t *testing.T) {
  181. type fields struct {
  182. kube client.Client
  183. namespace string
  184. store v1beta1.GenericStore
  185. mock func(c *FakeClient)
  186. }
  187. type args struct {
  188. ctx context.Context
  189. ref v1beta1.ExternalSecretFind
  190. }
  191. tests := []struct {
  192. name string
  193. fields fields
  194. args args
  195. want map[string][]byte
  196. wantErr bool
  197. }{
  198. {
  199. name: "get all secrets",
  200. fields: fields{
  201. namespace: "default",
  202. store: &v1beta1.SecretStore{
  203. Spec: v1beta1.SecretStoreSpec{
  204. Provider: &v1beta1.SecretStoreProvider{
  205. BitwardenSecretsManager: &v1beta1.BitwardenSecretsManagerProvider{
  206. OrganizationID: "orgid",
  207. ProjectID: projectID,
  208. },
  209. },
  210. },
  211. },
  212. mock: func(c *FakeClient) {
  213. c.ListSecretReturnsOnCallN(0, &SecretIdentifiersResponse{
  214. Data: []SecretIdentifierResponse{
  215. {
  216. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  217. Key: "key1",
  218. OrganizationID: "orgid",
  219. },
  220. {
  221. ID: "7c0d21ec-10d9-4972-bdf8-ec52df99cc86",
  222. Key: "key2",
  223. OrganizationID: "orgid",
  224. },
  225. },
  226. })
  227. c.GetSecretReturnsOnCallN(0, &SecretResponse{
  228. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  229. Key: "key1",
  230. Value: "value1",
  231. })
  232. c.GetSecretReturnsOnCallN(1, &SecretResponse{
  233. ID: "7c0d21ec-10d9-4972-bdf8-ec52df99cc86",
  234. Key: "key2",
  235. Value: "value2",
  236. })
  237. },
  238. },
  239. args: args{
  240. ctx: context.TODO(),
  241. ref: v1beta1.ExternalSecretFind{},
  242. },
  243. want: map[string][]byte{
  244. "d8f29773-3019-4973-9bbc-66327d077fe2": []byte("value1"),
  245. "7c0d21ec-10d9-4972-bdf8-ec52df99cc86": []byte("value2"),
  246. },
  247. },
  248. }
  249. for _, tt := range tests {
  250. t.Run(tt.name, func(t *testing.T) {
  251. fakeClient := &FakeClient{}
  252. tt.fields.mock(fakeClient)
  253. p := &Provider{
  254. kube: tt.fields.kube,
  255. namespace: tt.fields.namespace,
  256. store: tt.fields.store,
  257. bitwardenSdkClient: fakeClient,
  258. }
  259. got, err := p.GetAllSecrets(tt.args.ctx, tt.args.ref)
  260. if (err != nil) != tt.wantErr {
  261. t.Errorf("GetAllSecrets() error = %v, wantErr %v", err, tt.wantErr)
  262. return
  263. }
  264. if !reflect.DeepEqual(got, tt.want) {
  265. t.Errorf("GetAllSecrets() got = %v, want %v", got, tt.want)
  266. }
  267. })
  268. }
  269. }
  270. func TestProviderGetSecret(t *testing.T) {
  271. type fields struct {
  272. kube func() client.Client
  273. namespace string
  274. store v1beta1.GenericStore
  275. mock func(c *FakeClient)
  276. }
  277. type args struct {
  278. ctx context.Context
  279. ref v1beta1.ExternalSecretDataRemoteRef
  280. }
  281. tests := []struct {
  282. name string
  283. fields fields
  284. args args
  285. want []byte
  286. wantErr bool
  287. }{
  288. {
  289. name: "get secret with UUID",
  290. fields: fields{
  291. kube: func() client.Client {
  292. return fake.NewFakeClient()
  293. },
  294. namespace: "default",
  295. store: &v1beta1.SecretStore{},
  296. mock: func(c *FakeClient) {
  297. c.GetSecretReturnsOnCallN(0, &SecretResponse{
  298. ID: "id",
  299. Key: "key",
  300. Note: "note",
  301. OrganizationID: "org",
  302. Value: "value",
  303. })
  304. },
  305. },
  306. args: args{
  307. ctx: context.Background(),
  308. ref: v1beta1.ExternalSecretDataRemoteRef{
  309. Key: "d8f29773-3019-4973-9bbc-66327d077fe2",
  310. },
  311. },
  312. want: []byte("value"),
  313. },
  314. {
  315. name: "get secret by name",
  316. fields: fields{
  317. kube: func() client.Client {
  318. return fake.NewFakeClient()
  319. },
  320. namespace: "default",
  321. store: &v1beta1.SecretStore{
  322. Spec: v1beta1.SecretStoreSpec{
  323. Provider: &v1beta1.SecretStoreProvider{
  324. BitwardenSecretsManager: &v1beta1.BitwardenSecretsManagerProvider{
  325. OrganizationID: "orgid",
  326. ProjectID: projectID,
  327. },
  328. },
  329. },
  330. },
  331. mock: func(c *FakeClient) {
  332. c.ListSecretReturnsOnCallN(0, &SecretIdentifiersResponse{
  333. Data: []SecretIdentifierResponse{
  334. {
  335. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  336. Key: "this-is-a-name",
  337. OrganizationID: "orgid",
  338. },
  339. },
  340. })
  341. c.GetSecretReturnsOnCallN(0, &SecretResponse{
  342. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  343. Key: "key",
  344. Note: "note",
  345. OrganizationID: "org",
  346. Value: "value",
  347. ProjectID: &projectID,
  348. })
  349. },
  350. },
  351. args: args{
  352. ctx: context.Background(),
  353. ref: v1beta1.ExternalSecretDataRemoteRef{
  354. Key: "this-is-a-name",
  355. },
  356. },
  357. want: []byte("value"),
  358. },
  359. }
  360. for _, tt := range tests {
  361. t.Run(tt.name, func(t *testing.T) {
  362. fakeClient := &FakeClient{}
  363. tt.fields.mock(fakeClient)
  364. p := &Provider{
  365. kube: tt.fields.kube(),
  366. namespace: tt.fields.namespace,
  367. store: tt.fields.store,
  368. bitwardenSdkClient: fakeClient,
  369. }
  370. got, err := p.GetSecret(tt.args.ctx, tt.args.ref)
  371. if (err != nil) != tt.wantErr {
  372. t.Errorf("GetSecret() error = %v, wantErr %v", err, tt.wantErr)
  373. return
  374. }
  375. if !reflect.DeepEqual(got, tt.want) {
  376. t.Errorf("GetSecret() got = %v, want %v", got, tt.want)
  377. }
  378. })
  379. }
  380. }
  381. func TestProviderPushSecret(t *testing.T) {
  382. type fields struct {
  383. kube func() client.Client
  384. namespace string
  385. store v1beta1.GenericStore
  386. mock func(c *FakeClient)
  387. assertMock func(t *testing.T, c *FakeClient)
  388. }
  389. type args struct {
  390. ctx context.Context
  391. secret *corev1.Secret
  392. data v1beta1.PushSecretData
  393. }
  394. tests := []struct {
  395. name string
  396. fields fields
  397. args args
  398. wantErr bool
  399. }{
  400. {
  401. name: "push secret is successful for a none existent remote secret",
  402. args: args{
  403. ctx: context.Background(),
  404. secret: &corev1.Secret{
  405. Data: map[string][]byte{
  406. "key": []byte("value"),
  407. },
  408. },
  409. data: v1alpha1.PushSecretData{
  410. Match: v1alpha1.PushSecretMatch{
  411. SecretKey: "key",
  412. RemoteRef: v1alpha1.PushSecretRemoteRef{
  413. RemoteKey: "this-is-a-name",
  414. },
  415. },
  416. },
  417. },
  418. fields: fields{
  419. kube: func() client.Client {
  420. return fake.NewFakeClient()
  421. },
  422. namespace: "default",
  423. store: &v1beta1.SecretStore{
  424. Spec: v1beta1.SecretStoreSpec{
  425. Provider: &v1beta1.SecretStoreProvider{
  426. BitwardenSecretsManager: &v1beta1.BitwardenSecretsManagerProvider{
  427. OrganizationID: "orgid",
  428. ProjectID: projectID,
  429. },
  430. },
  431. },
  432. },
  433. mock: func(c *FakeClient) {
  434. c.ListSecretReturnsOnCallN(0, &SecretIdentifiersResponse{
  435. Data: []SecretIdentifierResponse{
  436. {
  437. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  438. Key: "this-is-a-name",
  439. OrganizationID: "orgid",
  440. },
  441. },
  442. })
  443. c.GetSecretReturnsOnCallN(0, &SecretResponse{
  444. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  445. Key: "no-match", // if this is this-is-a-name it would match
  446. Note: "",
  447. OrganizationID: "orgid",
  448. Value: "value",
  449. ProjectID: &projectID,
  450. })
  451. c.CreateSecretReturnsOnCallN(0, &SecretResponse{})
  452. },
  453. assertMock: func(t *testing.T, c *FakeClient) {
  454. cargs := c.createSecretCallArguments[0]
  455. assert.Equal(t, cargs, SecretCreateRequest{
  456. Key: "this-is-a-name",
  457. Note: "",
  458. OrganizationID: "orgid",
  459. ProjectIDS: []string{projectID},
  460. Value: "value",
  461. })
  462. },
  463. },
  464. },
  465. {
  466. name: "push secret is successful for a existing remote secret but only the value differs will call update",
  467. args: args{
  468. ctx: context.Background(),
  469. secret: &corev1.Secret{
  470. Data: map[string][]byte{
  471. "key": []byte("new-value"),
  472. },
  473. },
  474. data: v1alpha1.PushSecretData{
  475. Match: v1alpha1.PushSecretMatch{
  476. SecretKey: "key",
  477. RemoteRef: v1alpha1.PushSecretRemoteRef{
  478. RemoteKey: "this-is-a-name",
  479. },
  480. },
  481. },
  482. },
  483. fields: fields{
  484. kube: func() client.Client {
  485. return fake.NewFakeClient()
  486. },
  487. namespace: "default",
  488. store: &v1beta1.SecretStore{
  489. Spec: v1beta1.SecretStoreSpec{
  490. Provider: &v1beta1.SecretStoreProvider{
  491. BitwardenSecretsManager: &v1beta1.BitwardenSecretsManagerProvider{
  492. OrganizationID: "orgid",
  493. ProjectID: projectID,
  494. },
  495. },
  496. },
  497. },
  498. mock: func(c *FakeClient) {
  499. c.ListSecretReturnsOnCallN(0, &SecretIdentifiersResponse{
  500. Data: []SecretIdentifierResponse{
  501. {
  502. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  503. Key: "this-is-a-name",
  504. OrganizationID: "orgid",
  505. },
  506. },
  507. })
  508. c.GetSecretReturnsOnCallN(0, &SecretResponse{
  509. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  510. Key: "this-is-a-name",
  511. Note: "",
  512. OrganizationID: "orgid",
  513. Value: "value",
  514. ProjectID: &projectID,
  515. })
  516. c.UpdateSecretReturnsOnCallN(0, &SecretResponse{})
  517. },
  518. assertMock: func(t *testing.T, c *FakeClient) {
  519. pargs := c.updateSecretCallArguments[0]
  520. assert.Equal(t, pargs, SecretPutRequest{
  521. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  522. Key: "this-is-a-name",
  523. Note: "",
  524. OrganizationID: "orgid",
  525. ProjectIDS: []string{projectID},
  526. Value: "new-value",
  527. })
  528. },
  529. },
  530. },
  531. {
  532. name: "push secret will not push if the same secret already exists",
  533. args: args{
  534. ctx: context.Background(),
  535. secret: &corev1.Secret{
  536. Data: map[string][]byte{
  537. "key": []byte("value"),
  538. },
  539. },
  540. data: v1alpha1.PushSecretData{
  541. Match: v1alpha1.PushSecretMatch{
  542. SecretKey: "key",
  543. RemoteRef: v1alpha1.PushSecretRemoteRef{
  544. RemoteKey: "this-is-a-name",
  545. },
  546. },
  547. },
  548. },
  549. fields: fields{
  550. kube: func() client.Client {
  551. return fake.NewFakeClient()
  552. },
  553. namespace: "default",
  554. store: &v1beta1.SecretStore{
  555. Spec: v1beta1.SecretStoreSpec{
  556. Provider: &v1beta1.SecretStoreProvider{
  557. BitwardenSecretsManager: &v1beta1.BitwardenSecretsManagerProvider{
  558. OrganizationID: "orgid",
  559. ProjectID: projectID,
  560. },
  561. },
  562. },
  563. },
  564. mock: func(c *FakeClient) {
  565. c.ListSecretReturnsOnCallN(0, &SecretIdentifiersResponse{
  566. Data: []SecretIdentifierResponse{
  567. {
  568. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  569. Key: "this-is-a-name",
  570. OrganizationID: "orgid",
  571. },
  572. },
  573. })
  574. c.GetSecretReturnsOnCallN(0, &SecretResponse{
  575. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  576. Key: "this-is-a-name",
  577. OrganizationID: "orgid",
  578. Value: "value",
  579. ProjectID: &projectID,
  580. })
  581. c.UpdateSecretReturnsOnCallN(0, &SecretResponse{})
  582. },
  583. assertMock: func(t *testing.T, c *FakeClient) {
  584. assert.Equal(t, 0, c.createSecretCalledN)
  585. assert.Equal(t, 0, c.updateSecretCalledN)
  586. },
  587. },
  588. },
  589. }
  590. for _, tt := range tests {
  591. t.Run(tt.name, func(t *testing.T) {
  592. fakeClient := &FakeClient{}
  593. tt.fields.mock(fakeClient)
  594. p := &Provider{
  595. kube: tt.fields.kube(),
  596. namespace: tt.fields.namespace,
  597. store: tt.fields.store,
  598. bitwardenSdkClient: fakeClient,
  599. }
  600. if err := p.PushSecret(tt.args.ctx, tt.args.secret, tt.args.data); (err != nil) != tt.wantErr {
  601. t.Errorf("PushSecret() error = %v, wantErr %v", err, tt.wantErr)
  602. }
  603. tt.fields.assertMock(t, fakeClient)
  604. })
  605. }
  606. }
  607. func TestProviderSecretExists(t *testing.T) {
  608. type fields struct {
  609. kube client.Client
  610. namespace string
  611. store v1beta1.GenericStore
  612. mock func(c *FakeClient)
  613. assertMock func(t *testing.T, c *FakeClient)
  614. }
  615. type args struct {
  616. ctx context.Context
  617. ref v1alpha1.PushSecretData
  618. }
  619. tests := []struct {
  620. name string
  621. fields fields
  622. args args
  623. want bool
  624. wantErr bool
  625. }{
  626. {
  627. name: "secret exists",
  628. fields: fields{
  629. store: &v1beta1.SecretStore{
  630. Spec: v1beta1.SecretStoreSpec{
  631. Provider: &v1beta1.SecretStoreProvider{
  632. BitwardenSecretsManager: &v1beta1.BitwardenSecretsManagerProvider{
  633. OrganizationID: "orgid",
  634. ProjectID: projectID,
  635. },
  636. },
  637. },
  638. },
  639. mock: func(c *FakeClient) {
  640. c.GetSecretReturnsOnCallN(0, &SecretResponse{})
  641. },
  642. assertMock: func(t *testing.T, c *FakeClient) {
  643. assert.Equal(t, 0, c.listSecretsCalledN)
  644. },
  645. },
  646. args: args{
  647. ctx: nil,
  648. ref: v1alpha1.PushSecretData{
  649. Match: v1alpha1.PushSecretMatch{
  650. RemoteRef: v1alpha1.PushSecretRemoteRef{
  651. RemoteKey: "d8f29773-3019-4973-9bbc-66327d077fe2",
  652. },
  653. },
  654. },
  655. },
  656. want: true,
  657. },
  658. {
  659. name: "secret exists by name",
  660. fields: fields{
  661. store: &v1beta1.SecretStore{
  662. Spec: v1beta1.SecretStoreSpec{
  663. Provider: &v1beta1.SecretStoreProvider{
  664. BitwardenSecretsManager: &v1beta1.BitwardenSecretsManagerProvider{
  665. OrganizationID: "orgid",
  666. ProjectID: projectID,
  667. },
  668. },
  669. },
  670. },
  671. mock: func(c *FakeClient) {
  672. c.ListSecretReturnsOnCallN(0, &SecretIdentifiersResponse{
  673. Data: []SecretIdentifierResponse{
  674. {
  675. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  676. Key: "name",
  677. OrganizationID: "orgid",
  678. },
  679. },
  680. })
  681. c.GetSecretReturnsOnCallN(0, &SecretResponse{
  682. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  683. Key: "name",
  684. OrganizationID: "orgid",
  685. Value: "value",
  686. ProjectID: &projectID,
  687. })
  688. },
  689. },
  690. args: args{
  691. ctx: nil,
  692. ref: v1alpha1.PushSecretData{
  693. Match: v1alpha1.PushSecretMatch{
  694. RemoteRef: v1alpha1.PushSecretRemoteRef{
  695. RemoteKey: "name",
  696. },
  697. },
  698. },
  699. },
  700. want: true,
  701. },
  702. {
  703. name: "secret not found by name",
  704. fields: fields{
  705. store: &v1beta1.SecretStore{
  706. Spec: v1beta1.SecretStoreSpec{
  707. Provider: &v1beta1.SecretStoreProvider{
  708. BitwardenSecretsManager: &v1beta1.BitwardenSecretsManagerProvider{
  709. OrganizationID: "orgid",
  710. ProjectID: projectID,
  711. },
  712. },
  713. },
  714. },
  715. mock: func(c *FakeClient) {
  716. c.ListSecretReturnsOnCallN(0, &SecretIdentifiersResponse{
  717. Data: []SecretIdentifierResponse{
  718. {
  719. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  720. Key: "name",
  721. OrganizationID: "orgid",
  722. },
  723. },
  724. })
  725. projectIDDifferent := "different-project"
  726. c.GetSecretReturnsOnCallN(0, &SecretResponse{
  727. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  728. Key: "name",
  729. OrganizationID: "orgid",
  730. Value: "value",
  731. ProjectID: &projectIDDifferent,
  732. })
  733. },
  734. },
  735. args: args{
  736. ctx: nil,
  737. ref: v1alpha1.PushSecretData{
  738. Match: v1alpha1.PushSecretMatch{
  739. RemoteRef: v1alpha1.PushSecretRemoteRef{
  740. RemoteKey: "name",
  741. },
  742. },
  743. },
  744. },
  745. want: false,
  746. wantErr: true, // secret not found
  747. },
  748. {
  749. name: "invalid name format should error",
  750. fields: fields{
  751. store: &v1beta1.SecretStore{
  752. Spec: v1beta1.SecretStoreSpec{
  753. Provider: &v1beta1.SecretStoreProvider{
  754. BitwardenSecretsManager: &v1beta1.BitwardenSecretsManagerProvider{
  755. OrganizationID: "orgid",
  756. ProjectID: projectID,
  757. },
  758. },
  759. },
  760. },
  761. mock: func(c *FakeClient) {
  762. },
  763. assertMock: func(t *testing.T, c *FakeClient) {
  764. assert.Equal(t, 0, c.listSecretsCalledN)
  765. },
  766. },
  767. args: args{
  768. ctx: nil,
  769. ref: v1alpha1.PushSecretData{
  770. Match: v1alpha1.PushSecretMatch{
  771. RemoteRef: v1alpha1.PushSecretRemoteRef{
  772. RemoteKey: "name",
  773. },
  774. },
  775. },
  776. },
  777. want: false,
  778. wantErr: true, // invalid remote key format
  779. },
  780. }
  781. for _, tt := range tests {
  782. t.Run(tt.name, func(t *testing.T) {
  783. fakeClient := &FakeClient{}
  784. tt.fields.mock(fakeClient)
  785. p := &Provider{
  786. kube: tt.fields.kube,
  787. namespace: tt.fields.namespace,
  788. store: tt.fields.store,
  789. bitwardenSdkClient: fakeClient,
  790. }
  791. got, err := p.SecretExists(tt.args.ctx, tt.args.ref)
  792. if (err != nil) != tt.wantErr {
  793. t.Errorf("SecretExists() error = %v, wantErr %v", err, tt.wantErr)
  794. return
  795. }
  796. if got != tt.want {
  797. t.Errorf("SecretExists() got = %v, want %v", got, tt.want)
  798. }
  799. })
  800. }
  801. }
  802. func TestProviderGetSecretMap(t *testing.T) {
  803. type fields struct {
  804. kube func() client.Client
  805. namespace string
  806. store v1beta1.GenericStore
  807. mock func(c *FakeClient)
  808. }
  809. type args struct {
  810. ctx context.Context
  811. ref v1beta1.ExternalSecretDataRemoteRef
  812. key string
  813. }
  814. tests := []struct {
  815. name string
  816. fields fields
  817. args args
  818. want []byte
  819. wantErr bool
  820. }{
  821. {
  822. name: "get secret map",
  823. fields: fields{
  824. kube: func() client.Client {
  825. return fake.NewFakeClient()
  826. },
  827. namespace: "default",
  828. store: &v1beta1.SecretStore{},
  829. mock: func(c *FakeClient) {
  830. c.GetSecretReturnsOnCallN(0, &SecretResponse{
  831. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  832. Key: "key",
  833. Note: "note",
  834. OrganizationID: "org",
  835. Value: `{"key": "value"}`,
  836. })
  837. },
  838. },
  839. args: args{
  840. ctx: context.Background(),
  841. ref: v1beta1.ExternalSecretDataRemoteRef{
  842. Key: "d8f29773-3019-4973-9bbc-66327d077fe2",
  843. Property: "key",
  844. },
  845. key: "key",
  846. },
  847. want: []byte("value"),
  848. },
  849. {
  850. name: "get secret map - missing key",
  851. fields: fields{
  852. kube: func() client.Client {
  853. return fake.NewFakeClient()
  854. },
  855. namespace: "default",
  856. store: &v1beta1.SecretStore{},
  857. mock: func(c *FakeClient) {
  858. c.GetSecretReturnsOnCallN(0, &SecretResponse{
  859. ID: "d8f29773-3019-4973-9bbc-66327d077fe2",
  860. Key: "key",
  861. Note: "note",
  862. OrganizationID: "org",
  863. Value: `{"key": "value"}`,
  864. })
  865. },
  866. },
  867. args: args{
  868. ctx: context.Background(),
  869. ref: v1beta1.ExternalSecretDataRemoteRef{
  870. Key: "d8f29773-3019-4973-9bbc-66327d077fe2",
  871. Property: "nope",
  872. },
  873. },
  874. },
  875. }
  876. for _, tt := range tests {
  877. t.Run(tt.name, func(t *testing.T) {
  878. fakeClient := &FakeClient{}
  879. tt.fields.mock(fakeClient)
  880. p := &Provider{
  881. kube: tt.fields.kube(),
  882. namespace: tt.fields.namespace,
  883. store: tt.fields.store,
  884. bitwardenSdkClient: fakeClient,
  885. }
  886. got, err := p.GetSecretMap(tt.args.ctx, tt.args.ref)
  887. if (err != nil) != tt.wantErr {
  888. t.Errorf("GetSecret() error = %v, wantErr %v", err, tt.wantErr)
  889. return
  890. }
  891. assert.Equal(t, tt.want, got[tt.args.key])
  892. })
  893. }
  894. }