pushsecret_controller_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  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 pushsecret
  13. import (
  14. "bytes"
  15. "context"
  16. "fmt"
  17. "os"
  18. "strconv"
  19. "time"
  20. . "github.com/onsi/ginkgo/v2"
  21. . "github.com/onsi/gomega"
  22. v1 "k8s.io/api/core/v1"
  23. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  24. "k8s.io/apimachinery/pkg/types"
  25. "sigs.k8s.io/controller-runtime/pkg/client"
  26. v1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
  27. v1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  28. ctest "github.com/external-secrets/external-secrets/pkg/controllers/commontest"
  29. "github.com/external-secrets/external-secrets/pkg/provider/testing/fake"
  30. )
  31. var (
  32. fakeProvider *fake.Client
  33. timeout = time.Second * 10
  34. interval = time.Millisecond * 250
  35. )
  36. type testCase struct {
  37. store v1beta1.GenericStore
  38. pushsecret *v1alpha1.PushSecret
  39. secret *v1.Secret
  40. assert func(pushsecret *v1alpha1.PushSecret, secret *v1.Secret) bool
  41. }
  42. func init() {
  43. fakeProvider = fake.New()
  44. v1beta1.ForceRegister(fakeProvider, &v1beta1.SecretStoreProvider{
  45. Fake: &v1beta1.FakeProvider{},
  46. })
  47. }
  48. func checkCondition(status v1alpha1.PushSecretStatus, cond v1alpha1.PushSecretStatusCondition) bool {
  49. for _, condition := range status.Conditions {
  50. if condition.Message == cond.Message &&
  51. condition.Reason == cond.Reason &&
  52. condition.Status == cond.Status &&
  53. condition.Type == cond.Type {
  54. return true
  55. }
  56. }
  57. return false
  58. }
  59. type testTweaks func(*testCase)
  60. var _ = Describe("ExternalSecret controller", func() {
  61. const (
  62. PushSecretName = "test-es"
  63. PushSecretFQDN = "externalsecrets.external-secrets.io/test-es"
  64. PushSecretStore = "test-store"
  65. SecretName = "test-secret"
  66. PushSecretTargetSecretName = "test-secret"
  67. FakeManager = "fake.manager"
  68. expectedSecretVal = "SOMEVALUE was templated"
  69. targetPropObj = "{{ .targetProperty | toString | upper }} was templated"
  70. FooValue = "map-foo-value"
  71. BarValue = "map-bar-value"
  72. )
  73. var PushSecretNamespace string
  74. // if we are in debug and need to increase the timeout for testing, we can do so by using an env var
  75. if customTimeout := os.Getenv("TEST_CUSTOM_TIMEOUT_SEC"); customTimeout != "" {
  76. if t, err := strconv.Atoi(customTimeout); err == nil {
  77. timeout = time.Second * time.Duration(t)
  78. }
  79. }
  80. BeforeEach(func() {
  81. var err error
  82. PushSecretNamespace, err = ctest.CreateNamespace("test-ns", k8sClient)
  83. Expect(err).ToNot(HaveOccurred())
  84. fakeProvider.Reset()
  85. })
  86. AfterEach(func() {
  87. k8sClient.Delete(context.Background(), &v1alpha1.PushSecret{
  88. ObjectMeta: metav1.ObjectMeta{
  89. Name: PushSecretName,
  90. Namespace: PushSecretNamespace,
  91. },
  92. })
  93. // give a time for reconciler to remove finalizers before removing SecretStores
  94. // TODO: Secret Stores should have finalizers bound to PushSecrets if DeletionPolicy == Delete
  95. time.Sleep(2 * time.Second)
  96. k8sClient.Delete(context.Background(), &v1beta1.SecretStore{
  97. ObjectMeta: metav1.ObjectMeta{
  98. Name: PushSecretStore,
  99. Namespace: PushSecretNamespace,
  100. },
  101. })
  102. k8sClient.Delete(context.Background(), &v1beta1.ClusterSecretStore{
  103. ObjectMeta: metav1.ObjectMeta{
  104. Name: PushSecretStore,
  105. },
  106. })
  107. k8sClient.Delete(context.Background(), &v1.Secret{
  108. ObjectMeta: metav1.ObjectMeta{
  109. Name: SecretName,
  110. Namespace: PushSecretNamespace,
  111. },
  112. })
  113. Expect(k8sClient.Delete(context.Background(), &v1.Namespace{
  114. ObjectMeta: metav1.ObjectMeta{
  115. Name: PushSecretNamespace,
  116. },
  117. })).To(Succeed())
  118. })
  119. makeDefaultTestcase := func() *testCase {
  120. return &testCase{
  121. pushsecret: &v1alpha1.PushSecret{
  122. ObjectMeta: metav1.ObjectMeta{
  123. Name: PushSecretName,
  124. Namespace: PushSecretNamespace,
  125. },
  126. Spec: v1alpha1.PushSecretSpec{
  127. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  128. {
  129. Name: PushSecretStore,
  130. Kind: "SecretStore",
  131. },
  132. },
  133. Selector: v1alpha1.PushSecretSelector{
  134. Secret: v1alpha1.PushSecretSecret{
  135. Name: SecretName,
  136. },
  137. },
  138. Data: []v1alpha1.PushSecretData{
  139. {
  140. Match: v1alpha1.PushSecretMatch{
  141. SecretKey: "key",
  142. RemoteRef: v1alpha1.PushSecretRemoteRef{
  143. RemoteKey: "path/to/key",
  144. },
  145. },
  146. },
  147. },
  148. },
  149. },
  150. secret: &v1.Secret{
  151. ObjectMeta: metav1.ObjectMeta{
  152. Name: SecretName,
  153. Namespace: PushSecretNamespace,
  154. },
  155. Data: map[string][]byte{
  156. "key": []byte("value"),
  157. },
  158. },
  159. store: &v1beta1.SecretStore{
  160. ObjectMeta: metav1.ObjectMeta{
  161. Name: PushSecretStore,
  162. Namespace: PushSecretNamespace,
  163. },
  164. TypeMeta: metav1.TypeMeta{
  165. Kind: "SecretStore",
  166. },
  167. Spec: v1beta1.SecretStoreSpec{
  168. Provider: &v1beta1.SecretStoreProvider{
  169. Fake: &v1beta1.FakeProvider{
  170. Data: []v1beta1.FakeProviderData{},
  171. },
  172. },
  173. },
  174. },
  175. }
  176. }
  177. // if target Secret name is not specified it should use the ExternalSecret name.
  178. syncSuccessfully := func(tc *testCase) {
  179. fakeProvider.SetSecretFn = func() error {
  180. return nil
  181. }
  182. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  183. Eventually(func() bool {
  184. By("checking if Provider value got updated")
  185. secretValue := secret.Data["key"]
  186. providerValue, ok := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  187. if !ok {
  188. return false
  189. }
  190. got := providerValue.Value
  191. return bytes.Equal(got, secretValue)
  192. }, time.Second*10, time.Second).Should(BeTrue())
  193. return true
  194. }
  195. }
  196. // if target Secret name is not specified it should use the ExternalSecret name.
  197. syncAndDeleteSuccessfully := func(tc *testCase) {
  198. fakeProvider.SetSecretFn = func() error {
  199. return nil
  200. }
  201. tc.pushsecret = &v1alpha1.PushSecret{
  202. ObjectMeta: metav1.ObjectMeta{
  203. Name: PushSecretName,
  204. Namespace: PushSecretNamespace,
  205. },
  206. Spec: v1alpha1.PushSecretSpec{
  207. DeletionPolicy: v1alpha1.PushSecretDeletionPolicyDelete,
  208. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  209. {
  210. Name: PushSecretStore,
  211. Kind: "SecretStore",
  212. },
  213. },
  214. Selector: v1alpha1.PushSecretSelector{
  215. Secret: v1alpha1.PushSecretSecret{
  216. Name: SecretName,
  217. },
  218. },
  219. Data: []v1alpha1.PushSecretData{
  220. {
  221. Match: v1alpha1.PushSecretMatch{
  222. SecretKey: "key",
  223. RemoteRef: v1alpha1.PushSecretRemoteRef{
  224. RemoteKey: "path/to/key",
  225. },
  226. },
  227. },
  228. },
  229. },
  230. }
  231. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  232. ps.Spec.Data[0].Match.RemoteRef.RemoteKey = "different-key"
  233. updatedPS := &v1alpha1.PushSecret{}
  234. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  235. Eventually(func() bool {
  236. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  237. By("checking if Provider value got updated")
  238. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  239. if err != nil {
  240. return false
  241. }
  242. key, ok := updatedPS.Status.SyncedPushSecrets[fmt.Sprintf("SecretStore/%v", PushSecretStore)]["different-key"]
  243. if !ok {
  244. return false
  245. }
  246. return key.Match.SecretKey == "key"
  247. }, time.Second*10, time.Second).Should(BeTrue())
  248. return true
  249. }
  250. }
  251. failDelete := func(tc *testCase) {
  252. fakeProvider.SetSecretFn = func() error {
  253. return nil
  254. }
  255. fakeProvider.DeleteSecretFn = func() error {
  256. return fmt.Errorf("Nope")
  257. }
  258. tc.pushsecret = &v1alpha1.PushSecret{
  259. ObjectMeta: metav1.ObjectMeta{
  260. Name: PushSecretName,
  261. Namespace: PushSecretNamespace,
  262. },
  263. Spec: v1alpha1.PushSecretSpec{
  264. DeletionPolicy: v1alpha1.PushSecretDeletionPolicyDelete,
  265. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  266. {
  267. Name: PushSecretStore,
  268. Kind: "SecretStore",
  269. },
  270. },
  271. Selector: v1alpha1.PushSecretSelector{
  272. Secret: v1alpha1.PushSecretSecret{
  273. Name: SecretName,
  274. },
  275. },
  276. Data: []v1alpha1.PushSecretData{
  277. {
  278. Match: v1alpha1.PushSecretMatch{
  279. SecretKey: "key",
  280. RemoteRef: v1alpha1.PushSecretRemoteRef{
  281. RemoteKey: "path/to/key",
  282. },
  283. },
  284. },
  285. },
  286. },
  287. }
  288. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  289. ps.Spec.Data[0].Match.RemoteRef.RemoteKey = "different-key"
  290. updatedPS := &v1alpha1.PushSecret{}
  291. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  292. Eventually(func() bool {
  293. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  294. By("checking if synced secrets correspond to both keys")
  295. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  296. if err != nil {
  297. return false
  298. }
  299. _, ok := updatedPS.Status.SyncedPushSecrets[fmt.Sprintf("SecretStore/%v", PushSecretStore)]["different-key"]
  300. if !ok {
  301. return false
  302. }
  303. _, ok = updatedPS.Status.SyncedPushSecrets[fmt.Sprintf("SecretStore/%v", PushSecretStore)]["path/to/key"]
  304. return ok
  305. }, time.Second*10, time.Second).Should(BeTrue())
  306. return true
  307. }
  308. }
  309. failDeleteStore := func(tc *testCase) {
  310. fakeProvider.SetSecretFn = func() error {
  311. return nil
  312. }
  313. fakeProvider.DeleteSecretFn = func() error {
  314. return fmt.Errorf("boom")
  315. }
  316. tc.pushsecret.Spec.DeletionPolicy = v1alpha1.PushSecretDeletionPolicyDelete
  317. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  318. secondStore := &v1beta1.SecretStore{
  319. ObjectMeta: metav1.ObjectMeta{
  320. Name: "new-store",
  321. Namespace: PushSecretNamespace,
  322. },
  323. TypeMeta: metav1.TypeMeta{
  324. Kind: "SecretStore",
  325. },
  326. Spec: v1beta1.SecretStoreSpec{
  327. Provider: &v1beta1.SecretStoreProvider{
  328. Fake: &v1beta1.FakeProvider{
  329. Data: []v1beta1.FakeProviderData{},
  330. },
  331. },
  332. },
  333. }
  334. Expect(k8sClient.Create(context.Background(), secondStore, &client.CreateOptions{})).Should(Succeed())
  335. ps.Spec.SecretStoreRefs[0].Name = "new-store"
  336. updatedPS := &v1alpha1.PushSecret{}
  337. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  338. Eventually(func() bool {
  339. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  340. By("checking if Provider value got updated")
  341. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  342. if err != nil {
  343. return false
  344. }
  345. syncedLen := len(updatedPS.Status.SyncedPushSecrets)
  346. return syncedLen == 2
  347. }, time.Second*10, time.Second).Should(BeTrue())
  348. return true
  349. }
  350. }
  351. deleteWholeStore := func(tc *testCase) {
  352. fakeProvider.SetSecretFn = func() error {
  353. return nil
  354. }
  355. fakeProvider.DeleteSecretFn = func() error {
  356. return nil
  357. }
  358. tc.pushsecret.Spec.DeletionPolicy = v1alpha1.PushSecretDeletionPolicyDelete
  359. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  360. secondStore := &v1beta1.SecretStore{
  361. ObjectMeta: metav1.ObjectMeta{
  362. Name: "new-store",
  363. Namespace: PushSecretNamespace,
  364. },
  365. TypeMeta: metav1.TypeMeta{
  366. Kind: "SecretStore",
  367. },
  368. Spec: v1beta1.SecretStoreSpec{
  369. Provider: &v1beta1.SecretStoreProvider{
  370. Fake: &v1beta1.FakeProvider{
  371. Data: []v1beta1.FakeProviderData{},
  372. },
  373. },
  374. },
  375. }
  376. Expect(k8sClient.Create(context.Background(), secondStore, &client.CreateOptions{})).Should(Succeed())
  377. ps.Spec.SecretStoreRefs[0].Name = "new-store"
  378. updatedPS := &v1alpha1.PushSecret{}
  379. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  380. Eventually(func() bool {
  381. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  382. By("checking if Provider value got updated")
  383. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  384. if err != nil {
  385. return false
  386. }
  387. key, ok := updatedPS.Status.SyncedPushSecrets["SecretStore/new-store"]["path/to/key"]
  388. if !ok {
  389. return false
  390. }
  391. syncedLen := len(updatedPS.Status.SyncedPushSecrets)
  392. if syncedLen != 1 {
  393. return false
  394. }
  395. return key.Match.SecretKey == "key"
  396. }, time.Second*10, time.Second).Should(BeTrue())
  397. return true
  398. }
  399. }
  400. // if target Secret name is not specified it should use the ExternalSecret name.
  401. syncMatchingLabels := func(tc *testCase) {
  402. fakeProvider.SetSecretFn = func() error {
  403. return nil
  404. }
  405. fakeProvider.DeleteSecretFn = func() error {
  406. return nil
  407. }
  408. tc.pushsecret = &v1alpha1.PushSecret{
  409. ObjectMeta: metav1.ObjectMeta{
  410. Name: PushSecretName,
  411. Namespace: PushSecretNamespace,
  412. },
  413. Spec: v1alpha1.PushSecretSpec{
  414. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  415. {
  416. LabelSelector: &metav1.LabelSelector{
  417. MatchLabels: map[string]string{
  418. "foo": "bar",
  419. },
  420. },
  421. Kind: "SecretStore",
  422. },
  423. },
  424. Selector: v1alpha1.PushSecretSelector{
  425. Secret: v1alpha1.PushSecretSecret{
  426. Name: SecretName,
  427. },
  428. },
  429. Data: []v1alpha1.PushSecretData{
  430. {
  431. Match: v1alpha1.PushSecretMatch{
  432. SecretKey: "key",
  433. RemoteRef: v1alpha1.PushSecretRemoteRef{
  434. RemoteKey: "path/to/key",
  435. },
  436. },
  437. },
  438. },
  439. },
  440. }
  441. tc.store = &v1beta1.SecretStore{
  442. TypeMeta: metav1.TypeMeta{
  443. Kind: "SecretStore",
  444. },
  445. ObjectMeta: metav1.ObjectMeta{
  446. Name: PushSecretStore,
  447. Namespace: PushSecretNamespace,
  448. Labels: map[string]string{
  449. "foo": "bar",
  450. },
  451. },
  452. Spec: v1beta1.SecretStoreSpec{
  453. Provider: &v1beta1.SecretStoreProvider{
  454. Fake: &v1beta1.FakeProvider{
  455. Data: []v1beta1.FakeProviderData{},
  456. },
  457. },
  458. },
  459. }
  460. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  461. secretValue := secret.Data["key"]
  462. providerValue := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  463. expected := v1alpha1.PushSecretStatusCondition{
  464. Type: v1alpha1.PushSecretReady,
  465. Status: v1.ConditionTrue,
  466. Reason: v1alpha1.ReasonSynced,
  467. Message: "PushSecret synced successfully",
  468. }
  469. return bytes.Equal(secretValue, providerValue) && checkCondition(ps.Status, expected)
  470. }
  471. }
  472. syncWithClusterStore := func(tc *testCase) {
  473. fakeProvider.SetSecretFn = func() error {
  474. return nil
  475. }
  476. tc.store = &v1beta1.ClusterSecretStore{
  477. TypeMeta: metav1.TypeMeta{
  478. Kind: "ClusterSecretStore",
  479. },
  480. ObjectMeta: metav1.ObjectMeta{
  481. Name: PushSecretStore,
  482. },
  483. Spec: v1beta1.SecretStoreSpec{
  484. Provider: &v1beta1.SecretStoreProvider{
  485. Fake: &v1beta1.FakeProvider{
  486. Data: []v1beta1.FakeProviderData{},
  487. },
  488. },
  489. },
  490. }
  491. tc.pushsecret.Spec.SecretStoreRefs[0].Kind = "ClusterSecretStore"
  492. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  493. secretValue := secret.Data["key"]
  494. providerValue := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  495. expected := v1alpha1.PushSecretStatusCondition{
  496. Type: v1alpha1.PushSecretReady,
  497. Status: v1.ConditionTrue,
  498. Reason: v1alpha1.ReasonSynced,
  499. Message: "PushSecret synced successfully",
  500. }
  501. return bytes.Equal(secretValue, providerValue) && checkCondition(ps.Status, expected)
  502. }
  503. }
  504. // if target Secret name is not specified it should use the ExternalSecret name.
  505. syncWithClusterStoreMatchingLabels := func(tc *testCase) {
  506. fakeProvider.SetSecretFn = func() error {
  507. return nil
  508. }
  509. tc.pushsecret = &v1alpha1.PushSecret{
  510. ObjectMeta: metav1.ObjectMeta{
  511. Name: PushSecretName,
  512. Namespace: PushSecretNamespace,
  513. },
  514. Spec: v1alpha1.PushSecretSpec{
  515. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  516. {
  517. LabelSelector: &metav1.LabelSelector{
  518. MatchLabels: map[string]string{
  519. "foo": "bar",
  520. },
  521. },
  522. Kind: "ClusterSecretStore",
  523. },
  524. },
  525. Selector: v1alpha1.PushSecretSelector{
  526. Secret: v1alpha1.PushSecretSecret{
  527. Name: SecretName,
  528. },
  529. },
  530. Data: []v1alpha1.PushSecretData{
  531. {
  532. Match: v1alpha1.PushSecretMatch{
  533. SecretKey: "key",
  534. RemoteRef: v1alpha1.PushSecretRemoteRef{
  535. RemoteKey: "path/to/key",
  536. },
  537. },
  538. },
  539. },
  540. },
  541. }
  542. tc.store = &v1beta1.ClusterSecretStore{
  543. ObjectMeta: metav1.ObjectMeta{
  544. Name: PushSecretStore,
  545. Labels: map[string]string{
  546. "foo": "bar",
  547. },
  548. },
  549. Spec: v1beta1.SecretStoreSpec{
  550. Provider: &v1beta1.SecretStoreProvider{
  551. Fake: &v1beta1.FakeProvider{
  552. Data: []v1beta1.FakeProviderData{},
  553. },
  554. },
  555. },
  556. }
  557. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  558. secretValue := secret.Data["key"]
  559. providerValue := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  560. expected := v1alpha1.PushSecretStatusCondition{
  561. Type: v1alpha1.PushSecretReady,
  562. Status: v1.ConditionTrue,
  563. Reason: v1alpha1.ReasonSynced,
  564. Message: "PushSecret synced successfully",
  565. }
  566. return bytes.Equal(secretValue, providerValue) && checkCondition(ps.Status, expected)
  567. }
  568. }
  569. // if target Secret name is not specified it should use the ExternalSecret name.
  570. failNoSecret := func(tc *testCase) {
  571. fakeProvider.SetSecretFn = func() error {
  572. return nil
  573. }
  574. tc.secret = nil
  575. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  576. expected := v1alpha1.PushSecretStatusCondition{
  577. Type: v1alpha1.PushSecretReady,
  578. Status: v1.ConditionFalse,
  579. Reason: v1alpha1.ReasonErrored,
  580. Message: "could not get source secret",
  581. }
  582. return checkCondition(ps.Status, expected)
  583. }
  584. }
  585. // if target Secret name is not specified it should use the ExternalSecret name.
  586. failNoSecretKey := func(tc *testCase) {
  587. fakeProvider.SetSecretFn = func() error {
  588. return nil
  589. }
  590. tc.pushsecret.Spec.Data[0].Match.SecretKey = "unexisting"
  591. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  592. expected := v1alpha1.PushSecretStatusCondition{
  593. Type: v1alpha1.PushSecretReady,
  594. Status: v1.ConditionFalse,
  595. Reason: v1alpha1.ReasonErrored,
  596. Message: "set secret failed: secret key unexisting does not exist",
  597. }
  598. return checkCondition(ps.Status, expected)
  599. }
  600. }
  601. // if target Secret name is not specified it should use the ExternalSecret name.
  602. failNoSecretStore := func(tc *testCase) {
  603. fakeProvider.SetSecretFn = func() error {
  604. return nil
  605. }
  606. tc.store = nil
  607. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  608. expected := v1alpha1.PushSecretStatusCondition{
  609. Type: v1alpha1.PushSecretReady,
  610. Status: v1.ConditionFalse,
  611. Reason: v1alpha1.ReasonErrored,
  612. Message: "could not get SecretStore \"test-store\", secretstores.external-secrets.io \"test-store\" not found",
  613. }
  614. return checkCondition(ps.Status, expected)
  615. }
  616. }
  617. // if target Secret name is not specified it should use the ExternalSecret name.
  618. failNoClusterStore := func(tc *testCase) {
  619. fakeProvider.SetSecretFn = func() error {
  620. return nil
  621. }
  622. tc.store = nil
  623. tc.pushsecret.Spec.SecretStoreRefs[0].Kind = "ClusterSecretStore"
  624. tc.pushsecret.Spec.SecretStoreRefs[0].Name = "unexisting"
  625. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  626. expected := v1alpha1.PushSecretStatusCondition{
  627. Type: v1alpha1.PushSecretReady,
  628. Status: v1.ConditionFalse,
  629. Reason: v1alpha1.ReasonErrored,
  630. Message: "could not get ClusterSecretStore \"unexisting\", clustersecretstores.external-secrets.io \"unexisting\" not found",
  631. }
  632. return checkCondition(ps.Status, expected)
  633. }
  634. } // if target Secret name is not specified it should use the ExternalSecret name.
  635. setSecretFail := func(tc *testCase) {
  636. fakeProvider.SetSecretFn = func() error {
  637. return fmt.Errorf("boom")
  638. }
  639. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  640. expected := v1alpha1.PushSecretStatusCondition{
  641. Type: v1alpha1.PushSecretReady,
  642. Status: v1.ConditionFalse,
  643. Reason: v1alpha1.ReasonErrored,
  644. Message: "set secret failed: could not write remote ref key to target secretstore test-store: boom",
  645. }
  646. return checkCondition(ps.Status, expected)
  647. }
  648. }
  649. // if target Secret name is not specified it should use the ExternalSecret name.
  650. newClientFail := func(tc *testCase) {
  651. fakeProvider.NewFn = func(context.Context, v1beta1.GenericStore, client.Client, string) (v1beta1.SecretsClient, error) {
  652. return nil, fmt.Errorf("boom")
  653. }
  654. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  655. expected := v1alpha1.PushSecretStatusCondition{
  656. Type: v1alpha1.PushSecretReady,
  657. Status: v1.ConditionFalse,
  658. Reason: v1alpha1.ReasonErrored,
  659. Message: "set secret failed: could not get secrets client for store test-store: boom",
  660. }
  661. return checkCondition(ps.Status, expected)
  662. }
  663. }
  664. DescribeTable("When reconciling a PushSecret",
  665. func(tweaks ...testTweaks) {
  666. tc := makeDefaultTestcase()
  667. for _, tweak := range tweaks {
  668. tweak(tc)
  669. }
  670. ctx := context.Background()
  671. By("creating a secret store, secret and pushsecret")
  672. if tc.store != nil {
  673. Expect(k8sClient.Create(ctx, tc.store)).To(Succeed())
  674. }
  675. if tc.secret != nil {
  676. Expect(k8sClient.Create(ctx, tc.secret)).To(Succeed())
  677. }
  678. if tc.pushsecret != nil {
  679. Expect(k8sClient.Create(ctx, tc.pushsecret)).Should(Succeed())
  680. }
  681. time.Sleep(2 * time.Second)
  682. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  683. createdPS := &v1alpha1.PushSecret{}
  684. By("checking the pushSecret condition")
  685. Eventually(func() bool {
  686. err := k8sClient.Get(ctx, psKey, createdPS)
  687. if err != nil {
  688. return false
  689. }
  690. return tc.assert(createdPS, tc.secret)
  691. }, timeout, interval).Should(BeTrue())
  692. // this must be optional so we can test faulty es configuration
  693. },
  694. Entry("should sync", syncSuccessfully),
  695. Entry("should delete if DeletionPolicy=Delete", syncAndDeleteSuccessfully),
  696. Entry("should track deletion tasks if Delete fails", failDelete),
  697. Entry("should track deleted stores if Delete fails", failDeleteStore),
  698. Entry("should delete all secrets if SecretStore changes", deleteWholeStore),
  699. Entry("should sync to stores matching labels", syncMatchingLabels),
  700. Entry("should sync with ClusterStore", syncWithClusterStore),
  701. Entry("should sync with ClusterStore matching labels", syncWithClusterStoreMatchingLabels),
  702. Entry("should fail if Secret is not created", failNoSecret),
  703. Entry("should fail if Secret Key does not exist", failNoSecretKey),
  704. Entry("should fail if SetSecret fails", setSecretFail),
  705. Entry("should fail if no valid SecretStore", failNoSecretStore),
  706. Entry("should fail if no valid ClusterSecretStore", failNoClusterStore),
  707. Entry("should fail if NewClient fails", newClientFail),
  708. )
  709. })