pushsecret_controller_test.go 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682
  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 pushsecret
  14. import (
  15. "bytes"
  16. "context"
  17. "errors"
  18. "fmt"
  19. "os"
  20. "strconv"
  21. "time"
  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. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  27. "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
  28. genv1alpha1 "github.com/external-secrets/external-secrets/apis/generators/v1alpha1"
  29. ctest "github.com/external-secrets/external-secrets/pkg/controllers/commontest"
  30. "github.com/external-secrets/external-secrets/pkg/controllers/pushsecret/psmetrics"
  31. "github.com/external-secrets/external-secrets/runtime/testing/fake"
  32. . "github.com/onsi/ginkgo/v2"
  33. . "github.com/onsi/gomega"
  34. )
  35. var (
  36. fakeProvider *fake.Client
  37. timeout = time.Second * 10
  38. interval = time.Millisecond * 250
  39. )
  40. type testCase struct {
  41. store esv1.GenericStore
  42. managedStore1 esv1.GenericStore
  43. managedStore2 esv1.GenericStore
  44. unmanagedStore1 esv1.GenericStore
  45. unmanagedStore2 esv1.GenericStore
  46. pushsecret *v1alpha1.PushSecret
  47. secret *v1.Secret
  48. assert func(pushsecret *v1alpha1.PushSecret, secret *v1.Secret) bool
  49. }
  50. func init() {
  51. fakeProvider = fake.New()
  52. esv1.ForceRegister(fakeProvider, &esv1.SecretStoreProvider{
  53. Fake: &esv1.FakeProvider{},
  54. }, esv1.MaintenanceStatusMaintained)
  55. psmetrics.SetUpMetrics()
  56. }
  57. func checkCondition(status v1alpha1.PushSecretStatus, cond v1alpha1.PushSecretStatusCondition) bool {
  58. for _, condition := range status.Conditions {
  59. if condition.Message == cond.Message &&
  60. condition.Reason == cond.Reason &&
  61. condition.Status == cond.Status &&
  62. condition.Type == cond.Type {
  63. return true
  64. }
  65. }
  66. return false
  67. }
  68. type testTweaks func(*testCase)
  69. var _ = Describe("PushSecret controller", func() {
  70. const (
  71. PushSecretName = "test-ps"
  72. PushSecretStore = "test-store"
  73. SecretName = "test-secret"
  74. )
  75. var PushSecretNamespace, OtherNamespace string
  76. // if we are in debug and need to increase the timeout for testing, we can do so by using an env var
  77. if customTimeout := os.Getenv("TEST_CUSTOM_TIMEOUT_SEC"); customTimeout != "" {
  78. if t, err := strconv.Atoi(customTimeout); err == nil {
  79. timeout = time.Second * time.Duration(t)
  80. }
  81. }
  82. BeforeEach(func() {
  83. var err error
  84. PushSecretNamespace, err = ctest.CreateNamespace("test-ns", k8sClient)
  85. Expect(err).ToNot(HaveOccurred())
  86. OtherNamespace, err = ctest.CreateNamespace("test-ns", k8sClient)
  87. Expect(err).ToNot(HaveOccurred())
  88. fakeProvider.Reset()
  89. Expect(k8sClient.Create(context.Background(), &genv1alpha1.Fake{
  90. TypeMeta: metav1.TypeMeta{
  91. Kind: "Fake",
  92. APIVersion: "generators.external-secrets.io/v1alpha1",
  93. },
  94. ObjectMeta: metav1.ObjectMeta{
  95. Name: "test",
  96. Namespace: PushSecretNamespace,
  97. },
  98. Spec: genv1alpha1.FakeSpec{
  99. Data: map[string]string{
  100. "key": "foo-bar-from-generator",
  101. },
  102. }})).ToNot(HaveOccurred())
  103. })
  104. AfterEach(func() {
  105. k8sClient.Delete(context.Background(), &v1alpha1.PushSecret{
  106. ObjectMeta: metav1.ObjectMeta{
  107. Name: PushSecretName,
  108. Namespace: PushSecretNamespace,
  109. },
  110. })
  111. // give a time for reconciler to remove finalizers before removing SecretStores
  112. time.Sleep(2 * time.Second)
  113. k8sClient.Delete(context.Background(), &esv1.SecretStore{
  114. ObjectMeta: metav1.ObjectMeta{
  115. Name: PushSecretStore,
  116. Namespace: PushSecretNamespace,
  117. },
  118. })
  119. k8sClient.Delete(context.Background(), &esv1.ClusterSecretStore{
  120. ObjectMeta: metav1.ObjectMeta{
  121. Name: PushSecretStore,
  122. },
  123. })
  124. k8sClient.Delete(context.Background(), &v1.Secret{
  125. ObjectMeta: metav1.ObjectMeta{
  126. Name: SecretName,
  127. Namespace: PushSecretNamespace,
  128. },
  129. })
  130. Expect(k8sClient.Delete(context.Background(), &v1.Namespace{
  131. ObjectMeta: metav1.ObjectMeta{
  132. Name: PushSecretNamespace,
  133. },
  134. })).To(Succeed())
  135. })
  136. const (
  137. defaultKey = "key"
  138. defaultVal = "value"
  139. defaultPath = "path/to/key"
  140. otherKey = "other-key"
  141. otherVal = "other-value"
  142. otherPath = "path/to/other-key"
  143. newKey = "new-key"
  144. newVal = "new-value"
  145. storePrefixTemplate = "SecretStore/%v"
  146. )
  147. makeDefaultTestcase := func() *testCase {
  148. return &testCase{
  149. pushsecret: &v1alpha1.PushSecret{
  150. ObjectMeta: metav1.ObjectMeta{
  151. Name: PushSecretName,
  152. Namespace: PushSecretNamespace,
  153. },
  154. Spec: v1alpha1.PushSecretSpec{
  155. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  156. {
  157. Name: PushSecretStore,
  158. Kind: "SecretStore",
  159. },
  160. },
  161. Selector: v1alpha1.PushSecretSelector{
  162. Secret: &v1alpha1.PushSecretSecret{
  163. Name: SecretName,
  164. },
  165. },
  166. Data: []v1alpha1.PushSecretData{
  167. {
  168. Match: v1alpha1.PushSecretMatch{
  169. SecretKey: defaultKey,
  170. RemoteRef: v1alpha1.PushSecretRemoteRef{
  171. RemoteKey: defaultPath,
  172. },
  173. },
  174. },
  175. },
  176. },
  177. },
  178. secret: &v1.Secret{
  179. ObjectMeta: metav1.ObjectMeta{
  180. Name: SecretName,
  181. Namespace: PushSecretNamespace,
  182. },
  183. Data: map[string][]byte{
  184. defaultKey: []byte(defaultVal),
  185. },
  186. },
  187. store: &esv1.SecretStore{
  188. ObjectMeta: metav1.ObjectMeta{
  189. Name: PushSecretStore,
  190. Namespace: PushSecretNamespace,
  191. },
  192. TypeMeta: metav1.TypeMeta{
  193. Kind: "SecretStore",
  194. },
  195. Spec: esv1.SecretStoreSpec{
  196. Provider: &esv1.SecretStoreProvider{
  197. Fake: &esv1.FakeProvider{
  198. Data: []esv1.FakeProviderData{},
  199. },
  200. },
  201. },
  202. },
  203. }
  204. }
  205. // if target Secret name is not specified it should use the ExternalSecret name.
  206. syncSuccessfully := func(tc *testCase) {
  207. fakeProvider.SetSecretFn = func() error {
  208. return nil
  209. }
  210. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  211. Eventually(func() bool {
  212. By("checking if Provider value got updated")
  213. secretValue := secret.Data[defaultKey]
  214. setSecretArgs := fakeProvider.GetPushSecretData()
  215. providerValue, ok := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  216. if !ok {
  217. return false
  218. }
  219. got := providerValue.Value
  220. return bytes.Equal(got, secretValue)
  221. }, time.Second*10, time.Second).Should(BeTrue())
  222. return true
  223. }
  224. }
  225. updateIfNotExists := func(tc *testCase) {
  226. fakeProvider.SetSecretFn = func() error {
  227. return nil
  228. }
  229. fakeProvider.SecretExistsFn = func(_ context.Context, ref esv1.PushSecretRemoteRef) (bool, error) {
  230. setSecretArgs := fakeProvider.GetPushSecretData()
  231. _, ok := setSecretArgs[ref.GetRemoteKey()]
  232. return ok, nil
  233. }
  234. tc.pushsecret.Spec.UpdatePolicy = v1alpha1.PushSecretUpdatePolicyIfNotExists
  235. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  236. Consistently(func() bool {
  237. By("updating the secret value")
  238. tc.secret.Data[defaultKey] = []byte(newVal)
  239. Expect(k8sClient.Update(context.Background(), secret, &client.UpdateOptions{})).Should(Succeed())
  240. By("checking if Provider value does not get updated")
  241. setSecretArgs := fakeProvider.GetPushSecretData()
  242. providerValue, ok := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  243. if !ok {
  244. return false
  245. }
  246. got := providerValue.Value
  247. return bytes.Equal(got, []byte(defaultVal))
  248. }, time.Second*10, time.Second).Should(BeTrue())
  249. return true
  250. }
  251. }
  252. updateIfNotExistsPartialSecrets := func(tc *testCase) {
  253. fakeProvider.SetSecretFn = func() error {
  254. return nil
  255. }
  256. fakeProvider.SecretExistsFn = func(_ context.Context, ref esv1.PushSecretRemoteRef) (bool, error) {
  257. setSecretArgs := fakeProvider.GetPushSecretData()
  258. _, ok := setSecretArgs[ref.GetRemoteKey()]
  259. return ok, nil
  260. }
  261. tc.pushsecret.Spec.UpdatePolicy = v1alpha1.PushSecretUpdatePolicyIfNotExists
  262. tc.pushsecret.Spec.Data = append(tc.pushsecret.Spec.Data, v1alpha1.PushSecretData{
  263. Match: v1alpha1.PushSecretMatch{
  264. SecretKey: otherKey,
  265. RemoteRef: v1alpha1.PushSecretRemoteRef{
  266. RemoteKey: otherPath,
  267. },
  268. },
  269. })
  270. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  271. Eventually(func() bool {
  272. tc.secret.Data[defaultKey] = []byte(newVal) // change initial value in secret
  273. tc.secret.Data[otherKey] = []byte(otherVal)
  274. By("checking if only not existing Provider value got updated")
  275. Expect(k8sClient.Update(context.Background(), secret, &client.UpdateOptions{})).Should(Succeed())
  276. setSecretArgs := fakeProvider.GetPushSecretData()
  277. providerValue, ok := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  278. if !ok {
  279. return false
  280. }
  281. got := providerValue.Value
  282. otherProviderValue, ok := setSecretArgs[ps.Spec.Data[1].Match.RemoteRef.RemoteKey]
  283. if !ok {
  284. return false
  285. }
  286. gotOther := otherProviderValue.Value
  287. return bytes.Equal(gotOther, tc.secret.Data[otherKey]) && bytes.Equal(got, []byte(defaultVal))
  288. }, time.Second*10, time.Second).Should(BeTrue())
  289. return true
  290. }
  291. }
  292. updateIfNotExistsSyncStatus := func(tc *testCase) {
  293. fakeProvider.SetSecretFn = func() error {
  294. return nil
  295. }
  296. fakeProvider.SecretExistsFn = func(_ context.Context, ref esv1.PushSecretRemoteRef) (bool, error) {
  297. setSecretArgs := fakeProvider.GetPushSecretData()
  298. _, ok := setSecretArgs[ref.GetRemoteKey()]
  299. return ok, nil
  300. }
  301. tc.pushsecret.Spec.UpdatePolicy = v1alpha1.PushSecretUpdatePolicyIfNotExists
  302. tc.pushsecret.Spec.Data = append(tc.pushsecret.Spec.Data, v1alpha1.PushSecretData{
  303. Match: v1alpha1.PushSecretMatch{
  304. SecretKey: otherKey,
  305. RemoteRef: v1alpha1.PushSecretRemoteRef{
  306. RemoteKey: otherPath,
  307. },
  308. },
  309. })
  310. tc.secret.Data[defaultKey] = []byte(newVal)
  311. tc.secret.Data[otherKey] = []byte(otherVal)
  312. updatedPS := &v1alpha1.PushSecret{}
  313. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  314. Eventually(func() bool {
  315. By("checking if PushSecret status gets updated correctly with UpdatePolicy=IfNotExists")
  316. Expect(k8sClient.Update(context.Background(), secret, &client.UpdateOptions{})).Should(Succeed())
  317. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  318. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  319. if err != nil {
  320. return false
  321. }
  322. _, ok := updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][defaultPath]
  323. if !ok {
  324. return false
  325. }
  326. _, ok = updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][otherPath]
  327. if !ok {
  328. return false
  329. }
  330. expected := v1alpha1.PushSecretStatusCondition{
  331. Type: v1alpha1.PushSecretReady,
  332. Status: v1.ConditionTrue,
  333. Reason: v1alpha1.ReasonSynced,
  334. Message: "PushSecret synced successfully. Existing secrets in providers unchanged.",
  335. }
  336. return checkCondition(ps.Status, expected)
  337. }, time.Second*10, time.Second).Should(BeTrue())
  338. return true
  339. }
  340. }
  341. updateIfNotExistsSyncFailed := func(tc *testCase) {
  342. fakeProvider.SetSecretFn = func() error {
  343. return nil
  344. }
  345. fakeProvider.SecretExistsFn = func(_ context.Context, _ esv1.PushSecretRemoteRef) (bool, error) {
  346. return false, errors.New("don't know")
  347. }
  348. tc.pushsecret.Spec.UpdatePolicy = v1alpha1.PushSecretUpdatePolicyIfNotExists
  349. tc.assert = func(ps *v1alpha1.PushSecret, _ *v1.Secret) bool {
  350. Eventually(func() bool {
  351. By("checking if sync failed if secret existence cannot be verified in Provider")
  352. expected := v1alpha1.PushSecretStatusCondition{
  353. Type: v1alpha1.PushSecretReady,
  354. Status: v1.ConditionFalse,
  355. Reason: v1alpha1.ReasonErrored,
  356. Message: "set secret failed: could not verify if secret exists in store: don't know",
  357. }
  358. return checkCondition(ps.Status, expected)
  359. }, time.Second*10, time.Second).Should(BeTrue())
  360. return true
  361. }
  362. }
  363. syncSuccessfullyReusingKeys := func(tc *testCase) {
  364. fakeProvider.SetSecretFn = func() error {
  365. return nil
  366. }
  367. tc.pushsecret = &v1alpha1.PushSecret{
  368. ObjectMeta: metav1.ObjectMeta{
  369. Name: PushSecretName,
  370. Namespace: PushSecretNamespace,
  371. },
  372. Spec: v1alpha1.PushSecretSpec{
  373. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  374. {
  375. Name: PushSecretStore,
  376. Kind: "SecretStore",
  377. },
  378. },
  379. Selector: v1alpha1.PushSecretSelector{
  380. Secret: &v1alpha1.PushSecretSecret{
  381. Name: SecretName,
  382. },
  383. },
  384. Data: []v1alpha1.PushSecretData{
  385. {
  386. Match: v1alpha1.PushSecretMatch{
  387. SecretKey: "otherKey",
  388. RemoteRef: v1alpha1.PushSecretRemoteRef{
  389. RemoteKey: defaultPath,
  390. },
  391. },
  392. },
  393. },
  394. Template: &esv1.ExternalSecretTemplate{
  395. Metadata: esv1.ExternalSecretTemplateMetadata{
  396. Labels: map[string]string{
  397. "foos": "ball",
  398. },
  399. Annotations: map[string]string{
  400. "hihi": "ga",
  401. },
  402. Finalizers: []string{"example.com/finalizer"},
  403. },
  404. Type: v1.SecretTypeOpaque,
  405. EngineVersion: esv1.TemplateEngineV2,
  406. Data: map[string]string{
  407. defaultKey: "{{ .key | toString | upper }} was templated",
  408. "otherKey": "{{ .key | toString | upper }} was also templated",
  409. },
  410. },
  411. },
  412. }
  413. tc.assert = func(ps *v1alpha1.PushSecret, _ *v1.Secret) bool {
  414. Eventually(func() bool {
  415. By("checking if Provider value got updated")
  416. setSecretArgs := fakeProvider.GetPushSecretData()
  417. providerValue, ok := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  418. if !ok {
  419. return false
  420. }
  421. got := providerValue.Value
  422. return bytes.Equal(got, []byte("VALUE was also templated"))
  423. }, time.Second*10, time.Second).Should(BeTrue())
  424. return true
  425. }
  426. }
  427. // if target Secret name is not specified it should use the ExternalSecret name.
  428. syncSuccessfullyWithTemplate := func(tc *testCase) {
  429. fakeProvider.SetSecretFn = func() error {
  430. return nil
  431. }
  432. tc.pushsecret = &v1alpha1.PushSecret{
  433. ObjectMeta: metav1.ObjectMeta{
  434. Name: PushSecretName,
  435. Namespace: PushSecretNamespace,
  436. },
  437. Spec: v1alpha1.PushSecretSpec{
  438. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  439. {
  440. Name: PushSecretStore,
  441. Kind: "SecretStore",
  442. },
  443. },
  444. Selector: v1alpha1.PushSecretSelector{
  445. Secret: &v1alpha1.PushSecretSecret{
  446. Name: SecretName,
  447. },
  448. },
  449. Data: []v1alpha1.PushSecretData{
  450. {
  451. Match: v1alpha1.PushSecretMatch{
  452. SecretKey: defaultKey,
  453. RemoteRef: v1alpha1.PushSecretRemoteRef{
  454. RemoteKey: defaultPath,
  455. },
  456. },
  457. },
  458. },
  459. Template: &esv1.ExternalSecretTemplate{
  460. Metadata: esv1.ExternalSecretTemplateMetadata{
  461. Labels: map[string]string{
  462. "foos": "ball",
  463. },
  464. Annotations: map[string]string{
  465. "hihi": "ga",
  466. },
  467. Finalizers: []string{"example.com/finalizer"},
  468. },
  469. Type: v1.SecretTypeOpaque,
  470. EngineVersion: esv1.TemplateEngineV2,
  471. Data: map[string]string{
  472. defaultKey: "{{ .key | toString | upper }} was templated",
  473. },
  474. },
  475. },
  476. }
  477. tc.assert = func(ps *v1alpha1.PushSecret, _ *v1.Secret) bool {
  478. Eventually(func() bool {
  479. By("checking if Provider value got updated")
  480. setSecretArgs := fakeProvider.GetPushSecretData()
  481. providerValue, ok := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  482. if !ok {
  483. return false
  484. }
  485. got := providerValue.Value
  486. return bytes.Equal(got, []byte("VALUE was templated"))
  487. }, time.Second*10, time.Second).Should(BeTrue())
  488. return true
  489. }
  490. }
  491. // if target Secret name is not specified it should use the ExternalSecret name.
  492. syncAndDeleteSuccessfully := func(tc *testCase) {
  493. fakeProvider.SetSecretFn = func() error {
  494. return nil
  495. }
  496. tc.pushsecret = &v1alpha1.PushSecret{
  497. ObjectMeta: metav1.ObjectMeta{
  498. Name: PushSecretName,
  499. Namespace: PushSecretNamespace,
  500. },
  501. Spec: v1alpha1.PushSecretSpec{
  502. DeletionPolicy: v1alpha1.PushSecretDeletionPolicyDelete,
  503. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  504. {
  505. Name: PushSecretStore,
  506. Kind: "SecretStore",
  507. },
  508. },
  509. Selector: v1alpha1.PushSecretSelector{
  510. Secret: &v1alpha1.PushSecretSecret{
  511. Name: SecretName,
  512. },
  513. },
  514. Data: []v1alpha1.PushSecretData{
  515. {
  516. Match: v1alpha1.PushSecretMatch{
  517. SecretKey: defaultKey,
  518. RemoteRef: v1alpha1.PushSecretRemoteRef{
  519. RemoteKey: defaultPath,
  520. },
  521. },
  522. },
  523. },
  524. },
  525. }
  526. tc.assert = func(ps *v1alpha1.PushSecret, _ *v1.Secret) bool {
  527. ps.Spec.Data[0].Match.RemoteRef.RemoteKey = newKey
  528. updatedPS := &v1alpha1.PushSecret{}
  529. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  530. Eventually(func() bool {
  531. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  532. By("checking if Provider value got updated")
  533. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  534. if err != nil {
  535. return false
  536. }
  537. key, ok := updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][newKey]
  538. if !ok {
  539. return false
  540. }
  541. return key.Match.SecretKey == defaultKey
  542. }, time.Second*10, time.Second).Should(BeTrue())
  543. return true
  544. }
  545. }
  546. // if PushSecret deletes a secret with properties, the status map should be cleaned up correctly
  547. syncAndDeleteWithProperties := func(tc *testCase) {
  548. fakeProvider.SetSecretFn = func() error {
  549. return nil
  550. }
  551. fakeProvider.DeleteSecretFn = func() error {
  552. return nil
  553. }
  554. tc.pushsecret = &v1alpha1.PushSecret{
  555. ObjectMeta: metav1.ObjectMeta{
  556. Name: PushSecretName,
  557. Namespace: PushSecretNamespace,
  558. },
  559. Spec: v1alpha1.PushSecretSpec{
  560. DeletionPolicy: v1alpha1.PushSecretDeletionPolicyDelete,
  561. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  562. {
  563. Name: PushSecretStore,
  564. Kind: "SecretStore",
  565. },
  566. },
  567. Selector: v1alpha1.PushSecretSelector{
  568. Secret: &v1alpha1.PushSecretSecret{
  569. Name: SecretName,
  570. },
  571. },
  572. Data: []v1alpha1.PushSecretData{
  573. {
  574. Match: v1alpha1.PushSecretMatch{
  575. SecretKey: defaultKey,
  576. RemoteRef: v1alpha1.PushSecretRemoteRef{
  577. RemoteKey: defaultPath,
  578. Property: "field1",
  579. },
  580. },
  581. },
  582. {
  583. Match: v1alpha1.PushSecretMatch{
  584. SecretKey: otherKey,
  585. RemoteRef: v1alpha1.PushSecretRemoteRef{
  586. RemoteKey: defaultPath,
  587. Property: "field2",
  588. },
  589. },
  590. },
  591. },
  592. },
  593. }
  594. tc.secret.Data[otherKey] = []byte(otherVal)
  595. tc.assert = func(ps *v1alpha1.PushSecret, _ *v1.Secret) bool {
  596. updatedPS := &v1alpha1.PushSecret{}
  597. // Wait for initial sync
  598. Eventually(func() bool {
  599. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  600. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  601. if err != nil {
  602. return false
  603. }
  604. // Check both properties are in status
  605. _, ok1 := updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][defaultPath+"/field1"]
  606. _, ok2 := updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][defaultPath+"/field2"]
  607. return ok1 && ok2
  608. }, time.Second*10, time.Second).Should(BeTrue())
  609. // Remove one property
  610. updatedPS.Spec.Data = []v1alpha1.PushSecretData{
  611. {
  612. Match: v1alpha1.PushSecretMatch{
  613. SecretKey: defaultKey,
  614. RemoteRef: v1alpha1.PushSecretRemoteRef{
  615. RemoteKey: defaultPath,
  616. Property: "field1",
  617. },
  618. },
  619. },
  620. }
  621. Expect(k8sClient.Update(context.Background(), updatedPS, &client.UpdateOptions{})).Should(Succeed())
  622. // Verify the removed property is deleted from status
  623. Eventually(func() bool {
  624. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  625. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  626. if err != nil {
  627. return false
  628. }
  629. // field1 should still exist
  630. _, ok1 := updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][defaultPath+"/field1"]
  631. // field2 should be removed
  632. _, ok2 := updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][defaultPath+"/field2"]
  633. return ok1 && !ok2
  634. }, time.Second*10, time.Second).Should(BeTrue())
  635. return true
  636. }
  637. }
  638. // if PushSecret's DeletionPolicy is cleared, it should delete successfully
  639. syncChangePolicyAndDeleteSuccessfully := func(tc *testCase) {
  640. fakeProvider.SetSecretFn = func() error {
  641. return nil
  642. }
  643. tc.pushsecret = &v1alpha1.PushSecret{
  644. ObjectMeta: metav1.ObjectMeta{
  645. Name: PushSecretName,
  646. Namespace: PushSecretNamespace,
  647. },
  648. Spec: v1alpha1.PushSecretSpec{
  649. DeletionPolicy: v1alpha1.PushSecretDeletionPolicyDelete,
  650. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  651. {
  652. Name: PushSecretStore,
  653. Kind: "SecretStore",
  654. },
  655. },
  656. Selector: v1alpha1.PushSecretSelector{
  657. Secret: &v1alpha1.PushSecretSecret{
  658. Name: SecretName,
  659. },
  660. },
  661. Data: []v1alpha1.PushSecretData{
  662. {
  663. Match: v1alpha1.PushSecretMatch{
  664. SecretKey: defaultKey,
  665. RemoteRef: v1alpha1.PushSecretRemoteRef{
  666. RemoteKey: defaultPath,
  667. },
  668. },
  669. },
  670. },
  671. },
  672. }
  673. tc.assert = func(ps *v1alpha1.PushSecret, _ *v1.Secret) bool {
  674. ps.Spec.DeletionPolicy = v1alpha1.PushSecretDeletionPolicyNone
  675. updatedPS := &v1alpha1.PushSecret{}
  676. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  677. Expect(k8sClient.Delete(context.Background(), ps, &client.DeleteOptions{})).Should(Succeed())
  678. Eventually(func() bool {
  679. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  680. By("checking if Get PushSecret returns not found")
  681. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  682. if err != nil && client.IgnoreNotFound(err) == nil {
  683. return true
  684. }
  685. return false
  686. }, time.Second*10, time.Second).Should(BeTrue())
  687. return true
  688. }
  689. }
  690. failDelete := func(tc *testCase) {
  691. fakeProvider.SetSecretFn = func() error {
  692. return nil
  693. }
  694. fakeProvider.DeleteSecretFn = func() error {
  695. return errors.New("Nope")
  696. }
  697. tc.pushsecret = &v1alpha1.PushSecret{
  698. ObjectMeta: metav1.ObjectMeta{
  699. Name: PushSecretName,
  700. Namespace: PushSecretNamespace,
  701. },
  702. Spec: v1alpha1.PushSecretSpec{
  703. DeletionPolicy: v1alpha1.PushSecretDeletionPolicyDelete,
  704. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  705. {
  706. Name: PushSecretStore,
  707. Kind: "SecretStore",
  708. },
  709. },
  710. Selector: v1alpha1.PushSecretSelector{
  711. Secret: &v1alpha1.PushSecretSecret{
  712. Name: SecretName,
  713. },
  714. },
  715. Data: []v1alpha1.PushSecretData{
  716. {
  717. Match: v1alpha1.PushSecretMatch{
  718. SecretKey: defaultKey,
  719. RemoteRef: v1alpha1.PushSecretRemoteRef{
  720. RemoteKey: defaultPath,
  721. },
  722. },
  723. },
  724. },
  725. },
  726. }
  727. tc.assert = func(ps *v1alpha1.PushSecret, _ *v1.Secret) bool {
  728. ps.Spec.Data[0].Match.RemoteRef.RemoteKey = newKey
  729. updatedPS := &v1alpha1.PushSecret{}
  730. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  731. Eventually(func() bool {
  732. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  733. By("checking if synced secrets correspond to both keys")
  734. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  735. if err != nil {
  736. return false
  737. }
  738. _, ok := updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][newKey]
  739. if !ok {
  740. return false
  741. }
  742. _, ok = updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][defaultPath]
  743. return ok
  744. }, time.Second*10, time.Second).Should(BeTrue())
  745. return true
  746. }
  747. }
  748. failDeleteStore := func(tc *testCase) {
  749. fakeProvider.SetSecretFn = func() error {
  750. return nil
  751. }
  752. fakeProvider.DeleteSecretFn = func() error {
  753. return errors.New("boom")
  754. }
  755. tc.pushsecret.Spec.DeletionPolicy = v1alpha1.PushSecretDeletionPolicyDelete
  756. tc.assert = func(ps *v1alpha1.PushSecret, _ *v1.Secret) bool {
  757. secondStore := &esv1.SecretStore{
  758. ObjectMeta: metav1.ObjectMeta{
  759. Name: "new-store",
  760. Namespace: PushSecretNamespace,
  761. },
  762. TypeMeta: metav1.TypeMeta{
  763. Kind: "SecretStore",
  764. },
  765. Spec: esv1.SecretStoreSpec{
  766. Provider: &esv1.SecretStoreProvider{
  767. Fake: &esv1.FakeProvider{
  768. Data: []esv1.FakeProviderData{},
  769. },
  770. },
  771. },
  772. }
  773. Expect(k8sClient.Create(context.Background(), secondStore, &client.CreateOptions{})).Should(Succeed())
  774. ps.Spec.SecretStoreRefs[0].Name = "new-store"
  775. updatedPS := &v1alpha1.PushSecret{}
  776. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  777. Eventually(func() bool {
  778. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  779. By("checking if Provider value got updated")
  780. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  781. if err != nil {
  782. return false
  783. }
  784. syncedLen := len(updatedPS.Status.SyncedPushSecrets)
  785. return syncedLen == 2
  786. }, time.Second*10, time.Second).Should(BeTrue())
  787. return true
  788. }
  789. }
  790. deleteWholeStore := func(tc *testCase) {
  791. fakeProvider.SetSecretFn = func() error {
  792. return nil
  793. }
  794. fakeProvider.DeleteSecretFn = func() error {
  795. return nil
  796. }
  797. tc.pushsecret.Spec.DeletionPolicy = v1alpha1.PushSecretDeletionPolicyDelete
  798. tc.assert = func(ps *v1alpha1.PushSecret, _ *v1.Secret) bool {
  799. secondStore := &esv1.SecretStore{
  800. ObjectMeta: metav1.ObjectMeta{
  801. Name: "new-store",
  802. Namespace: PushSecretNamespace,
  803. },
  804. TypeMeta: metav1.TypeMeta{
  805. Kind: "SecretStore",
  806. },
  807. Spec: esv1.SecretStoreSpec{
  808. Provider: &esv1.SecretStoreProvider{
  809. Fake: &esv1.FakeProvider{
  810. Data: []esv1.FakeProviderData{},
  811. },
  812. },
  813. },
  814. }
  815. Expect(k8sClient.Create(context.Background(), secondStore, &client.CreateOptions{})).Should(Succeed())
  816. ps.Spec.SecretStoreRefs[0].Name = "new-store"
  817. updatedPS := &v1alpha1.PushSecret{}
  818. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  819. Eventually(func() bool {
  820. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  821. By("checking if Provider value got updated")
  822. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  823. if err != nil {
  824. return false
  825. }
  826. key, ok := updatedPS.Status.SyncedPushSecrets["SecretStore/new-store"][defaultPath]
  827. if !ok {
  828. return false
  829. }
  830. syncedLen := len(updatedPS.Status.SyncedPushSecrets)
  831. if syncedLen != 1 {
  832. return false
  833. }
  834. return key.Match.SecretKey == defaultKey
  835. }, time.Second*10, time.Second).Should(BeTrue())
  836. return true
  837. }
  838. }
  839. // if conversion strategy is defined, revert the keys based on the strategy.
  840. syncSuccessfullyWithConversionStrategy := func(tc *testCase) {
  841. fakeProvider.SetSecretFn = func() error {
  842. return nil
  843. }
  844. tc.pushsecret = &v1alpha1.PushSecret{
  845. ObjectMeta: metav1.ObjectMeta{
  846. Name: PushSecretName,
  847. Namespace: PushSecretNamespace,
  848. },
  849. Spec: v1alpha1.PushSecretSpec{
  850. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  851. {
  852. Name: PushSecretStore,
  853. Kind: "SecretStore",
  854. },
  855. },
  856. Selector: v1alpha1.PushSecretSelector{
  857. Secret: &v1alpha1.PushSecretSecret{
  858. Name: SecretName,
  859. },
  860. },
  861. Data: []v1alpha1.PushSecretData{
  862. {
  863. ConversionStrategy: v1alpha1.PushSecretConversionReverseUnicode,
  864. Match: v1alpha1.PushSecretMatch{
  865. SecretKey: "some-array[0].entity",
  866. RemoteRef: v1alpha1.PushSecretRemoteRef{
  867. RemoteKey: defaultPath,
  868. },
  869. },
  870. },
  871. },
  872. },
  873. }
  874. tc.secret = &v1.Secret{
  875. ObjectMeta: metav1.ObjectMeta{
  876. Name: SecretName,
  877. Namespace: PushSecretNamespace,
  878. },
  879. Data: map[string][]byte{
  880. "some-array_U005b_0_U005d_.entity": []byte("value"),
  881. },
  882. }
  883. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  884. Eventually(func() bool {
  885. By("checking if Provider value got updated")
  886. secretValue := secret.Data["some-array_U005b_0_U005d_.entity"]
  887. setSecretArgs := fakeProvider.GetPushSecretData()
  888. providerValue, ok := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  889. if !ok {
  890. return false
  891. }
  892. got := providerValue.Value
  893. return bytes.Equal(got, secretValue)
  894. }, time.Second*10, time.Second).Should(BeTrue())
  895. return true
  896. }
  897. }
  898. // if target Secret name is not specified it should use the ExternalSecret name.
  899. syncMatchingLabels := func(tc *testCase) {
  900. fakeProvider.SetSecretFn = func() error {
  901. return nil
  902. }
  903. fakeProvider.DeleteSecretFn = func() error {
  904. return nil
  905. }
  906. tc.pushsecret = &v1alpha1.PushSecret{
  907. ObjectMeta: metav1.ObjectMeta{
  908. Name: PushSecretName,
  909. Namespace: PushSecretNamespace,
  910. },
  911. Spec: v1alpha1.PushSecretSpec{
  912. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  913. {
  914. LabelSelector: &metav1.LabelSelector{
  915. MatchLabels: map[string]string{
  916. "foo": "bar",
  917. },
  918. },
  919. Kind: "SecretStore",
  920. Name: PushSecretStore,
  921. },
  922. },
  923. Selector: v1alpha1.PushSecretSelector{
  924. Secret: &v1alpha1.PushSecretSecret{
  925. Name: SecretName,
  926. },
  927. },
  928. Data: []v1alpha1.PushSecretData{
  929. {
  930. Match: v1alpha1.PushSecretMatch{
  931. SecretKey: defaultKey,
  932. RemoteRef: v1alpha1.PushSecretRemoteRef{
  933. RemoteKey: defaultPath,
  934. },
  935. },
  936. },
  937. },
  938. },
  939. }
  940. tc.store = &esv1.SecretStore{
  941. TypeMeta: metav1.TypeMeta{
  942. Kind: "SecretStore",
  943. },
  944. ObjectMeta: metav1.ObjectMeta{
  945. Name: PushSecretStore,
  946. Namespace: PushSecretNamespace,
  947. Labels: map[string]string{
  948. "foo": "bar",
  949. },
  950. },
  951. Spec: esv1.SecretStoreSpec{
  952. Provider: &esv1.SecretStoreProvider{
  953. Fake: &esv1.FakeProvider{
  954. Data: []esv1.FakeProviderData{},
  955. },
  956. },
  957. },
  958. }
  959. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  960. secretValue := secret.Data[defaultKey]
  961. setSecretArgs := fakeProvider.GetPushSecretData()
  962. providerValue := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  963. expected := v1alpha1.PushSecretStatusCondition{
  964. Type: v1alpha1.PushSecretReady,
  965. Status: v1.ConditionTrue,
  966. Reason: v1alpha1.ReasonSynced,
  967. Message: "PushSecret synced successfully",
  968. }
  969. return bytes.Equal(secretValue, providerValue) && checkCondition(ps.Status, expected)
  970. }
  971. }
  972. syncWithClusterStore := func(tc *testCase) {
  973. fakeProvider.SetSecretFn = func() error {
  974. return nil
  975. }
  976. tc.store = &esv1.ClusterSecretStore{
  977. TypeMeta: metav1.TypeMeta{
  978. Kind: "ClusterSecretStore",
  979. },
  980. ObjectMeta: metav1.ObjectMeta{
  981. Name: PushSecretStore,
  982. },
  983. Spec: esv1.SecretStoreSpec{
  984. Provider: &esv1.SecretStoreProvider{
  985. Fake: &esv1.FakeProvider{
  986. Data: []esv1.FakeProviderData{},
  987. },
  988. },
  989. },
  990. }
  991. tc.pushsecret.Spec.SecretStoreRefs[0].Kind = "ClusterSecretStore"
  992. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  993. secretValue := secret.Data[defaultKey]
  994. setSecretArgs := fakeProvider.GetPushSecretData()
  995. providerValue := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  996. expected := v1alpha1.PushSecretStatusCondition{
  997. Type: v1alpha1.PushSecretReady,
  998. Status: v1.ConditionTrue,
  999. Reason: v1alpha1.ReasonSynced,
  1000. Message: "PushSecret synced successfully",
  1001. }
  1002. return bytes.Equal(secretValue, providerValue) && checkCondition(ps.Status, expected)
  1003. }
  1004. }
  1005. syncWithGenerator := func(tc *testCase) {
  1006. fakeProvider.SetSecretFn = func() error {
  1007. return nil
  1008. }
  1009. tc.pushsecret.Spec.Selector.Secret = nil
  1010. tc.pushsecret.Spec.Selector.GeneratorRef = &esv1.GeneratorRef{
  1011. APIVersion: "generators.external-secrets.io/v1alpha1",
  1012. Kind: "Fake",
  1013. Name: "test",
  1014. }
  1015. tc.assert = func(ps *v1alpha1.PushSecret, _ *v1.Secret) bool {
  1016. setSecretArgs := fakeProvider.GetPushSecretData()
  1017. providerValue := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  1018. expected := v1alpha1.PushSecretStatusCondition{
  1019. Type: v1alpha1.PushSecretReady,
  1020. Status: v1.ConditionTrue,
  1021. Reason: v1alpha1.ReasonSynced,
  1022. Message: "PushSecret synced successfully",
  1023. }
  1024. return bytes.Equal([]byte("foo-bar-from-generator"), providerValue) && checkCondition(ps.Status, expected)
  1025. }
  1026. }
  1027. // if target Secret name is not specified it should use the ExternalSecret name.
  1028. syncWithClusterStoreMatchingLabels := func(tc *testCase) {
  1029. fakeProvider.SetSecretFn = func() error {
  1030. return nil
  1031. }
  1032. tc.pushsecret = &v1alpha1.PushSecret{
  1033. ObjectMeta: metav1.ObjectMeta{
  1034. Name: PushSecretName,
  1035. Namespace: PushSecretNamespace,
  1036. },
  1037. Spec: v1alpha1.PushSecretSpec{
  1038. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  1039. {
  1040. LabelSelector: &metav1.LabelSelector{
  1041. MatchLabels: map[string]string{
  1042. "foo": "bar",
  1043. },
  1044. },
  1045. Kind: "ClusterSecretStore",
  1046. Name: PushSecretStore,
  1047. },
  1048. },
  1049. Selector: v1alpha1.PushSecretSelector{
  1050. Secret: &v1alpha1.PushSecretSecret{
  1051. Name: SecretName,
  1052. },
  1053. },
  1054. Data: []v1alpha1.PushSecretData{
  1055. {
  1056. Match: v1alpha1.PushSecretMatch{
  1057. SecretKey: defaultKey,
  1058. RemoteRef: v1alpha1.PushSecretRemoteRef{
  1059. RemoteKey: defaultPath,
  1060. },
  1061. },
  1062. },
  1063. },
  1064. },
  1065. }
  1066. tc.store = &esv1.ClusterSecretStore{
  1067. ObjectMeta: metav1.ObjectMeta{
  1068. Name: PushSecretStore,
  1069. Labels: map[string]string{
  1070. "foo": "bar",
  1071. },
  1072. },
  1073. Spec: esv1.SecretStoreSpec{
  1074. Provider: &esv1.SecretStoreProvider{
  1075. Fake: &esv1.FakeProvider{
  1076. Data: []esv1.FakeProviderData{},
  1077. },
  1078. },
  1079. },
  1080. }
  1081. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1082. secretValue := secret.Data[defaultKey]
  1083. setSecretArgs := fakeProvider.GetPushSecretData()
  1084. providerValue := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  1085. expected := v1alpha1.PushSecretStatusCondition{
  1086. Type: v1alpha1.PushSecretReady,
  1087. Status: v1.ConditionTrue,
  1088. Reason: v1alpha1.ReasonSynced,
  1089. Message: "PushSecret synced successfully",
  1090. }
  1091. return bytes.Equal(secretValue, providerValue) && checkCondition(ps.Status, expected)
  1092. }
  1093. }
  1094. // if target Secret name is not specified it should use the ExternalSecret name.
  1095. failNoSecret := func(tc *testCase) {
  1096. fakeProvider.SetSecretFn = func() error {
  1097. return nil
  1098. }
  1099. tc.secret = nil
  1100. tc.assert = func(ps *v1alpha1.PushSecret, _ *v1.Secret) bool {
  1101. expected := v1alpha1.PushSecretStatusCondition{
  1102. Type: v1alpha1.PushSecretReady,
  1103. Status: v1.ConditionFalse,
  1104. Reason: v1alpha1.ReasonErrored,
  1105. Message: "could not get source secret",
  1106. }
  1107. return checkCondition(ps.Status, expected)
  1108. }
  1109. }
  1110. // if target Secret name is not specified it should use the ExternalSecret name.
  1111. failNoSecretKey := func(tc *testCase) {
  1112. fakeProvider.SetSecretFn = func() error {
  1113. return nil
  1114. }
  1115. tc.pushsecret.Spec.Data[0].Match.SecretKey = "unexisting"
  1116. tc.assert = func(ps *v1alpha1.PushSecret, _ *v1.Secret) bool {
  1117. expected := v1alpha1.PushSecretStatusCondition{
  1118. Type: v1alpha1.PushSecretReady,
  1119. Status: v1.ConditionFalse,
  1120. Reason: v1alpha1.ReasonErrored,
  1121. Message: "set secret failed: secret key unexisting does not exist",
  1122. }
  1123. return checkCondition(ps.Status, expected)
  1124. }
  1125. }
  1126. // if target Secret name is not specified it should use the ExternalSecret name.
  1127. failNoSecretStore := func(tc *testCase) {
  1128. fakeProvider.SetSecretFn = func() error {
  1129. return nil
  1130. }
  1131. tc.store = nil
  1132. tc.assert = func(ps *v1alpha1.PushSecret, _ *v1.Secret) bool {
  1133. expected := v1alpha1.PushSecretStatusCondition{
  1134. Type: v1alpha1.PushSecretReady,
  1135. Status: v1.ConditionFalse,
  1136. Reason: v1alpha1.ReasonErrored,
  1137. Message: "could not get SecretStore \"test-store\", secretstores.external-secrets.io \"test-store\" not found",
  1138. }
  1139. return checkCondition(ps.Status, expected)
  1140. }
  1141. }
  1142. // if target Secret name is not specified it should use the ExternalSecret name.
  1143. failNoClusterStore := func(tc *testCase) {
  1144. fakeProvider.SetSecretFn = func() error {
  1145. return nil
  1146. }
  1147. tc.store = nil
  1148. tc.pushsecret.Spec.SecretStoreRefs[0].Kind = "ClusterSecretStore"
  1149. tc.pushsecret.Spec.SecretStoreRefs[0].Name = "unexisting"
  1150. tc.assert = func(ps *v1alpha1.PushSecret, _ *v1.Secret) bool {
  1151. expected := v1alpha1.PushSecretStatusCondition{
  1152. Type: v1alpha1.PushSecretReady,
  1153. Status: v1.ConditionFalse,
  1154. Reason: v1alpha1.ReasonErrored,
  1155. Message: "could not get ClusterSecretStore \"unexisting\", clustersecretstores.external-secrets.io \"unexisting\" not found",
  1156. }
  1157. return checkCondition(ps.Status, expected)
  1158. }
  1159. }
  1160. // if target Secret name is not specified it should use the ExternalSecret name.
  1161. setSecretFail := func(tc *testCase) {
  1162. fakeProvider.SetSecretFn = func() error {
  1163. return errors.New("boom")
  1164. }
  1165. tc.assert = func(ps *v1alpha1.PushSecret, _ *v1.Secret) bool {
  1166. expected := v1alpha1.PushSecretStatusCondition{
  1167. Type: v1alpha1.PushSecretReady,
  1168. Status: v1.ConditionFalse,
  1169. Reason: v1alpha1.ReasonErrored,
  1170. Message: "set secret failed: could not write remote ref key to target secretstore test-store: boom",
  1171. }
  1172. return checkCondition(ps.Status, expected)
  1173. }
  1174. }
  1175. // if target Secret name is not specified it should use the ExternalSecret name.
  1176. newClientFail := func(tc *testCase) {
  1177. fakeProvider.NewFn = func(_ context.Context, _ esv1.GenericStore, _ client.Client, _ string) (esv1.SecretsClient, error) {
  1178. return nil, errors.New("boom")
  1179. }
  1180. tc.assert = func(ps *v1alpha1.PushSecret, _ *v1.Secret) bool {
  1181. expected := v1alpha1.PushSecretStatusCondition{
  1182. Type: v1alpha1.PushSecretReady,
  1183. Status: v1.ConditionFalse,
  1184. Reason: v1alpha1.ReasonErrored,
  1185. Message: "set secret failed: could not get secrets client for store test-store: boom",
  1186. }
  1187. return checkCondition(ps.Status, expected)
  1188. }
  1189. }
  1190. // SecretStores in different namespace than PushSecret should not be selected.
  1191. secretStoreDifferentNamespace := func(tc *testCase) {
  1192. fakeProvider.SetSecretFn = func() error {
  1193. return nil
  1194. }
  1195. // Create the SecretStore in a different namespace
  1196. tc.store = &esv1.SecretStore{
  1197. ObjectMeta: metav1.ObjectMeta{
  1198. Name: "other-ns-store",
  1199. Namespace: OtherNamespace,
  1200. Labels: map[string]string{
  1201. "foo": "bar",
  1202. },
  1203. },
  1204. TypeMeta: metav1.TypeMeta{
  1205. Kind: "SecretStore",
  1206. },
  1207. Spec: esv1.SecretStoreSpec{
  1208. Provider: &esv1.SecretStoreProvider{
  1209. Fake: &esv1.FakeProvider{
  1210. Data: []esv1.FakeProviderData{},
  1211. },
  1212. },
  1213. },
  1214. }
  1215. // Use label selector to select SecretStores
  1216. tc.pushsecret.Spec.SecretStoreRefs = []v1alpha1.PushSecretStoreRef{
  1217. {
  1218. Kind: "SecretStore",
  1219. LabelSelector: &metav1.LabelSelector{
  1220. MatchLabels: map[string]string{
  1221. "foo": "bar",
  1222. },
  1223. },
  1224. },
  1225. }
  1226. // Should not select the SecretStore in a different namespace
  1227. // (if so, it would fail to find it in the same namespace and be reflected in the status)
  1228. tc.assert = func(ps *v1alpha1.PushSecret, _ *v1.Secret) bool {
  1229. // Assert that the status is never updated (no SecretStores found)
  1230. Consistently(func() bool {
  1231. err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(ps), ps)
  1232. if err != nil {
  1233. return false
  1234. }
  1235. return len(ps.Status.Conditions) == 0
  1236. }, timeout, interval).Should(BeTrue())
  1237. return true
  1238. }
  1239. }
  1240. // Secrets in different namespace than PushSecret should not be selected.
  1241. secretDifferentNamespace := func(tc *testCase) {
  1242. fakeProvider.SetSecretFn = func() error {
  1243. return nil
  1244. }
  1245. // Create the Secret in a different namespace
  1246. tc.secret = &v1.Secret{
  1247. ObjectMeta: metav1.ObjectMeta{
  1248. Name: SecretName,
  1249. Namespace: OtherNamespace,
  1250. Labels: map[string]string{
  1251. "foo": "bar",
  1252. },
  1253. },
  1254. Data: map[string][]byte{
  1255. defaultKey: []byte(defaultVal),
  1256. },
  1257. }
  1258. // Use label selector to select Secrets
  1259. tc.pushsecret.Spec.Selector.Secret = &v1alpha1.PushSecretSecret{
  1260. Selector: &metav1.LabelSelector{
  1261. MatchLabels: map[string]string{
  1262. "foo": "bar",
  1263. },
  1264. },
  1265. }
  1266. tc.assert = func(_ *v1alpha1.PushSecret, _ *v1.Secret) bool {
  1267. Eventually(func() bool {
  1268. // We should not be able to reference a secret across namespaces,
  1269. // the map should be empty.
  1270. Expect(fakeProvider.GetPushSecretData()).To(BeEmpty())
  1271. return true
  1272. }, time.Second*10, time.Second).Should(BeTrue())
  1273. return true
  1274. }
  1275. }
  1276. DescribeTable("When reconciling a PushSecret",
  1277. func(tweaks ...testTweaks) {
  1278. tc := makeDefaultTestcase()
  1279. for _, tweak := range tweaks {
  1280. tweak(tc)
  1281. }
  1282. ctx := context.Background()
  1283. By("creating a secret store, secret and pushsecret")
  1284. if tc.store != nil {
  1285. Expect(k8sClient.Create(ctx, tc.store)).To(Succeed())
  1286. }
  1287. if tc.secret != nil {
  1288. Expect(k8sClient.Create(ctx, tc.secret)).To(Succeed())
  1289. }
  1290. if tc.pushsecret != nil {
  1291. Expect(k8sClient.Create(ctx, tc.pushsecret)).Should(Succeed())
  1292. }
  1293. time.Sleep(2 * time.Second) // prevents race conditions during tests causing failures
  1294. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  1295. createdPS := &v1alpha1.PushSecret{}
  1296. By("checking the pushSecret condition")
  1297. Eventually(func() bool {
  1298. err := k8sClient.Get(ctx, psKey, createdPS)
  1299. if err != nil {
  1300. return false
  1301. }
  1302. return tc.assert(createdPS, tc.secret)
  1303. }, timeout, interval).Should(BeTrue())
  1304. // this must be optional so we can test faulty es configuration
  1305. },
  1306. Entry("should sync", syncSuccessfully),
  1307. Entry("should not update existing secret if UpdatePolicy=IfNotExists", updateIfNotExists),
  1308. Entry("should only update parts of secret that don't already exist if UpdatePolicy=IfNotExists", updateIfNotExistsPartialSecrets),
  1309. Entry("should update the PushSecret status correctly if UpdatePolicy=IfNotExists", updateIfNotExistsSyncStatus),
  1310. Entry("should fail if secret existence cannot be verified if UpdatePolicy=IfNotExists", updateIfNotExistsSyncFailed),
  1311. Entry("should sync with template", syncSuccessfullyWithTemplate),
  1312. Entry("should sync with template reusing keys", syncSuccessfullyReusingKeys),
  1313. Entry("should sync with conversion strategy", syncSuccessfullyWithConversionStrategy),
  1314. Entry("should delete if DeletionPolicy=Delete", syncAndDeleteSuccessfully),
  1315. Entry("should delete secrets with properties and update status correctly", syncAndDeleteWithProperties),
  1316. Entry("should delete after DeletionPolicy changed from Delete to None", syncChangePolicyAndDeleteSuccessfully),
  1317. Entry("should track deletion tasks if Delete fails", failDelete),
  1318. Entry("should track deleted stores if Delete fails", failDeleteStore),
  1319. Entry("should delete all secrets if SecretStore changes", deleteWholeStore),
  1320. Entry("should sync to stores matching labels", syncMatchingLabels),
  1321. Entry("should sync with ClusterStore", syncWithClusterStore),
  1322. Entry("should sync with ClusterStore matching labels", syncWithClusterStoreMatchingLabels),
  1323. Entry("should sync with Generator", syncWithGenerator),
  1324. Entry("should fail if Secret is not created", failNoSecret),
  1325. Entry("should fail if Secret Key does not exist", failNoSecretKey),
  1326. Entry("should fail if SetSecret fails", setSecretFail),
  1327. Entry("should fail if no valid SecretStore", failNoSecretStore),
  1328. Entry("should fail if no valid ClusterSecretStore", failNoClusterStore),
  1329. Entry("should fail if NewClient fails", newClientFail),
  1330. Entry("should not sync to SecretStore in different namespace", secretStoreDifferentNamespace),
  1331. Entry("should not reference secret in different namespace", secretDifferentNamespace),
  1332. )
  1333. })
  1334. var _ = Describe("PushSecret Controller Un/Managed Stores", func() {
  1335. const (
  1336. PushSecretName = "test-ps"
  1337. ManagedPushSecretStore1 = "test-managed-store-1"
  1338. ManagedPushSecretStore2 = "test-managed-store-2"
  1339. UnmanagedPushSecretStore1 = "test-unmanaged-store-1"
  1340. UnmanagedPushSecretStore2 = "test-unmanaged-store-2"
  1341. SecretName = "test-secret"
  1342. )
  1343. var PushSecretNamespace string
  1344. PushSecretStores := []string{ManagedPushSecretStore1, ManagedPushSecretStore2, UnmanagedPushSecretStore1, UnmanagedPushSecretStore2}
  1345. // if we are in debug and need to increase the timeout for testing, we can do so by using an env var
  1346. if customTimeout := os.Getenv("TEST_CUSTOM_TIMEOUT_SEC"); customTimeout != "" {
  1347. if t, err := strconv.Atoi(customTimeout); err == nil {
  1348. timeout = time.Second * time.Duration(t)
  1349. }
  1350. }
  1351. BeforeEach(func() {
  1352. var err error
  1353. PushSecretNamespace, err = ctest.CreateNamespace("test-ns", k8sClient)
  1354. Expect(err).ToNot(HaveOccurred())
  1355. fakeProvider.Reset()
  1356. })
  1357. AfterEach(func() {
  1358. k8sClient.Delete(context.Background(), &v1alpha1.PushSecret{
  1359. ObjectMeta: metav1.ObjectMeta{
  1360. Name: PushSecretName,
  1361. Namespace: PushSecretNamespace,
  1362. },
  1363. })
  1364. // give a time for reconciler to remove finalizers before removing SecretStores
  1365. time.Sleep(2 * time.Second)
  1366. for _, psstore := range PushSecretStores {
  1367. k8sClient.Delete(context.Background(), &esv1.SecretStore{
  1368. ObjectMeta: metav1.ObjectMeta{
  1369. Name: psstore,
  1370. Namespace: PushSecretNamespace,
  1371. },
  1372. })
  1373. k8sClient.Delete(context.Background(), &esv1.ClusterSecretStore{
  1374. ObjectMeta: metav1.ObjectMeta{
  1375. Name: psstore,
  1376. },
  1377. })
  1378. }
  1379. k8sClient.Delete(context.Background(), &v1.Secret{
  1380. ObjectMeta: metav1.ObjectMeta{
  1381. Name: SecretName,
  1382. Namespace: PushSecretNamespace,
  1383. },
  1384. })
  1385. Expect(k8sClient.Delete(context.Background(), &v1.Namespace{
  1386. ObjectMeta: metav1.ObjectMeta{
  1387. Name: PushSecretNamespace,
  1388. },
  1389. })).To(Succeed())
  1390. })
  1391. const (
  1392. defaultKey = "key"
  1393. defaultVal = "value"
  1394. defaultPath = "path/to/key"
  1395. )
  1396. makeDefaultTestcase := func() *testCase {
  1397. return &testCase{
  1398. pushsecret: &v1alpha1.PushSecret{
  1399. ObjectMeta: metav1.ObjectMeta{
  1400. Name: PushSecretName,
  1401. Namespace: PushSecretNamespace,
  1402. },
  1403. Spec: v1alpha1.PushSecretSpec{
  1404. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  1405. {
  1406. Name: ManagedPushSecretStore1,
  1407. Kind: "SecretStore",
  1408. },
  1409. },
  1410. Selector: v1alpha1.PushSecretSelector{
  1411. Secret: &v1alpha1.PushSecretSecret{
  1412. Name: SecretName,
  1413. },
  1414. },
  1415. Data: []v1alpha1.PushSecretData{
  1416. {
  1417. Match: v1alpha1.PushSecretMatch{
  1418. SecretKey: defaultKey,
  1419. RemoteRef: v1alpha1.PushSecretRemoteRef{
  1420. RemoteKey: defaultPath,
  1421. },
  1422. },
  1423. },
  1424. },
  1425. },
  1426. },
  1427. secret: &v1.Secret{
  1428. ObjectMeta: metav1.ObjectMeta{
  1429. Name: SecretName,
  1430. Namespace: PushSecretNamespace,
  1431. },
  1432. Data: map[string][]byte{
  1433. defaultKey: []byte(defaultVal),
  1434. },
  1435. },
  1436. managedStore1: &esv1.SecretStore{
  1437. ObjectMeta: metav1.ObjectMeta{
  1438. Name: ManagedPushSecretStore1,
  1439. Namespace: PushSecretNamespace,
  1440. },
  1441. TypeMeta: metav1.TypeMeta{
  1442. Kind: "SecretStore",
  1443. },
  1444. Spec: esv1.SecretStoreSpec{
  1445. Provider: &esv1.SecretStoreProvider{
  1446. Fake: &esv1.FakeProvider{
  1447. Data: []esv1.FakeProviderData{},
  1448. },
  1449. },
  1450. },
  1451. },
  1452. managedStore2: &esv1.SecretStore{
  1453. ObjectMeta: metav1.ObjectMeta{
  1454. Name: ManagedPushSecretStore2,
  1455. Namespace: PushSecretNamespace,
  1456. },
  1457. TypeMeta: metav1.TypeMeta{
  1458. Kind: "SecretStore",
  1459. },
  1460. Spec: esv1.SecretStoreSpec{
  1461. Provider: &esv1.SecretStoreProvider{
  1462. Fake: &esv1.FakeProvider{
  1463. Data: []esv1.FakeProviderData{},
  1464. },
  1465. },
  1466. },
  1467. },
  1468. unmanagedStore1: &esv1.SecretStore{
  1469. ObjectMeta: metav1.ObjectMeta{
  1470. Name: UnmanagedPushSecretStore1,
  1471. Namespace: PushSecretNamespace,
  1472. },
  1473. TypeMeta: metav1.TypeMeta{
  1474. Kind: "SecretStore",
  1475. },
  1476. Spec: esv1.SecretStoreSpec{
  1477. Provider: &esv1.SecretStoreProvider{
  1478. Fake: &esv1.FakeProvider{
  1479. Data: []esv1.FakeProviderData{},
  1480. },
  1481. },
  1482. Controller: "not-managed",
  1483. },
  1484. },
  1485. unmanagedStore2: &esv1.SecretStore{
  1486. ObjectMeta: metav1.ObjectMeta{
  1487. Name: UnmanagedPushSecretStore2,
  1488. Namespace: PushSecretNamespace,
  1489. },
  1490. TypeMeta: metav1.TypeMeta{
  1491. Kind: "SecretStore",
  1492. },
  1493. Spec: esv1.SecretStoreSpec{
  1494. Provider: &esv1.SecretStoreProvider{
  1495. Fake: &esv1.FakeProvider{
  1496. Data: []esv1.FakeProviderData{},
  1497. },
  1498. },
  1499. Controller: "not-managed",
  1500. },
  1501. },
  1502. }
  1503. }
  1504. multipleManagedStoresSyncsSuccessfully := func(tc *testCase) {
  1505. fakeProvider.SetSecretFn = func() error {
  1506. return nil
  1507. }
  1508. tc.pushsecret.Spec.SecretStoreRefs = append(tc.pushsecret.Spec.SecretStoreRefs,
  1509. v1alpha1.PushSecretStoreRef{
  1510. Name: ManagedPushSecretStore2,
  1511. Kind: "SecretStore",
  1512. },
  1513. )
  1514. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1515. Eventually(func() bool {
  1516. By("checking if Provider value got updated")
  1517. secretValue := secret.Data[defaultKey]
  1518. setSecretArgs := fakeProvider.GetPushSecretData()
  1519. providerValue, ok := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  1520. if !ok {
  1521. return false
  1522. }
  1523. got := providerValue.Value
  1524. return bytes.Equal(got, secretValue)
  1525. }, time.Second*10, time.Second).Should(BeTrue())
  1526. return true
  1527. }
  1528. }
  1529. skipUnmanagedStores := func(tc *testCase) {
  1530. tc.pushsecret.Spec.SecretStoreRefs = []v1alpha1.PushSecretStoreRef{
  1531. {
  1532. Name: UnmanagedPushSecretStore1,
  1533. Kind: "SecretStore",
  1534. },
  1535. {
  1536. Name: UnmanagedPushSecretStore2,
  1537. Kind: "SecretStore",
  1538. },
  1539. }
  1540. tc.assert = func(ps *v1alpha1.PushSecret, _ *v1.Secret) bool {
  1541. return len(ps.Status.Conditions) == 0
  1542. }
  1543. }
  1544. warnUnmanagedStoresAndSyncManagedStores := func(tc *testCase) {
  1545. fakeProvider.SetSecretFn = func() error {
  1546. return nil
  1547. }
  1548. tc.pushsecret.Spec.SecretStoreRefs = []v1alpha1.PushSecretStoreRef{
  1549. {
  1550. Name: ManagedPushSecretStore1,
  1551. Kind: "SecretStore",
  1552. },
  1553. {
  1554. Name: ManagedPushSecretStore2,
  1555. Kind: "SecretStore",
  1556. },
  1557. {
  1558. Name: UnmanagedPushSecretStore1,
  1559. Kind: "SecretStore",
  1560. },
  1561. {
  1562. Name: UnmanagedPushSecretStore2,
  1563. Kind: "SecretStore",
  1564. },
  1565. }
  1566. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1567. Eventually(func() bool {
  1568. By("checking if Provider value got updated")
  1569. secretValue := secret.Data[defaultKey]
  1570. setSecretArgs := fakeProvider.GetPushSecretData()
  1571. providerValue, ok := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  1572. if !ok {
  1573. return false
  1574. }
  1575. got := providerValue.Value
  1576. return bytes.Equal(got, secretValue)
  1577. }, time.Second*10, time.Second).Should(BeTrue())
  1578. return true
  1579. }
  1580. }
  1581. DescribeTable("When reconciling a PushSecret with multiple secret stores",
  1582. func(tweaks ...testTweaks) {
  1583. tc := makeDefaultTestcase()
  1584. for _, tweak := range tweaks {
  1585. tweak(tc)
  1586. }
  1587. ctx := context.Background()
  1588. By("creating secret stores, a secret and a pushsecret")
  1589. if tc.managedStore1 != nil {
  1590. Expect(k8sClient.Create(ctx, tc.managedStore1)).To(Succeed())
  1591. }
  1592. if tc.managedStore2 != nil {
  1593. Expect(k8sClient.Create(ctx, tc.managedStore2)).To(Succeed())
  1594. }
  1595. if tc.unmanagedStore1 != nil {
  1596. Expect(k8sClient.Create(ctx, tc.unmanagedStore1)).To(Succeed())
  1597. }
  1598. if tc.unmanagedStore2 != nil {
  1599. Expect(k8sClient.Create(ctx, tc.unmanagedStore2)).To(Succeed())
  1600. }
  1601. if tc.secret != nil {
  1602. Expect(k8sClient.Create(ctx, tc.secret)).To(Succeed())
  1603. }
  1604. if tc.pushsecret != nil {
  1605. Expect(k8sClient.Create(ctx, tc.pushsecret)).Should(Succeed())
  1606. }
  1607. time.Sleep(2 * time.Second) // prevents race conditions during tests causing failures
  1608. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  1609. createdPS := &v1alpha1.PushSecret{}
  1610. By("checking the pushSecret condition")
  1611. Eventually(func() bool {
  1612. err := k8sClient.Get(ctx, psKey, createdPS)
  1613. if err != nil {
  1614. return false
  1615. }
  1616. return tc.assert(createdPS, tc.secret)
  1617. }, timeout, interval).Should(BeTrue())
  1618. // this must be optional so we can test faulty es configuration
  1619. },
  1620. Entry("should sync successfully if there are multiple managed stores", multipleManagedStoresSyncsSuccessfully),
  1621. Entry("should skip unmanaged stores", skipUnmanagedStores),
  1622. Entry("should skip unmanaged stores and sync managed stores", warnUnmanagedStoresAndSyncManagedStores),
  1623. )
  1624. })