client_test.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917
  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 kubernetes
  13. import (
  14. "context"
  15. "errors"
  16. "reflect"
  17. "strings"
  18. "testing"
  19. "github.com/google/go-cmp/cmp"
  20. "github.com/stretchr/testify/assert"
  21. v1 "k8s.io/api/core/v1"
  22. apierrors "k8s.io/apimachinery/pkg/api/errors"
  23. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  24. "k8s.io/apimachinery/pkg/runtime/schema"
  25. "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
  26. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  27. )
  28. const (
  29. errSomethingWentWrong = "Something went wrong"
  30. )
  31. type fakeClient struct {
  32. t *testing.T
  33. secretMap map[string]*v1.Secret
  34. expectedListOptions metav1.ListOptions
  35. err error
  36. }
  37. func (fk *fakeClient) Get(_ context.Context, name string, _ metav1.GetOptions) (*v1.Secret, error) {
  38. if fk.err != nil {
  39. return nil, fk.err
  40. }
  41. secret, ok := fk.secretMap[name]
  42. if !ok {
  43. return nil, apierrors.NewNotFound(schema.GroupResource{Group: "", Resource: "Secret"}, "secret")
  44. }
  45. // return inmutable to simulate external system and avoid accidental side effects
  46. sCopy := secret.DeepCopy()
  47. // update operation requires to relate names
  48. sCopy.Name = name
  49. return sCopy, nil
  50. }
  51. func (fk *fakeClient) List(_ context.Context, opts metav1.ListOptions) (*v1.SecretList, error) {
  52. assert.Equal(fk.t, fk.expectedListOptions, opts)
  53. list := &v1.SecretList{}
  54. for _, v := range fk.secretMap {
  55. list.Items = append(list.Items, *v)
  56. }
  57. return list, nil
  58. }
  59. func (fk *fakeClient) Delete(_ context.Context, name string, _ metav1.DeleteOptions) error {
  60. if fk.err != nil {
  61. return fk.err
  62. }
  63. _, ok := fk.secretMap[name]
  64. if !ok {
  65. return apierrors.NewNotFound(schema.GroupResource{Group: "", Resource: "Secret"}, "secret")
  66. }
  67. delete(fk.secretMap, name)
  68. return nil
  69. }
  70. func (fk *fakeClient) Create(_ context.Context, secret *v1.Secret, _ metav1.CreateOptions) (*v1.Secret, error) {
  71. s := &v1.Secret{
  72. Data: secret.Data,
  73. Type: secret.Type,
  74. }
  75. fk.secretMap[secret.Name] = s
  76. return s, nil
  77. }
  78. func (fk *fakeClient) Update(_ context.Context, secret *v1.Secret, _ metav1.UpdateOptions) (*v1.Secret, error) {
  79. s, ok := fk.secretMap[secret.Name]
  80. if !ok {
  81. return nil, errors.New("error while updating secret")
  82. }
  83. s.Data = secret.Data
  84. return s, nil
  85. }
  86. var binaryTestData = []byte{0x00, 0xff, 0x00, 0xff, 0xac, 0xab, 0x28, 0x21}
  87. func TestGetSecret(t *testing.T) {
  88. tests := []struct {
  89. desc string
  90. secrets map[string]*v1.Secret
  91. clientErr error
  92. ref esv1beta1.ExternalSecretDataRemoteRef
  93. want []byte
  94. wantErr string
  95. }{
  96. {
  97. desc: "secret data with correct property",
  98. secrets: map[string]*v1.Secret{
  99. "mysec": {
  100. Data: map[string][]byte{
  101. "token": []byte(`foobar`),
  102. },
  103. },
  104. },
  105. ref: esv1beta1.ExternalSecretDataRemoteRef{
  106. Key: "mysec",
  107. Property: "token",
  108. },
  109. want: []byte(`foobar`),
  110. },
  111. {
  112. desc: "secret data with multi level property",
  113. secrets: map[string]*v1.Secret{
  114. "mysec": {
  115. Data: map[string][]byte{
  116. "foo": []byte(`{"huga":{"bar":"val"}}`),
  117. },
  118. },
  119. },
  120. ref: esv1beta1.ExternalSecretDataRemoteRef{
  121. Key: "mysec",
  122. Property: "foo.huga.bar",
  123. },
  124. want: []byte(`val`),
  125. },
  126. {
  127. desc: "secret data with property containing .",
  128. secrets: map[string]*v1.Secret{
  129. "mysec": {
  130. Data: map[string][]byte{
  131. "foo.png": []byte(`correct`),
  132. "foo": []byte(`{"png":"wrong"}`),
  133. },
  134. },
  135. },
  136. ref: esv1beta1.ExternalSecretDataRemoteRef{
  137. Key: "mysec",
  138. Property: "foo.png",
  139. },
  140. want: []byte(`correct`),
  141. },
  142. {
  143. desc: "secret data contains html characters",
  144. secrets: map[string]*v1.Secret{
  145. "mysec": {
  146. Data: map[string][]byte{
  147. "html": []byte(`<foobar>`),
  148. },
  149. },
  150. },
  151. ref: esv1beta1.ExternalSecretDataRemoteRef{
  152. Key: "mysec",
  153. },
  154. want: []byte(`{"html":"<foobar>"}`),
  155. },
  156. {
  157. desc: "secret metadata contains html characters",
  158. secrets: map[string]*v1.Secret{
  159. "mysec": {
  160. ObjectMeta: metav1.ObjectMeta{
  161. Annotations: map[string]string{"date": "today"},
  162. Labels: map[string]string{"dev": "<seb>"},
  163. },
  164. },
  165. },
  166. ref: esv1beta1.ExternalSecretDataRemoteRef{
  167. MetadataPolicy: esv1beta1.ExternalSecretMetadataPolicyFetch,
  168. Key: "mysec",
  169. },
  170. want: []byte(`{"annotations":{"date":"today"},"labels":{"dev":"<seb>"}}`),
  171. },
  172. {
  173. desc: "secret data contains binary",
  174. secrets: map[string]*v1.Secret{
  175. "mysec": {
  176. Data: map[string][]byte{
  177. "bindata": binaryTestData,
  178. },
  179. },
  180. },
  181. ref: esv1beta1.ExternalSecretDataRemoteRef{
  182. Key: "mysec",
  183. Property: "bindata",
  184. },
  185. want: binaryTestData,
  186. },
  187. {
  188. desc: "secret data without property",
  189. secrets: map[string]*v1.Secret{
  190. "mysec": {
  191. Data: map[string][]byte{
  192. "token": []byte(`foobar`),
  193. },
  194. },
  195. },
  196. ref: esv1beta1.ExternalSecretDataRemoteRef{
  197. Key: "mysec",
  198. },
  199. want: []byte(`{"token":"foobar"}`),
  200. },
  201. {
  202. desc: "secret metadata without property",
  203. secrets: map[string]*v1.Secret{
  204. "mysec": {
  205. ObjectMeta: metav1.ObjectMeta{
  206. Annotations: map[string]string{"date": "today"},
  207. Labels: map[string]string{"dev": "seb"},
  208. },
  209. },
  210. },
  211. ref: esv1beta1.ExternalSecretDataRemoteRef{
  212. MetadataPolicy: esv1beta1.ExternalSecretMetadataPolicyFetch,
  213. Key: "mysec",
  214. },
  215. want: []byte(`{"annotations":{"date":"today"},"labels":{"dev":"seb"}}`),
  216. },
  217. {
  218. desc: "secret metadata with single level property",
  219. secrets: map[string]*v1.Secret{
  220. "mysec": {
  221. ObjectMeta: metav1.ObjectMeta{
  222. Annotations: map[string]string{"date": "today"},
  223. Labels: map[string]string{"dev": "seb"},
  224. },
  225. },
  226. },
  227. ref: esv1beta1.ExternalSecretDataRemoteRef{
  228. MetadataPolicy: esv1beta1.ExternalSecretMetadataPolicyFetch,
  229. Key: "mysec",
  230. Property: "labels",
  231. },
  232. want: []byte(`{"dev":"seb"}`),
  233. },
  234. {
  235. desc: "secret metadata with multiple level property",
  236. secrets: map[string]*v1.Secret{
  237. "mysec": {
  238. ObjectMeta: metav1.ObjectMeta{
  239. Annotations: map[string]string{"date": "today"},
  240. Labels: map[string]string{"dev": "seb"},
  241. },
  242. },
  243. },
  244. ref: esv1beta1.ExternalSecretDataRemoteRef{
  245. MetadataPolicy: esv1beta1.ExternalSecretMetadataPolicyFetch,
  246. Key: "mysec",
  247. Property: "labels.dev",
  248. },
  249. want: []byte(`seb`),
  250. },
  251. {
  252. desc: "secret is not found",
  253. clientErr: apierrors.NewNotFound(schema.GroupResource{Group: "", Resource: "Secret"}, "secret"),
  254. ref: esv1beta1.ExternalSecretDataRemoteRef{
  255. Key: "mysec",
  256. Property: "token",
  257. },
  258. wantErr: `Secret "secret" not found`,
  259. },
  260. {
  261. desc: "secret data with wrong property",
  262. secrets: map[string]*v1.Secret{
  263. "mysec": {
  264. Data: map[string][]byte{
  265. "token": []byte(`foobar`),
  266. },
  267. },
  268. },
  269. ref: esv1beta1.ExternalSecretDataRemoteRef{
  270. Key: "mysec",
  271. Property: "not-the-token",
  272. },
  273. wantErr: "property not-the-token does not exist in data of secret",
  274. },
  275. {
  276. desc: "secret metadata with wrong property",
  277. secrets: map[string]*v1.Secret{
  278. "mysec": {
  279. ObjectMeta: metav1.ObjectMeta{
  280. Annotations: map[string]string{"date": "today"},
  281. Labels: map[string]string{"dev": "seb"},
  282. },
  283. },
  284. },
  285. ref: esv1beta1.ExternalSecretDataRemoteRef{
  286. MetadataPolicy: esv1beta1.ExternalSecretMetadataPolicyFetch,
  287. Key: "mysec",
  288. Property: "foo",
  289. },
  290. wantErr: "property foo does not exist in metadata of secret",
  291. },
  292. }
  293. for _, tt := range tests {
  294. t.Run(tt.desc, func(t *testing.T) {
  295. p := &Client{
  296. userSecretClient: &fakeClient{t: t, secretMap: tt.secrets, err: tt.clientErr},
  297. namespace: "default",
  298. }
  299. got, err := p.GetSecret(context.Background(), tt.ref)
  300. if err != nil {
  301. if tt.wantErr == "" {
  302. t.Fatalf("failed to call GetSecret: %v", err)
  303. }
  304. if !strings.Contains(err.Error(), tt.wantErr) {
  305. t.Fatalf("received an unexpected error: %q should have contained %q", err.Error(), tt.wantErr)
  306. }
  307. return
  308. }
  309. if tt.wantErr != "" {
  310. t.Fatalf("expected to receive an error but got nil")
  311. }
  312. if !reflect.DeepEqual(got, tt.want) {
  313. t.Fatalf("received an unexpected secret: got: %s, want %s", got, tt.want)
  314. }
  315. })
  316. }
  317. }
  318. func TestGetSecretMap(t *testing.T) {
  319. type fields struct {
  320. Client KClient
  321. ReviewClient RClient
  322. Namespace string
  323. }
  324. tests := []struct {
  325. name string
  326. fields fields
  327. ref esv1beta1.ExternalSecretDataRemoteRef
  328. want map[string][]byte
  329. wantErr bool
  330. }{
  331. {
  332. name: "successful case metadata without property",
  333. fields: fields{
  334. Client: &fakeClient{
  335. t: t,
  336. secretMap: map[string]*v1.Secret{
  337. "mysec": {
  338. ObjectMeta: metav1.ObjectMeta{
  339. Annotations: map[string]string{"date": "today"},
  340. Labels: map[string]string{"dev": "seb"},
  341. },
  342. },
  343. },
  344. },
  345. Namespace: "default",
  346. },
  347. ref: esv1beta1.ExternalSecretDataRemoteRef{
  348. MetadataPolicy: esv1beta1.ExternalSecretMetadataPolicyFetch,
  349. Key: "mysec",
  350. },
  351. want: map[string][]byte{"annotations": []byte("{\"date\":\"today\"}"), "labels": []byte("{\"dev\":\"seb\"}")},
  352. },
  353. {
  354. name: "successful case metadata with single property",
  355. fields: fields{
  356. Client: &fakeClient{
  357. t: t,
  358. secretMap: map[string]*v1.Secret{
  359. "mysec": {
  360. ObjectMeta: metav1.ObjectMeta{
  361. Annotations: map[string]string{"date": "today"},
  362. Labels: map[string]string{"dev": "seb"},
  363. },
  364. },
  365. },
  366. },
  367. Namespace: "default",
  368. },
  369. ref: esv1beta1.ExternalSecretDataRemoteRef{
  370. MetadataPolicy: esv1beta1.ExternalSecretMetadataPolicyFetch,
  371. Key: "mysec",
  372. Property: "labels",
  373. },
  374. want: map[string][]byte{"dev": []byte("\"seb\"")},
  375. },
  376. {
  377. name: "error case metadata with wrong property",
  378. fields: fields{
  379. Client: &fakeClient{
  380. t: t,
  381. secretMap: map[string]*v1.Secret{
  382. "mysec": {
  383. ObjectMeta: metav1.ObjectMeta{
  384. Annotations: map[string]string{"date": "today"},
  385. Labels: map[string]string{"dev": "seb"},
  386. },
  387. },
  388. },
  389. },
  390. Namespace: "default",
  391. },
  392. ref: esv1beta1.ExternalSecretDataRemoteRef{
  393. MetadataPolicy: esv1beta1.ExternalSecretMetadataPolicyFetch,
  394. Key: "mysec",
  395. Property: "foo",
  396. },
  397. wantErr: true,
  398. },
  399. }
  400. for _, tt := range tests {
  401. t.Run(tt.name, func(t *testing.T) {
  402. p := &Client{
  403. userSecretClient: tt.fields.Client,
  404. userReviewClient: tt.fields.ReviewClient,
  405. namespace: tt.fields.Namespace,
  406. }
  407. got, err := p.GetSecretMap(context.Background(), tt.ref)
  408. if (err != nil) != tt.wantErr {
  409. t.Errorf("ProviderKubernetes.GetSecretMap() error = %v, wantErr %v", err, tt.wantErr)
  410. return
  411. }
  412. if !reflect.DeepEqual(got, tt.want) {
  413. t.Errorf("ProviderKubernetes.GetSecretMap() = %v, want %v", got, tt.want)
  414. }
  415. })
  416. }
  417. }
  418. func TestGetAllSecrets(t *testing.T) {
  419. type fields struct {
  420. Client KClient
  421. ReviewClient RClient
  422. Namespace string
  423. }
  424. type args struct {
  425. ctx context.Context
  426. ref esv1beta1.ExternalSecretFind
  427. }
  428. tests := []struct {
  429. name string
  430. fields fields
  431. args args
  432. want map[string][]byte
  433. wantErr bool
  434. }{
  435. {
  436. name: "use regex",
  437. fields: fields{
  438. Client: &fakeClient{
  439. t: t,
  440. secretMap: map[string]*v1.Secret{
  441. "mysec": {
  442. ObjectMeta: metav1.ObjectMeta{
  443. Name: "mysec",
  444. },
  445. Data: map[string][]byte{
  446. "token": []byte(`foo`),
  447. },
  448. },
  449. "other": {
  450. ObjectMeta: metav1.ObjectMeta{
  451. Name: "other",
  452. },
  453. Data: map[string][]byte{
  454. "token": []byte(`bar`),
  455. },
  456. },
  457. },
  458. },
  459. },
  460. args: args{
  461. ref: esv1beta1.ExternalSecretFind{
  462. Name: &esv1beta1.FindName{
  463. RegExp: "other",
  464. },
  465. },
  466. },
  467. want: map[string][]byte{
  468. "other": []byte(`{"token":"bar"}`),
  469. },
  470. },
  471. {
  472. name: "use tags/labels",
  473. fields: fields{
  474. Client: &fakeClient{
  475. t: t,
  476. expectedListOptions: metav1.ListOptions{
  477. LabelSelector: "app=foobar",
  478. },
  479. secretMap: map[string]*v1.Secret{
  480. "mysec": {
  481. ObjectMeta: metav1.ObjectMeta{
  482. Name: "mysec",
  483. },
  484. Data: map[string][]byte{
  485. "token": []byte(`foo`),
  486. },
  487. },
  488. "other": {
  489. ObjectMeta: metav1.ObjectMeta{
  490. Name: "other",
  491. },
  492. Data: map[string][]byte{
  493. "token": []byte(`bar`),
  494. },
  495. },
  496. },
  497. },
  498. },
  499. args: args{
  500. ref: esv1beta1.ExternalSecretFind{
  501. Tags: map[string]string{
  502. "app": "foobar",
  503. },
  504. },
  505. },
  506. want: map[string][]byte{
  507. "mysec": []byte(`{"token":"foo"}`),
  508. "other": []byte(`{"token":"bar"}`),
  509. },
  510. },
  511. }
  512. for _, tt := range tests {
  513. t.Run(tt.name, func(t *testing.T) {
  514. p := &Client{
  515. userSecretClient: tt.fields.Client,
  516. userReviewClient: tt.fields.ReviewClient,
  517. namespace: tt.fields.Namespace,
  518. }
  519. got, err := p.GetAllSecrets(tt.args.ctx, tt.args.ref)
  520. if (err != nil) != tt.wantErr {
  521. t.Errorf("ProviderKubernetes.GetAllSecrets() error = %v, wantErr %v", err, tt.wantErr)
  522. return
  523. }
  524. if !reflect.DeepEqual(got, tt.want) {
  525. t.Errorf("ProviderKubernetes.GetAllSecrets() = %v, want %v", got, tt.want)
  526. }
  527. })
  528. }
  529. }
  530. func TestDeleteSecret(t *testing.T) {
  531. type fields struct {
  532. Client KClient
  533. }
  534. tests := []struct {
  535. name string
  536. fields fields
  537. ref esv1beta1.PushRemoteRef
  538. wantSecretMap map[string]*v1.Secret
  539. wantErr bool
  540. }{
  541. {
  542. name: "refuse to delete without property",
  543. fields: fields{
  544. Client: &fakeClient{
  545. t: t,
  546. secretMap: map[string]*v1.Secret{
  547. "mysec": {
  548. Data: map[string][]byte{
  549. "token": []byte(`foobar`),
  550. },
  551. },
  552. },
  553. },
  554. },
  555. ref: v1alpha1.PushSecretRemoteRef{
  556. RemoteKey: "mysec",
  557. },
  558. wantErr: true,
  559. wantSecretMap: map[string]*v1.Secret{
  560. "mysec": {
  561. Data: map[string][]byte{
  562. "token": []byte(`foobar`),
  563. },
  564. },
  565. },
  566. },
  567. {
  568. name: "gracefully ignore not found secret",
  569. fields: fields{
  570. Client: &fakeClient{
  571. t: t,
  572. secretMap: map[string]*v1.Secret{},
  573. },
  574. },
  575. ref: v1alpha1.PushSecretRemoteRef{
  576. RemoteKey: "mysec",
  577. Property: "token",
  578. },
  579. wantErr: false,
  580. wantSecretMap: map[string]*v1.Secret{},
  581. },
  582. {
  583. name: "gracefully ignore not found property",
  584. fields: fields{
  585. Client: &fakeClient{
  586. t: t,
  587. secretMap: map[string]*v1.Secret{
  588. "mysec": {
  589. Data: map[string][]byte{
  590. "token": []byte(`foobar`),
  591. },
  592. },
  593. },
  594. },
  595. },
  596. ref: v1alpha1.PushSecretRemoteRef{
  597. RemoteKey: "mysec",
  598. Property: "secret",
  599. },
  600. wantErr: false,
  601. wantSecretMap: map[string]*v1.Secret{
  602. "mysec": {
  603. Data: map[string][]byte{
  604. "token": []byte(`foobar`),
  605. },
  606. },
  607. },
  608. },
  609. {
  610. name: "unexpected lookup error",
  611. fields: fields{
  612. Client: &fakeClient{
  613. t: t,
  614. secretMap: map[string]*v1.Secret{
  615. "mysec": {
  616. Data: map[string][]byte{
  617. "token": []byte(`foobar`),
  618. },
  619. },
  620. },
  621. err: errors.New(errSomethingWentWrong),
  622. },
  623. },
  624. ref: v1alpha1.PushSecretRemoteRef{
  625. RemoteKey: "mysec",
  626. },
  627. wantErr: true,
  628. wantSecretMap: map[string]*v1.Secret{
  629. "mysec": {
  630. Data: map[string][]byte{
  631. "token": []byte(`foobar`),
  632. },
  633. },
  634. },
  635. },
  636. {
  637. name: "delete whole secret if only property should be removed",
  638. fields: fields{
  639. Client: &fakeClient{
  640. t: t,
  641. secretMap: map[string]*v1.Secret{
  642. "mysec": {
  643. Data: map[string][]byte{
  644. "token": []byte(`foobar`),
  645. },
  646. },
  647. },
  648. },
  649. },
  650. ref: v1alpha1.PushSecretRemoteRef{
  651. RemoteKey: "mysec",
  652. Property: "token",
  653. },
  654. wantErr: false,
  655. wantSecretMap: map[string]*v1.Secret{},
  656. },
  657. {
  658. name: "multiple properties, just remove that one",
  659. fields: fields{
  660. Client: &fakeClient{
  661. t: t,
  662. secretMap: map[string]*v1.Secret{
  663. "mysec": {
  664. Data: map[string][]byte{
  665. "token": []byte(`foo`),
  666. "secret": []byte(`bar`),
  667. },
  668. },
  669. },
  670. },
  671. },
  672. ref: v1alpha1.PushSecretRemoteRef{
  673. RemoteKey: "mysec",
  674. Property: "token",
  675. },
  676. wantErr: false,
  677. wantSecretMap: map[string]*v1.Secret{
  678. "mysec": {
  679. Data: map[string][]byte{
  680. "secret": []byte(`bar`),
  681. },
  682. },
  683. },
  684. },
  685. }
  686. for _, tt := range tests {
  687. t.Run(tt.name, func(t *testing.T) {
  688. p := &Client{
  689. userSecretClient: tt.fields.Client,
  690. }
  691. err := p.DeleteSecret(context.Background(), tt.ref)
  692. if (err != nil) != tt.wantErr {
  693. t.Errorf("ProviderKubernetes.DeleteSecret() error = %v, wantErr %v", err, tt.wantErr)
  694. return
  695. }
  696. fClient := tt.fields.Client.(*fakeClient)
  697. if diff := cmp.Diff(tt.wantSecretMap, fClient.secretMap); diff != "" {
  698. t.Errorf("Unexpected resulting secrets map: -want, +got :\n%s\n", diff)
  699. }
  700. })
  701. }
  702. }
  703. func TestPushSecret(t *testing.T) {
  704. type fields struct {
  705. Client KClient
  706. PushType v1.SecretType
  707. PushValue string
  708. }
  709. tests := []struct {
  710. name string
  711. fields fields
  712. ref esv1beta1.PushRemoteRef
  713. wantSecretMap map[string]*v1.Secret
  714. wantErr bool
  715. }{
  716. {
  717. name: "refuse to work without property",
  718. fields: fields{
  719. Client: &fakeClient{
  720. t: t,
  721. secretMap: map[string]*v1.Secret{
  722. "mysec": {
  723. Data: map[string][]byte{
  724. "token": []byte(`foo`),
  725. },
  726. },
  727. },
  728. },
  729. PushValue: "bar",
  730. },
  731. ref: v1alpha1.PushSecretRemoteRef{
  732. RemoteKey: "mysec",
  733. },
  734. wantErr: true,
  735. wantSecretMap: map[string]*v1.Secret{
  736. "mysec": {
  737. Data: map[string][]byte{
  738. "token": []byte(`foo`),
  739. },
  740. },
  741. },
  742. },
  743. {
  744. name: "add missing property to existing secret",
  745. fields: fields{
  746. Client: &fakeClient{
  747. t: t,
  748. secretMap: map[string]*v1.Secret{
  749. "mysec": {
  750. Data: map[string][]byte{
  751. "token": []byte(`foo`),
  752. },
  753. },
  754. },
  755. },
  756. PushValue: "bar",
  757. },
  758. ref: v1alpha1.PushSecretRemoteRef{
  759. RemoteKey: "mysec",
  760. Property: "secret",
  761. },
  762. wantErr: false,
  763. wantSecretMap: map[string]*v1.Secret{
  764. "mysec": {
  765. Data: map[string][]byte{
  766. "token": []byte(`foo`),
  767. "secret": []byte(`bar`),
  768. },
  769. },
  770. },
  771. },
  772. {
  773. name: "replace existing property in existing secret",
  774. fields: fields{
  775. Client: &fakeClient{
  776. t: t,
  777. secretMap: map[string]*v1.Secret{
  778. "mysec": {
  779. Data: map[string][]byte{
  780. "token": []byte(`foo`),
  781. },
  782. },
  783. },
  784. },
  785. PushValue: "bar",
  786. },
  787. ref: v1alpha1.PushSecretRemoteRef{
  788. RemoteKey: "mysec",
  789. Property: "token",
  790. },
  791. wantErr: false,
  792. wantSecretMap: map[string]*v1.Secret{
  793. "mysec": {
  794. Data: map[string][]byte{
  795. "token": []byte(`bar`),
  796. },
  797. },
  798. },
  799. },
  800. {
  801. name: "create new secret",
  802. fields: fields{
  803. Client: &fakeClient{
  804. t: t,
  805. secretMap: map[string]*v1.Secret{
  806. "yoursec": {
  807. Data: map[string][]byte{
  808. "token": []byte(`foo`),
  809. },
  810. },
  811. },
  812. },
  813. PushValue: "bar",
  814. },
  815. ref: v1alpha1.PushSecretRemoteRef{
  816. RemoteKey: "mysec",
  817. Property: "secret",
  818. },
  819. wantErr: false,
  820. wantSecretMap: map[string]*v1.Secret{
  821. "yoursec": {
  822. Data: map[string][]byte{
  823. "token": []byte(`foo`),
  824. },
  825. },
  826. "mysec": {
  827. Data: map[string][]byte{
  828. "secret": []byte(`bar`),
  829. },
  830. Type: v1.SecretTypeOpaque,
  831. },
  832. },
  833. },
  834. {
  835. name: "create new dockerconfigjson secret",
  836. fields: fields{
  837. Client: &fakeClient{
  838. t: t,
  839. secretMap: map[string]*v1.Secret{
  840. "yoursec": {
  841. Data: map[string][]byte{
  842. "token": []byte(`foo`),
  843. },
  844. },
  845. },
  846. },
  847. PushType: v1.SecretTypeDockerConfigJson,
  848. PushValue: `{"auths": {"myregistry.localhost": {"username": "{{ .username }}", "password": "{{ .password }}"}}}`,
  849. },
  850. ref: v1alpha1.PushSecretRemoteRef{
  851. RemoteKey: "mysec",
  852. Property: "config.json",
  853. },
  854. wantErr: false,
  855. wantSecretMap: map[string]*v1.Secret{
  856. "yoursec": {
  857. Data: map[string][]byte{
  858. "token": []byte(`foo`),
  859. },
  860. },
  861. "mysec": {
  862. Data: map[string][]byte{
  863. "config.json": []byte(`{"auths": {"myregistry.localhost": {"username": "{{ .username }}", "password": "{{ .password }}"}}}`),
  864. },
  865. Type: v1.SecretTypeDockerConfigJson,
  866. },
  867. },
  868. }}
  869. for _, tt := range tests {
  870. t.Run(tt.name, func(t *testing.T) {
  871. p := &Client{
  872. userSecretClient: tt.fields.Client,
  873. store: &esv1beta1.KubernetesProvider{},
  874. }
  875. err := p.PushSecret(context.Background(), []byte(tt.fields.PushValue), tt.fields.PushType, nil, tt.ref)
  876. if (err != nil) != tt.wantErr {
  877. t.Errorf("ProviderKubernetes.DeleteSecret() error = %v, wantErr %v", err, tt.wantErr)
  878. return
  879. }
  880. fClient := tt.fields.Client.(*fakeClient)
  881. if diff := cmp.Diff(tt.wantSecretMap, fClient.secretMap); diff != "" {
  882. t.Errorf("Unexpected resulting secrets map: -want, +got :\n%s\n", diff)
  883. }
  884. })
  885. }
  886. }