client_test.go 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461
  1. /*
  2. Copyright © 2025 ESO Maintainer Team
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. https://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package kubernetes
  14. import (
  15. "context"
  16. "errors"
  17. "reflect"
  18. "strings"
  19. "testing"
  20. "github.com/google/go-cmp/cmp"
  21. "github.com/stretchr/testify/assert"
  22. v1 "k8s.io/api/core/v1"
  23. apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
  24. apierrors "k8s.io/apimachinery/pkg/api/errors"
  25. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  26. "k8s.io/apimachinery/pkg/runtime/schema"
  27. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  28. "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
  29. testingfake "github.com/external-secrets/external-secrets/runtime/testing/fake"
  30. )
  31. const (
  32. errSomethingWentWrong = "Something went wrong"
  33. )
  34. type fakeClient struct {
  35. t *testing.T
  36. secretMap map[string]*v1.Secret
  37. expectedListOptions metav1.ListOptions
  38. err error
  39. }
  40. func (fk *fakeClient) Get(_ context.Context, name string, _ metav1.GetOptions) (*v1.Secret, error) {
  41. if fk.err != nil {
  42. return nil, fk.err
  43. }
  44. secret, ok := fk.secretMap[name]
  45. if !ok {
  46. return nil, apierrors.NewNotFound(schema.GroupResource{Group: "", Resource: "Secret"}, "secret")
  47. }
  48. // return inmutable to simulate external system and avoid accidental side effects
  49. sCopy := secret.DeepCopy()
  50. // update operation requires to relate names
  51. sCopy.Name = name
  52. return sCopy, nil
  53. }
  54. func (fk *fakeClient) List(_ context.Context, opts metav1.ListOptions) (*v1.SecretList, error) {
  55. assert.Equal(fk.t, fk.expectedListOptions, opts)
  56. list := &v1.SecretList{}
  57. for _, v := range fk.secretMap {
  58. list.Items = append(list.Items, *v)
  59. }
  60. return list, nil
  61. }
  62. func (fk *fakeClient) Delete(_ context.Context, name string, _ metav1.DeleteOptions) error {
  63. if fk.err != nil {
  64. return fk.err
  65. }
  66. _, ok := fk.secretMap[name]
  67. if !ok {
  68. return apierrors.NewNotFound(schema.GroupResource{Group: "", Resource: "Secret"}, "secret")
  69. }
  70. delete(fk.secretMap, name)
  71. return nil
  72. }
  73. func (fk *fakeClient) Create(_ context.Context, secret *v1.Secret, _ metav1.CreateOptions) (*v1.Secret, error) {
  74. s := &v1.Secret{
  75. Data: secret.Data,
  76. ObjectMeta: secret.ObjectMeta,
  77. Type: secret.Type,
  78. }
  79. fk.secretMap[secret.Name] = s
  80. return s, nil
  81. }
  82. func (fk *fakeClient) Update(_ context.Context, secret *v1.Secret, _ metav1.UpdateOptions) (*v1.Secret, error) {
  83. s, ok := fk.secretMap[secret.Name]
  84. if !ok {
  85. return nil, errors.New("error while updating secret")
  86. }
  87. s.ObjectMeta = secret.ObjectMeta
  88. s.Data = secret.Data
  89. return s, nil
  90. }
  91. var binaryTestData = []byte{0x00, 0xff, 0x00, 0xff, 0xac, 0xab, 0x28, 0x21}
  92. func TestGetSecret(t *testing.T) {
  93. tests := []struct {
  94. desc string
  95. secrets map[string]*v1.Secret
  96. clientErr error
  97. ref esv1.ExternalSecretDataRemoteRef
  98. want []byte
  99. wantErr string
  100. }{
  101. {
  102. desc: "secret data with correct property",
  103. secrets: map[string]*v1.Secret{
  104. "mysec": {
  105. Data: map[string][]byte{
  106. "token": []byte(`foobar`),
  107. },
  108. },
  109. },
  110. ref: esv1.ExternalSecretDataRemoteRef{
  111. Key: "mysec",
  112. Property: "token",
  113. },
  114. want: []byte(`foobar`),
  115. },
  116. {
  117. desc: "secret data with multi level property",
  118. secrets: map[string]*v1.Secret{
  119. "mysec": {
  120. Data: map[string][]byte{
  121. "foo": []byte(`{"huga":{"bar":"val"}}`),
  122. },
  123. },
  124. },
  125. ref: esv1.ExternalSecretDataRemoteRef{
  126. Key: "mysec",
  127. Property: "foo.huga.bar",
  128. },
  129. want: []byte(`val`),
  130. },
  131. {
  132. desc: "secret data with property containing .",
  133. secrets: map[string]*v1.Secret{
  134. "mysec": {
  135. Data: map[string][]byte{
  136. "foo.png": []byte(`correct`),
  137. "foo": []byte(`{"png":"wrong"}`),
  138. },
  139. },
  140. },
  141. ref: esv1.ExternalSecretDataRemoteRef{
  142. Key: "mysec",
  143. Property: "foo.png",
  144. },
  145. want: []byte(`correct`),
  146. },
  147. {
  148. desc: "secret data contains html characters",
  149. secrets: map[string]*v1.Secret{
  150. "mysec": {
  151. Data: map[string][]byte{
  152. "html": []byte(`<foobar>`),
  153. },
  154. },
  155. },
  156. ref: esv1.ExternalSecretDataRemoteRef{
  157. Key: "mysec",
  158. },
  159. want: []byte(`{"html":"<foobar>"}`),
  160. },
  161. {
  162. desc: "secret metadata contains html characters",
  163. secrets: map[string]*v1.Secret{
  164. "mysec": {
  165. ObjectMeta: metav1.ObjectMeta{
  166. Annotations: map[string]string{"date": "today"},
  167. Labels: map[string]string{"dev": "<seb>"},
  168. },
  169. },
  170. },
  171. ref: esv1.ExternalSecretDataRemoteRef{
  172. MetadataPolicy: esv1.ExternalSecretMetadataPolicyFetch,
  173. Key: "mysec",
  174. },
  175. want: []byte(`{"annotations":{"date":"today"},"labels":{"dev":"<seb>"}}`),
  176. },
  177. {
  178. desc: "secret data contains binary",
  179. secrets: map[string]*v1.Secret{
  180. "mysec": {
  181. Data: map[string][]byte{
  182. "bindata": binaryTestData,
  183. },
  184. },
  185. },
  186. ref: esv1.ExternalSecretDataRemoteRef{
  187. Key: "mysec",
  188. Property: "bindata",
  189. },
  190. want: binaryTestData,
  191. },
  192. {
  193. desc: "secret data without property",
  194. secrets: map[string]*v1.Secret{
  195. "mysec": {
  196. Data: map[string][]byte{
  197. "token": []byte(`foobar`),
  198. },
  199. },
  200. },
  201. ref: esv1.ExternalSecretDataRemoteRef{
  202. Key: "mysec",
  203. },
  204. want: []byte(`{"token":"foobar"}`),
  205. },
  206. {
  207. desc: "secret metadata without property",
  208. secrets: map[string]*v1.Secret{
  209. "mysec": {
  210. ObjectMeta: metav1.ObjectMeta{
  211. Annotations: map[string]string{"date": "today"},
  212. Labels: map[string]string{"dev": "seb"},
  213. },
  214. },
  215. },
  216. ref: esv1.ExternalSecretDataRemoteRef{
  217. MetadataPolicy: esv1.ExternalSecretMetadataPolicyFetch,
  218. Key: "mysec",
  219. },
  220. want: []byte(`{"annotations":{"date":"today"},"labels":{"dev":"seb"}}`),
  221. },
  222. {
  223. desc: "secret metadata with single level property",
  224. secrets: map[string]*v1.Secret{
  225. "mysec": {
  226. ObjectMeta: metav1.ObjectMeta{
  227. Annotations: map[string]string{"date": "today"},
  228. Labels: map[string]string{"dev": "seb"},
  229. },
  230. },
  231. },
  232. ref: esv1.ExternalSecretDataRemoteRef{
  233. MetadataPolicy: esv1.ExternalSecretMetadataPolicyFetch,
  234. Key: "mysec",
  235. Property: "labels",
  236. },
  237. want: []byte(`{"dev":"seb"}`),
  238. },
  239. {
  240. desc: "secret metadata with multiple level property",
  241. secrets: map[string]*v1.Secret{
  242. "mysec": {
  243. ObjectMeta: metav1.ObjectMeta{
  244. Annotations: map[string]string{"date": "today"},
  245. Labels: map[string]string{"dev": "seb"},
  246. },
  247. },
  248. },
  249. ref: esv1.ExternalSecretDataRemoteRef{
  250. MetadataPolicy: esv1.ExternalSecretMetadataPolicyFetch,
  251. Key: "mysec",
  252. Property: "labels.dev",
  253. },
  254. want: []byte(`seb`),
  255. },
  256. {
  257. desc: "secret is not found",
  258. clientErr: apierrors.NewNotFound(schema.GroupResource{Group: "", Resource: "Secret"}, "secret"),
  259. ref: esv1.ExternalSecretDataRemoteRef{
  260. Key: "mysec",
  261. Property: "token",
  262. },
  263. wantErr: `Secret "secret" not found`,
  264. },
  265. {
  266. desc: "secret data with wrong property",
  267. secrets: map[string]*v1.Secret{
  268. "mysec": {
  269. Data: map[string][]byte{
  270. "token": []byte(`foobar`),
  271. },
  272. },
  273. },
  274. ref: esv1.ExternalSecretDataRemoteRef{
  275. Key: "mysec",
  276. Property: "not-the-token",
  277. },
  278. wantErr: "property not-the-token does not exist in data of secret",
  279. },
  280. {
  281. desc: "secret metadata with wrong property",
  282. secrets: map[string]*v1.Secret{
  283. "mysec": {
  284. ObjectMeta: metav1.ObjectMeta{
  285. Annotations: map[string]string{"date": "today"},
  286. Labels: map[string]string{"dev": "seb"},
  287. },
  288. },
  289. },
  290. ref: esv1.ExternalSecretDataRemoteRef{
  291. MetadataPolicy: esv1.ExternalSecretMetadataPolicyFetch,
  292. Key: "mysec",
  293. Property: "foo",
  294. },
  295. wantErr: "property foo does not exist in metadata of secret",
  296. },
  297. }
  298. for _, tt := range tests {
  299. t.Run(tt.desc, func(t *testing.T) {
  300. p := &Client{
  301. userSecretClient: &fakeClient{t: t, secretMap: tt.secrets, err: tt.clientErr},
  302. namespace: "default",
  303. }
  304. got, err := p.GetSecret(context.Background(), tt.ref)
  305. if err != nil {
  306. if tt.wantErr == "" {
  307. t.Fatalf("failed to call GetSecret: %v", err)
  308. }
  309. if !strings.Contains(err.Error(), tt.wantErr) {
  310. t.Fatalf("received an unexpected error: %q should have contained %q", err.Error(), tt.wantErr)
  311. }
  312. return
  313. }
  314. if tt.wantErr != "" {
  315. t.Fatalf("expected to receive an error but got nil")
  316. }
  317. if !reflect.DeepEqual(got, tt.want) {
  318. t.Fatalf("received an unexpected secret: got: %s, want %s", got, tt.want)
  319. }
  320. })
  321. }
  322. }
  323. func TestGetSecretMap(t *testing.T) {
  324. type fields struct {
  325. Client KClient
  326. ReviewClient RClient
  327. Namespace string
  328. }
  329. tests := []struct {
  330. name string
  331. fields fields
  332. ref esv1.ExternalSecretDataRemoteRef
  333. want map[string][]byte
  334. wantErr bool
  335. wantErrMsg string
  336. }{
  337. {
  338. name: "successful case metadata without property",
  339. fields: fields{
  340. Client: &fakeClient{
  341. t: t,
  342. secretMap: map[string]*v1.Secret{
  343. "mysec": {
  344. ObjectMeta: metav1.ObjectMeta{
  345. Annotations: map[string]string{"date": "today"},
  346. Labels: map[string]string{"dev": "seb"},
  347. },
  348. },
  349. },
  350. },
  351. Namespace: "default",
  352. },
  353. ref: esv1.ExternalSecretDataRemoteRef{
  354. MetadataPolicy: esv1.ExternalSecretMetadataPolicyFetch,
  355. Key: "mysec",
  356. },
  357. want: map[string][]byte{"annotations": []byte("{\"date\":\"today\"}"), "labels": []byte("{\"dev\":\"seb\"}")},
  358. },
  359. {
  360. name: "successful case metadata with single property",
  361. fields: fields{
  362. Client: &fakeClient{
  363. t: t,
  364. secretMap: map[string]*v1.Secret{
  365. "mysec": {
  366. ObjectMeta: metav1.ObjectMeta{
  367. Annotations: map[string]string{"date": "today"},
  368. Labels: map[string]string{"dev": "seb"},
  369. },
  370. },
  371. },
  372. },
  373. Namespace: "default",
  374. },
  375. ref: esv1.ExternalSecretDataRemoteRef{
  376. MetadataPolicy: esv1.ExternalSecretMetadataPolicyFetch,
  377. Key: "mysec",
  378. Property: "labels",
  379. },
  380. want: map[string][]byte{"dev": []byte("\"seb\"")},
  381. },
  382. {
  383. name: "error case metadata with wrong property",
  384. fields: fields{
  385. Client: &fakeClient{
  386. t: t,
  387. secretMap: map[string]*v1.Secret{
  388. "mysec": {
  389. ObjectMeta: metav1.ObjectMeta{
  390. Annotations: map[string]string{"date": "today"},
  391. Labels: map[string]string{"dev": "seb"},
  392. },
  393. },
  394. },
  395. },
  396. Namespace: "default",
  397. },
  398. ref: esv1.ExternalSecretDataRemoteRef{
  399. MetadataPolicy: esv1.ExternalSecretMetadataPolicyFetch,
  400. Key: "mysec",
  401. Property: "foo",
  402. },
  403. wantErr: true,
  404. },
  405. {
  406. // Security regression test: ensure json.Unmarshal errors don't leak secret data
  407. name: "invalid JSON in property does not leak secret data in error message",
  408. fields: fields{
  409. Client: &fakeClient{
  410. t: t,
  411. secretMap: map[string]*v1.Secret{
  412. "mysec": {
  413. Data: map[string][]byte{
  414. // Base64 encoded invalid JSON containing sensitive data
  415. // "secret-api-key-8019210420527506405" base64 encoded
  416. "nested": []byte("c2VjcmV0LWFwaS1rZXktODAxOTIxMDQyMDUyNzUwNjQwNQ=="),
  417. },
  418. },
  419. },
  420. },
  421. Namespace: "default",
  422. },
  423. ref: esv1.ExternalSecretDataRemoteRef{
  424. Key: "mysec",
  425. Property: "nested",
  426. },
  427. wantErr: true,
  428. wantErrMsg: "failed to unmarshal secret: invalid JSON format",
  429. },
  430. }
  431. for _, tt := range tests {
  432. t.Run(tt.name, func(t *testing.T) {
  433. p := &Client{
  434. userSecretClient: tt.fields.Client,
  435. userReviewClient: tt.fields.ReviewClient,
  436. namespace: tt.fields.Namespace,
  437. }
  438. got, err := p.GetSecretMap(context.Background(), tt.ref)
  439. if (err != nil) != tt.wantErr {
  440. t.Errorf("ProviderKubernetes.GetSecretMap() error = %v, wantErr %v", err, tt.wantErr)
  441. return
  442. }
  443. if tt.wantErrMsg != "" && err != nil {
  444. if !strings.Contains(err.Error(), tt.wantErrMsg) {
  445. t.Errorf("ProviderKubernetes.GetSecretMap() error = %v, wantErrMsg %v", err, tt.wantErrMsg)
  446. }
  447. // Security regression: ensure error doesn't contain sensitive data
  448. sensitiveData := "secret-api-key-8019210420527506405"
  449. if strings.Contains(err.Error(), sensitiveData) {
  450. t.Errorf("SECURITY REGRESSION: Error message contains secret data! error = %v", err)
  451. }
  452. }
  453. if !reflect.DeepEqual(got, tt.want) {
  454. t.Errorf("ProviderKubernetes.GetSecretMap() = %v, want %v", got, tt.want)
  455. }
  456. })
  457. }
  458. }
  459. func TestGetAllSecrets(t *testing.T) {
  460. type fields struct {
  461. Client KClient
  462. ReviewClient RClient
  463. Namespace string
  464. }
  465. type args struct {
  466. ctx context.Context
  467. ref esv1.ExternalSecretFind
  468. }
  469. tests := []struct {
  470. name string
  471. fields fields
  472. args args
  473. want map[string][]byte
  474. wantErr bool
  475. }{
  476. {
  477. name: "use regex",
  478. fields: fields{
  479. Client: &fakeClient{
  480. t: t,
  481. secretMap: map[string]*v1.Secret{
  482. "mysec": {
  483. ObjectMeta: metav1.ObjectMeta{
  484. Name: "mysec",
  485. },
  486. Data: map[string][]byte{
  487. "token": []byte(`foo`),
  488. },
  489. },
  490. "other": {
  491. ObjectMeta: metav1.ObjectMeta{
  492. Name: "other",
  493. },
  494. Data: map[string][]byte{
  495. "token": []byte(`bar`),
  496. },
  497. },
  498. },
  499. },
  500. },
  501. args: args{
  502. ref: esv1.ExternalSecretFind{
  503. Name: &esv1.FindName{
  504. RegExp: "other",
  505. },
  506. },
  507. },
  508. want: map[string][]byte{
  509. "other": []byte(`{"token":"bar"}`),
  510. },
  511. },
  512. {
  513. name: "use tags/labels",
  514. fields: fields{
  515. Client: &fakeClient{
  516. t: t,
  517. expectedListOptions: metav1.ListOptions{
  518. LabelSelector: "app=foobar",
  519. },
  520. secretMap: map[string]*v1.Secret{
  521. "mysec": {
  522. ObjectMeta: metav1.ObjectMeta{
  523. Name: "mysec",
  524. },
  525. Data: map[string][]byte{
  526. "token": []byte(`foo`),
  527. },
  528. },
  529. "other": {
  530. ObjectMeta: metav1.ObjectMeta{
  531. Name: "other",
  532. },
  533. Data: map[string][]byte{
  534. "token": []byte(`bar`),
  535. },
  536. },
  537. },
  538. },
  539. },
  540. args: args{
  541. ref: esv1.ExternalSecretFind{
  542. Tags: map[string]string{
  543. "app": "foobar",
  544. },
  545. },
  546. },
  547. want: map[string][]byte{
  548. "mysec": []byte(`{"token":"foo"}`),
  549. "other": []byte(`{"token":"bar"}`),
  550. },
  551. },
  552. }
  553. for _, tt := range tests {
  554. t.Run(tt.name, func(t *testing.T) {
  555. p := &Client{
  556. userSecretClient: tt.fields.Client,
  557. userReviewClient: tt.fields.ReviewClient,
  558. namespace: tt.fields.Namespace,
  559. }
  560. got, err := p.GetAllSecrets(tt.args.ctx, tt.args.ref)
  561. if (err != nil) != tt.wantErr {
  562. t.Errorf("ProviderKubernetes.GetAllSecrets() error = %v, wantErr %v", err, tt.wantErr)
  563. return
  564. }
  565. if !reflect.DeepEqual(got, tt.want) {
  566. t.Errorf("ProviderKubernetes.GetAllSecrets() = %v, want %v", got, tt.want)
  567. }
  568. })
  569. }
  570. }
  571. func TestDeleteSecret(t *testing.T) {
  572. type fields struct {
  573. Client KClient
  574. }
  575. tests := []struct {
  576. name string
  577. fields fields
  578. ref esv1.PushSecretRemoteRef
  579. wantSecretMap map[string]*v1.Secret
  580. wantErr bool
  581. }{
  582. {
  583. name: "delete whole secret if no property specified",
  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. },
  599. wantErr: false,
  600. wantSecretMap: map[string]*v1.Secret{},
  601. },
  602. {
  603. name: "delete whole secret if no property specified and empty properties",
  604. fields: fields{
  605. Client: &fakeClient{
  606. t: t,
  607. secretMap: map[string]*v1.Secret{},
  608. },
  609. },
  610. ref: v1alpha1.PushSecretRemoteRef{
  611. RemoteKey: "mysec",
  612. },
  613. wantErr: false,
  614. wantSecretMap: map[string]*v1.Secret{},
  615. },
  616. {
  617. name: "gracefully ignore not found secret",
  618. fields: fields{
  619. Client: &fakeClient{
  620. t: t,
  621. secretMap: map[string]*v1.Secret{},
  622. },
  623. },
  624. ref: v1alpha1.PushSecretRemoteRef{
  625. RemoteKey: "mysec",
  626. Property: "token",
  627. },
  628. wantErr: false,
  629. wantSecretMap: map[string]*v1.Secret{},
  630. },
  631. {
  632. name: "gracefully ignore not found property",
  633. fields: fields{
  634. Client: &fakeClient{
  635. t: t,
  636. secretMap: map[string]*v1.Secret{
  637. "mysec": {
  638. Data: map[string][]byte{
  639. "token": []byte(`foobar`),
  640. },
  641. },
  642. },
  643. },
  644. },
  645. ref: v1alpha1.PushSecretRemoteRef{
  646. RemoteKey: "mysec",
  647. Property: "secret",
  648. },
  649. wantErr: false,
  650. wantSecretMap: map[string]*v1.Secret{
  651. "mysec": {
  652. Data: map[string][]byte{
  653. "token": []byte(`foobar`),
  654. },
  655. },
  656. },
  657. },
  658. {
  659. name: "unexpected lookup error",
  660. fields: fields{
  661. Client: &fakeClient{
  662. t: t,
  663. secretMap: map[string]*v1.Secret{
  664. "mysec": {
  665. Data: map[string][]byte{
  666. "token": []byte(`foobar`),
  667. },
  668. },
  669. },
  670. err: errors.New(errSomethingWentWrong),
  671. },
  672. },
  673. ref: v1alpha1.PushSecretRemoteRef{
  674. RemoteKey: "mysec",
  675. },
  676. wantErr: true,
  677. wantSecretMap: map[string]*v1.Secret{
  678. "mysec": {
  679. Data: map[string][]byte{
  680. "token": []byte(`foobar`),
  681. },
  682. },
  683. },
  684. },
  685. {
  686. name: "delete whole secret if only property should be removed",
  687. fields: fields{
  688. Client: &fakeClient{
  689. t: t,
  690. secretMap: map[string]*v1.Secret{
  691. "mysec": {
  692. Data: map[string][]byte{
  693. "token": []byte(`foobar`),
  694. },
  695. },
  696. },
  697. },
  698. },
  699. ref: v1alpha1.PushSecretRemoteRef{
  700. RemoteKey: "mysec",
  701. Property: "token",
  702. },
  703. wantErr: false,
  704. wantSecretMap: map[string]*v1.Secret{},
  705. },
  706. {
  707. name: "multiple properties, just remove that one",
  708. fields: fields{
  709. Client: &fakeClient{
  710. t: t,
  711. secretMap: map[string]*v1.Secret{
  712. "mysec": {
  713. Data: map[string][]byte{
  714. "token": []byte(`foo`),
  715. "secret": []byte(`bar`),
  716. },
  717. },
  718. },
  719. },
  720. },
  721. ref: v1alpha1.PushSecretRemoteRef{
  722. RemoteKey: "mysec",
  723. Property: "token",
  724. },
  725. wantErr: false,
  726. wantSecretMap: map[string]*v1.Secret{
  727. "mysec": {
  728. ObjectMeta: metav1.ObjectMeta{
  729. Name: "mysec",
  730. },
  731. Data: map[string][]byte{
  732. "secret": []byte(`bar`),
  733. },
  734. },
  735. },
  736. },
  737. }
  738. for _, tt := range tests {
  739. t.Run(tt.name, func(t *testing.T) {
  740. p := &Client{
  741. userSecretClient: tt.fields.Client,
  742. }
  743. err := p.DeleteSecret(context.Background(), tt.ref)
  744. if (err != nil) != tt.wantErr {
  745. t.Errorf("ProviderKubernetes.DeleteSecret() error = %v, wantErr %v", err, tt.wantErr)
  746. return
  747. }
  748. fClient := tt.fields.Client.(*fakeClient)
  749. if diff := cmp.Diff(tt.wantSecretMap, fClient.secretMap); diff != "" {
  750. t.Errorf("Unexpected resulting secrets map: -want, +got :\n%s\n", diff)
  751. }
  752. })
  753. }
  754. }
  755. func TestPushSecret(t *testing.T) {
  756. secretKey := "secret-key"
  757. type fields struct {
  758. Client KClient
  759. }
  760. tests := []struct {
  761. name string
  762. fields fields
  763. data testingfake.PushSecretData
  764. secret *v1.Secret
  765. wantSecretMap map[string]*v1.Secret
  766. wantErr bool
  767. }{
  768. {
  769. name: "refuse to work without property if secret key is provided",
  770. fields: fields{
  771. Client: &fakeClient{
  772. t: t,
  773. secretMap: map[string]*v1.Secret{
  774. "mysec": {
  775. Data: map[string][]byte{
  776. "token": []byte(`foo`),
  777. },
  778. },
  779. },
  780. },
  781. },
  782. data: testingfake.PushSecretData{
  783. SecretKey: secretKey,
  784. RemoteKey: "mysec",
  785. },
  786. secret: &v1.Secret{
  787. Data: map[string][]byte{secretKey: []byte("bar")},
  788. },
  789. wantErr: true,
  790. wantSecretMap: map[string]*v1.Secret{
  791. "mysec": {
  792. Data: map[string][]byte{
  793. "token": []byte(`foo`),
  794. },
  795. },
  796. },
  797. },
  798. {
  799. name: "push the whole secret if neither remote property or secretKey is defined but keep existing keys",
  800. fields: fields{
  801. Client: &fakeClient{
  802. t: t,
  803. secretMap: map[string]*v1.Secret{
  804. "mysec": {
  805. Data: map[string][]byte{
  806. "token": []byte(`foo`),
  807. },
  808. },
  809. },
  810. },
  811. },
  812. data: testingfake.PushSecretData{
  813. RemoteKey: "mysec",
  814. },
  815. secret: &v1.Secret{
  816. Data: map[string][]byte{"token2": []byte("foo")},
  817. },
  818. wantSecretMap: map[string]*v1.Secret{
  819. "mysec": {
  820. ObjectMeta: metav1.ObjectMeta{
  821. Name: "mysec",
  822. Labels: map[string]string{},
  823. Annotations: map[string]string{},
  824. },
  825. Data: map[string][]byte{
  826. "token": []byte(`foo`),
  827. "token2": []byte(`foo`),
  828. },
  829. },
  830. },
  831. },
  832. {
  833. name: "push the whole secret while secret exists into a single property",
  834. fields: fields{
  835. Client: &fakeClient{
  836. t: t,
  837. secretMap: map[string]*v1.Secret{
  838. "mysec": {
  839. Data: map[string][]byte{
  840. "token": []byte(`foo`),
  841. },
  842. },
  843. },
  844. },
  845. },
  846. data: testingfake.PushSecretData{
  847. RemoteKey: "mysec",
  848. Property: "token",
  849. },
  850. secret: &v1.Secret{
  851. Data: map[string][]byte{"foo": []byte("bar")},
  852. },
  853. wantSecretMap: map[string]*v1.Secret{
  854. "mysec": {
  855. ObjectMeta: metav1.ObjectMeta{
  856. Name: "mysec",
  857. Labels: map[string]string{},
  858. Annotations: map[string]string{},
  859. },
  860. Data: map[string][]byte{
  861. "token": []byte(`{"foo":"bar"}`),
  862. },
  863. },
  864. },
  865. },
  866. {
  867. name: "push the whole secret while secret exists but new property is defined should update the secret and keep existing key",
  868. fields: fields{
  869. Client: &fakeClient{
  870. t: t,
  871. secretMap: map[string]*v1.Secret{
  872. "mysec": {
  873. Data: map[string][]byte{
  874. "token": []byte(`foo`),
  875. },
  876. },
  877. },
  878. },
  879. },
  880. data: testingfake.PushSecretData{
  881. RemoteKey: "mysec",
  882. Property: "token2",
  883. },
  884. secret: &v1.Secret{
  885. Data: map[string][]byte{"foo": []byte("bar")},
  886. },
  887. wantSecretMap: map[string]*v1.Secret{
  888. "mysec": {
  889. ObjectMeta: metav1.ObjectMeta{
  890. Name: "mysec",
  891. Labels: map[string]string{},
  892. Annotations: map[string]string{},
  893. },
  894. Data: map[string][]byte{
  895. "token": []byte(`foo`),
  896. "token2": []byte(`{"foo":"bar"}`),
  897. },
  898. },
  899. },
  900. },
  901. {
  902. name: "push the whole secret as json if remote property is defined but secret key is not given",
  903. fields: fields{
  904. Client: &fakeClient{
  905. t: t,
  906. secretMap: map[string]*v1.Secret{},
  907. },
  908. },
  909. data: testingfake.PushSecretData{
  910. RemoteKey: "mysec",
  911. Property: "marshaled",
  912. },
  913. secret: &v1.Secret{
  914. Data: map[string][]byte{
  915. "token": []byte("foo"),
  916. "token2": []byte("2"),
  917. },
  918. },
  919. wantSecretMap: map[string]*v1.Secret{
  920. "mysec": {
  921. ObjectMeta: metav1.ObjectMeta{
  922. Name: "mysec",
  923. Labels: map[string]string{},
  924. Annotations: map[string]string{},
  925. },
  926. Data: map[string][]byte{
  927. "marshaled": []byte(`{"token":"foo","token2":"2"}`),
  928. },
  929. Type: "Opaque",
  930. },
  931. },
  932. },
  933. {
  934. name: "add missing property to existing secret",
  935. fields: fields{
  936. Client: &fakeClient{
  937. t: t,
  938. secretMap: map[string]*v1.Secret{
  939. "mysec": {
  940. Data: map[string][]byte{
  941. "token": []byte(`foo`),
  942. },
  943. },
  944. },
  945. },
  946. },
  947. secret: &v1.Secret{
  948. Data: map[string][]byte{secretKey: []byte("bar")},
  949. },
  950. data: testingfake.PushSecretData{
  951. SecretKey: secretKey,
  952. RemoteKey: "mysec",
  953. Property: "secret",
  954. },
  955. wantErr: false,
  956. wantSecretMap: map[string]*v1.Secret{
  957. "mysec": {
  958. ObjectMeta: metav1.ObjectMeta{
  959. Name: "mysec",
  960. Labels: map[string]string{},
  961. Annotations: map[string]string{},
  962. },
  963. Data: map[string][]byte{
  964. "token": []byte(`foo`),
  965. "secret": []byte(`bar`),
  966. },
  967. },
  968. },
  969. },
  970. {
  971. name: "replace existing property in existing secret",
  972. fields: fields{
  973. Client: &fakeClient{
  974. t: t,
  975. secretMap: map[string]*v1.Secret{
  976. "mysec": {
  977. Data: map[string][]byte{
  978. "token": []byte(`foo`),
  979. },
  980. },
  981. },
  982. },
  983. },
  984. secret: &v1.Secret{
  985. Data: map[string][]byte{secretKey: []byte("bar")},
  986. },
  987. data: testingfake.PushSecretData{
  988. SecretKey: secretKey,
  989. RemoteKey: "mysec",
  990. Property: "token",
  991. },
  992. wantErr: false,
  993. wantSecretMap: map[string]*v1.Secret{
  994. "mysec": {
  995. ObjectMeta: metav1.ObjectMeta{
  996. Name: "mysec",
  997. Labels: map[string]string{},
  998. Annotations: map[string]string{},
  999. },
  1000. Data: map[string][]byte{
  1001. "token": []byte(`bar`),
  1002. },
  1003. },
  1004. },
  1005. },
  1006. {
  1007. name: "replace existing property in existing secret with targetMergePolicy set to Ignore",
  1008. fields: fields{
  1009. Client: &fakeClient{
  1010. t: t,
  1011. secretMap: map[string]*v1.Secret{
  1012. "mysec": {
  1013. Data: map[string][]byte{
  1014. "token": []byte(`foo`),
  1015. },
  1016. },
  1017. },
  1018. },
  1019. },
  1020. secret: &v1.Secret{
  1021. ObjectMeta: metav1.ObjectMeta{
  1022. Name: "mysec",
  1023. // these should be ignored as the targetMergePolicy is set to Ignore
  1024. Labels: map[string]string{"dev": "seb"},
  1025. Annotations: map[string]string{"date": "today"},
  1026. },
  1027. Data: map[string][]byte{secretKey: []byte("bar")},
  1028. },
  1029. data: testingfake.PushSecretData{
  1030. SecretKey: secretKey,
  1031. RemoteKey: "mysec",
  1032. Property: "token",
  1033. Metadata: &apiextensionsv1.JSON{
  1034. Raw: []byte(`{"apiVersion":"kubernetes.external-secrets.io/v1alpha1", "kind": "PushSecretMetadata", spec: {"targetMergePolicy": "Ignore"}}`),
  1035. },
  1036. },
  1037. wantErr: false,
  1038. wantSecretMap: map[string]*v1.Secret{
  1039. "mysec": {
  1040. ObjectMeta: metav1.ObjectMeta{
  1041. Name: "mysec",
  1042. Labels: map[string]string{},
  1043. Annotations: map[string]string{},
  1044. },
  1045. Data: map[string][]byte{
  1046. "token": []byte(`bar`),
  1047. },
  1048. },
  1049. },
  1050. },
  1051. {
  1052. name: "replace existing property in existing secret with targetMergePolicy set to Replace",
  1053. fields: fields{
  1054. Client: &fakeClient{
  1055. t: t,
  1056. secretMap: map[string]*v1.Secret{
  1057. "mysec": {
  1058. ObjectMeta: metav1.ObjectMeta{
  1059. Name: "mysec",
  1060. Labels: map[string]string{
  1061. "already": "existing",
  1062. },
  1063. Annotations: map[string]string{
  1064. "already": "existing",
  1065. },
  1066. },
  1067. Data: map[string][]byte{
  1068. "token": []byte(`foo`),
  1069. },
  1070. },
  1071. },
  1072. },
  1073. },
  1074. secret: &v1.Secret{
  1075. ObjectMeta: metav1.ObjectMeta{
  1076. Name: "mysec",
  1077. // these should replace existing metadata as the targetMergePolicy is set to Replace
  1078. Labels: map[string]string{"dev": "seb"},
  1079. Annotations: map[string]string{"date": "today"},
  1080. },
  1081. Data: map[string][]byte{secretKey: []byte("bar")},
  1082. },
  1083. data: testingfake.PushSecretData{
  1084. SecretKey: secretKey,
  1085. RemoteKey: "mysec",
  1086. Property: "token",
  1087. Metadata: &apiextensionsv1.JSON{
  1088. Raw: []byte(`{"apiVersion":"kubernetes.external-secrets.io/v1alpha1", "kind": "PushSecretMetadata", spec: {"targetMergePolicy": "Replace"}}`),
  1089. },
  1090. },
  1091. wantErr: false,
  1092. wantSecretMap: map[string]*v1.Secret{
  1093. "mysec": {
  1094. ObjectMeta: metav1.ObjectMeta{
  1095. Name: "mysec",
  1096. Labels: map[string]string{
  1097. "dev": "seb",
  1098. },
  1099. Annotations: map[string]string{
  1100. "date": "today",
  1101. },
  1102. },
  1103. Data: map[string][]byte{
  1104. "token": []byte(`bar`),
  1105. },
  1106. },
  1107. },
  1108. },
  1109. {
  1110. name: "create new secret, merging existing metadata",
  1111. fields: fields{
  1112. Client: &fakeClient{
  1113. t: t,
  1114. secretMap: map[string]*v1.Secret{
  1115. "yoursec": {
  1116. Data: map[string][]byte{
  1117. "token": []byte(`foo`),
  1118. },
  1119. },
  1120. },
  1121. },
  1122. },
  1123. secret: &v1.Secret{
  1124. ObjectMeta: metav1.ObjectMeta{
  1125. Annotations: map[string]string{
  1126. "this-annotation": "should be present on the targey secret",
  1127. },
  1128. },
  1129. Data: map[string][]byte{secretKey: []byte("bar")},
  1130. },
  1131. data: testingfake.PushSecretData{
  1132. SecretKey: secretKey,
  1133. RemoteKey: "mysec",
  1134. Property: "secret",
  1135. Metadata: &apiextensionsv1.JSON{
  1136. Raw: []byte(`{"apiVersion":"kubernetes.external-secrets.io/v1alpha1", "kind": "PushSecretMetadata", spec: {"annotations": {"date": "today"}, "labels": {"dev": "seb"}}}`),
  1137. },
  1138. },
  1139. wantErr: false,
  1140. wantSecretMap: map[string]*v1.Secret{
  1141. "yoursec": {
  1142. Data: map[string][]byte{
  1143. "token": []byte(`foo`),
  1144. },
  1145. },
  1146. "mysec": {
  1147. ObjectMeta: metav1.ObjectMeta{
  1148. Name: "mysec",
  1149. Annotations: map[string]string{
  1150. "date": "today",
  1151. "this-annotation": "should be present on the targey secret",
  1152. },
  1153. Labels: map[string]string{"dev": "seb"},
  1154. },
  1155. Data: map[string][]byte{
  1156. "secret": []byte(`bar`),
  1157. },
  1158. Type: v1.SecretTypeOpaque,
  1159. },
  1160. },
  1161. },
  1162. {
  1163. name: "create new secret with metadata from secret metadata and remoteRef.metadata",
  1164. fields: fields{
  1165. Client: &fakeClient{
  1166. t: t,
  1167. secretMap: map[string]*v1.Secret{
  1168. "yoursec": {
  1169. Data: map[string][]byte{
  1170. "token": []byte(`foo`),
  1171. },
  1172. },
  1173. },
  1174. },
  1175. },
  1176. secret: &v1.Secret{
  1177. ObjectMeta: metav1.ObjectMeta{
  1178. Annotations: map[string]string{"date": "today"},
  1179. Labels: map[string]string{"dev": "seb"},
  1180. },
  1181. Data: map[string][]byte{secretKey: []byte("bar")},
  1182. },
  1183. data: testingfake.PushSecretData{
  1184. SecretKey: secretKey,
  1185. RemoteKey: "mysec",
  1186. Property: "secret",
  1187. Metadata: &apiextensionsv1.JSON{
  1188. Raw: []byte(
  1189. `{"apiVersion":"kubernetes.external-secrets.io/v1alpha1", "kind": "PushSecretMetadata", spec: { "sourceMergePolicy": "Replace", "annotations": {"another-field": "from-remote-ref"}, "labels": {"other-label": "from-remote-ref"}}}`,
  1190. ),
  1191. },
  1192. },
  1193. wantErr: false,
  1194. wantSecretMap: map[string]*v1.Secret{
  1195. "yoursec": {
  1196. Data: map[string][]byte{
  1197. "token": []byte(`foo`),
  1198. },
  1199. },
  1200. "mysec": {
  1201. ObjectMeta: metav1.ObjectMeta{
  1202. Name: "mysec",
  1203. Annotations: map[string]string{
  1204. "another-field": "from-remote-ref",
  1205. },
  1206. Labels: map[string]string{
  1207. "other-label": "from-remote-ref",
  1208. },
  1209. },
  1210. Data: map[string][]byte{
  1211. "secret": []byte(`bar`),
  1212. },
  1213. Type: v1.SecretTypeOpaque,
  1214. },
  1215. },
  1216. },
  1217. {
  1218. name: "invalid secret metadata structure results in error",
  1219. fields: fields{
  1220. Client: &fakeClient{
  1221. t: t,
  1222. secretMap: map[string]*v1.Secret{
  1223. "yoursec": {
  1224. Data: map[string][]byte{
  1225. "token": []byte(`foo`),
  1226. },
  1227. },
  1228. },
  1229. },
  1230. },
  1231. secret: &v1.Secret{
  1232. Data: map[string][]byte{secretKey: []byte("bar")},
  1233. },
  1234. data: testingfake.PushSecretData{
  1235. SecretKey: secretKey,
  1236. RemoteKey: "mysec",
  1237. Property: "secret",
  1238. Metadata: &apiextensionsv1.JSON{
  1239. Raw: []byte(`{}`),
  1240. },
  1241. },
  1242. wantErr: true,
  1243. wantSecretMap: map[string]*v1.Secret{
  1244. "yoursec": {
  1245. Data: map[string][]byte{
  1246. "token": []byte(`foo`),
  1247. },
  1248. },
  1249. },
  1250. },
  1251. {
  1252. name: "non-json secret metadata results in error",
  1253. fields: fields{
  1254. Client: &fakeClient{
  1255. t: t,
  1256. secretMap: map[string]*v1.Secret{
  1257. "yoursec": {
  1258. Data: map[string][]byte{
  1259. "token": []byte(`foo`),
  1260. },
  1261. },
  1262. },
  1263. },
  1264. },
  1265. secret: &v1.Secret{
  1266. Data: map[string][]byte{secretKey: []byte("bar")},
  1267. },
  1268. data: testingfake.PushSecretData{
  1269. SecretKey: secretKey,
  1270. RemoteKey: "mysec",
  1271. Property: "secret",
  1272. Metadata: &apiextensionsv1.JSON{
  1273. Raw: []byte(`--- not json ---`),
  1274. },
  1275. },
  1276. wantErr: true,
  1277. wantSecretMap: map[string]*v1.Secret{
  1278. "yoursec": {
  1279. Data: map[string][]byte{
  1280. "token": []byte(`foo`),
  1281. },
  1282. },
  1283. },
  1284. },
  1285. {
  1286. name: "create new secret with whole secret",
  1287. fields: fields{
  1288. Client: &fakeClient{
  1289. t: t,
  1290. secretMap: map[string]*v1.Secret{
  1291. "yoursec": {
  1292. Data: map[string][]byte{
  1293. "token": []byte(`foo`),
  1294. },
  1295. },
  1296. },
  1297. },
  1298. },
  1299. secret: &v1.Secret{
  1300. Data: map[string][]byte{
  1301. "foo": []byte("bar"),
  1302. "baz": []byte("bang"),
  1303. },
  1304. },
  1305. data: testingfake.PushSecretData{
  1306. RemoteKey: "mysec",
  1307. },
  1308. wantErr: false,
  1309. wantSecretMap: map[string]*v1.Secret{
  1310. "yoursec": {
  1311. Data: map[string][]byte{
  1312. "token": []byte(`foo`),
  1313. },
  1314. },
  1315. "mysec": {
  1316. ObjectMeta: metav1.ObjectMeta{
  1317. Name: "mysec",
  1318. Labels: map[string]string{},
  1319. Annotations: map[string]string{},
  1320. },
  1321. Data: map[string][]byte{
  1322. "foo": []byte("bar"),
  1323. "baz": []byte("bang"),
  1324. },
  1325. Type: v1.SecretTypeOpaque,
  1326. },
  1327. },
  1328. },
  1329. {
  1330. name: "create new dockerconfigjson secret",
  1331. fields: fields{
  1332. Client: &fakeClient{
  1333. t: t,
  1334. secretMap: map[string]*v1.Secret{
  1335. "yoursec": {
  1336. Data: map[string][]byte{
  1337. "token": []byte(`foo`),
  1338. },
  1339. },
  1340. },
  1341. },
  1342. },
  1343. secret: &v1.Secret{
  1344. Type: v1.SecretTypeDockerConfigJson,
  1345. Data: map[string][]byte{secretKey: []byte(`{"auths": {"myregistry.localhost": {"username": "{{ .username }}", "password": "{{ .password }}"}}}`)},
  1346. },
  1347. data: testingfake.PushSecretData{
  1348. SecretKey: secretKey,
  1349. RemoteKey: "mysec",
  1350. Property: "config.json",
  1351. },
  1352. wantErr: false,
  1353. wantSecretMap: map[string]*v1.Secret{
  1354. "yoursec": {
  1355. Data: map[string][]byte{
  1356. "token": []byte(`foo`),
  1357. },
  1358. },
  1359. "mysec": {
  1360. ObjectMeta: metav1.ObjectMeta{
  1361. Name: "mysec",
  1362. Labels: map[string]string{},
  1363. Annotations: map[string]string{},
  1364. },
  1365. Data: map[string][]byte{
  1366. "config.json": []byte(`{"auths": {"myregistry.localhost": {"username": "{{ .username }}", "password": "{{ .password }}"}}}`),
  1367. },
  1368. Type: v1.SecretTypeDockerConfigJson,
  1369. },
  1370. },
  1371. },
  1372. {
  1373. name: "create new secret with remote namespace",
  1374. fields: fields{
  1375. Client: &fakeClient{
  1376. t: t,
  1377. secretMap: map[string]*v1.Secret{},
  1378. },
  1379. },
  1380. secret: &v1.Secret{
  1381. ObjectMeta: metav1.ObjectMeta{
  1382. Name: "mysec",
  1383. Namespace: "source-namespace",
  1384. },
  1385. Data: map[string][]byte{secretKey: []byte("bar")},
  1386. },
  1387. data: testingfake.PushSecretData{
  1388. SecretKey: secretKey,
  1389. RemoteKey: "mysec",
  1390. Property: "secret",
  1391. Metadata: &apiextensionsv1.JSON{
  1392. Raw: []byte(`{"apiVersion":"kubernetes.external-secrets.io/v1alpha1", "kind": "PushSecretMetadata", "spec": {"remoteNamespace": "target-namespace"}}`),
  1393. },
  1394. },
  1395. wantErr: false,
  1396. wantSecretMap: map[string]*v1.Secret{
  1397. "mysec": {
  1398. ObjectMeta: metav1.ObjectMeta{
  1399. Name: "mysec",
  1400. Namespace: "target-namespace",
  1401. Labels: map[string]string{},
  1402. Annotations: map[string]string{},
  1403. },
  1404. Data: map[string][]byte{
  1405. "secret": []byte(`bar`),
  1406. },
  1407. Type: v1.SecretTypeOpaque,
  1408. },
  1409. },
  1410. },
  1411. }
  1412. for _, tt := range tests {
  1413. t.Run(tt.name, func(t *testing.T) {
  1414. p := &Client{
  1415. userSecretClient: tt.fields.Client,
  1416. store: &esv1.KubernetesProvider{},
  1417. }
  1418. err := p.PushSecret(context.Background(), tt.secret, tt.data)
  1419. if (err != nil) != tt.wantErr {
  1420. t.Errorf("ProviderKubernetes error = %v, wantErr %v", err, tt.wantErr)
  1421. return
  1422. }
  1423. fClient := tt.fields.Client.(*fakeClient)
  1424. if diff := cmp.Diff(tt.wantSecretMap, fClient.secretMap); diff != "" {
  1425. t.Errorf("Unexpected resulting secrets map: -want, +got :\n%s\n", diff)
  1426. }
  1427. })
  1428. }
  1429. }