pushsecret_controller_test.go 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586
  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/pkg/provider/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(ctx 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(ctx 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(ctx 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(ctx context.Context, ref 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, secret *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, secret *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, secret *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, secret *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's DeletionPolicy is cleared, it should delete successfully
  547. syncChangePolicyAndDeleteSuccessfully := func(tc *testCase) {
  548. fakeProvider.SetSecretFn = func() error {
  549. return nil
  550. }
  551. tc.pushsecret = &v1alpha1.PushSecret{
  552. ObjectMeta: metav1.ObjectMeta{
  553. Name: PushSecretName,
  554. Namespace: PushSecretNamespace,
  555. },
  556. Spec: v1alpha1.PushSecretSpec{
  557. DeletionPolicy: v1alpha1.PushSecretDeletionPolicyDelete,
  558. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  559. {
  560. Name: PushSecretStore,
  561. Kind: "SecretStore",
  562. },
  563. },
  564. Selector: v1alpha1.PushSecretSelector{
  565. Secret: &v1alpha1.PushSecretSecret{
  566. Name: SecretName,
  567. },
  568. },
  569. Data: []v1alpha1.PushSecretData{
  570. {
  571. Match: v1alpha1.PushSecretMatch{
  572. SecretKey: defaultKey,
  573. RemoteRef: v1alpha1.PushSecretRemoteRef{
  574. RemoteKey: defaultPath,
  575. },
  576. },
  577. },
  578. },
  579. },
  580. }
  581. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  582. ps.Spec.DeletionPolicy = v1alpha1.PushSecretDeletionPolicyNone
  583. updatedPS := &v1alpha1.PushSecret{}
  584. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  585. Expect(k8sClient.Delete(context.Background(), ps, &client.DeleteOptions{})).Should(Succeed())
  586. Eventually(func() bool {
  587. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  588. By("checking if Get PushSecret returns not found")
  589. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  590. if err != nil && client.IgnoreNotFound(err) == nil {
  591. return true
  592. }
  593. return false
  594. }, time.Second*10, time.Second).Should(BeTrue())
  595. return true
  596. }
  597. }
  598. failDelete := func(tc *testCase) {
  599. fakeProvider.SetSecretFn = func() error {
  600. return nil
  601. }
  602. fakeProvider.DeleteSecretFn = func() error {
  603. return errors.New("Nope")
  604. }
  605. tc.pushsecret = &v1alpha1.PushSecret{
  606. ObjectMeta: metav1.ObjectMeta{
  607. Name: PushSecretName,
  608. Namespace: PushSecretNamespace,
  609. },
  610. Spec: v1alpha1.PushSecretSpec{
  611. DeletionPolicy: v1alpha1.PushSecretDeletionPolicyDelete,
  612. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  613. {
  614. Name: PushSecretStore,
  615. Kind: "SecretStore",
  616. },
  617. },
  618. Selector: v1alpha1.PushSecretSelector{
  619. Secret: &v1alpha1.PushSecretSecret{
  620. Name: SecretName,
  621. },
  622. },
  623. Data: []v1alpha1.PushSecretData{
  624. {
  625. Match: v1alpha1.PushSecretMatch{
  626. SecretKey: defaultKey,
  627. RemoteRef: v1alpha1.PushSecretRemoteRef{
  628. RemoteKey: defaultPath,
  629. },
  630. },
  631. },
  632. },
  633. },
  634. }
  635. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  636. ps.Spec.Data[0].Match.RemoteRef.RemoteKey = newKey
  637. updatedPS := &v1alpha1.PushSecret{}
  638. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  639. Eventually(func() bool {
  640. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  641. By("checking if synced secrets correspond to both keys")
  642. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  643. if err != nil {
  644. return false
  645. }
  646. _, ok := updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][newKey]
  647. if !ok {
  648. return false
  649. }
  650. _, ok = updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][defaultPath]
  651. return ok
  652. }, time.Second*10, time.Second).Should(BeTrue())
  653. return true
  654. }
  655. }
  656. failDeleteStore := func(tc *testCase) {
  657. fakeProvider.SetSecretFn = func() error {
  658. return nil
  659. }
  660. fakeProvider.DeleteSecretFn = func() error {
  661. return errors.New("boom")
  662. }
  663. tc.pushsecret.Spec.DeletionPolicy = v1alpha1.PushSecretDeletionPolicyDelete
  664. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  665. secondStore := &esv1.SecretStore{
  666. ObjectMeta: metav1.ObjectMeta{
  667. Name: "new-store",
  668. Namespace: PushSecretNamespace,
  669. },
  670. TypeMeta: metav1.TypeMeta{
  671. Kind: "SecretStore",
  672. },
  673. Spec: esv1.SecretStoreSpec{
  674. Provider: &esv1.SecretStoreProvider{
  675. Fake: &esv1.FakeProvider{
  676. Data: []esv1.FakeProviderData{},
  677. },
  678. },
  679. },
  680. }
  681. Expect(k8sClient.Create(context.Background(), secondStore, &client.CreateOptions{})).Should(Succeed())
  682. ps.Spec.SecretStoreRefs[0].Name = "new-store"
  683. updatedPS := &v1alpha1.PushSecret{}
  684. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  685. Eventually(func() bool {
  686. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  687. By("checking if Provider value got updated")
  688. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  689. if err != nil {
  690. return false
  691. }
  692. syncedLen := len(updatedPS.Status.SyncedPushSecrets)
  693. return syncedLen == 2
  694. }, time.Second*10, time.Second).Should(BeTrue())
  695. return true
  696. }
  697. }
  698. deleteWholeStore := func(tc *testCase) {
  699. fakeProvider.SetSecretFn = func() error {
  700. return nil
  701. }
  702. fakeProvider.DeleteSecretFn = func() error {
  703. return nil
  704. }
  705. tc.pushsecret.Spec.DeletionPolicy = v1alpha1.PushSecretDeletionPolicyDelete
  706. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  707. secondStore := &esv1.SecretStore{
  708. ObjectMeta: metav1.ObjectMeta{
  709. Name: "new-store",
  710. Namespace: PushSecretNamespace,
  711. },
  712. TypeMeta: metav1.TypeMeta{
  713. Kind: "SecretStore",
  714. },
  715. Spec: esv1.SecretStoreSpec{
  716. Provider: &esv1.SecretStoreProvider{
  717. Fake: &esv1.FakeProvider{
  718. Data: []esv1.FakeProviderData{},
  719. },
  720. },
  721. },
  722. }
  723. Expect(k8sClient.Create(context.Background(), secondStore, &client.CreateOptions{})).Should(Succeed())
  724. ps.Spec.SecretStoreRefs[0].Name = "new-store"
  725. updatedPS := &v1alpha1.PushSecret{}
  726. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  727. Eventually(func() bool {
  728. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  729. By("checking if Provider value got updated")
  730. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  731. if err != nil {
  732. return false
  733. }
  734. key, ok := updatedPS.Status.SyncedPushSecrets["SecretStore/new-store"][defaultPath]
  735. if !ok {
  736. return false
  737. }
  738. syncedLen := len(updatedPS.Status.SyncedPushSecrets)
  739. if syncedLen != 1 {
  740. return false
  741. }
  742. return key.Match.SecretKey == defaultKey
  743. }, time.Second*10, time.Second).Should(BeTrue())
  744. return true
  745. }
  746. }
  747. // if conversion strategy is defined, revert the keys based on the strategy.
  748. syncSuccessfullyWithConversionStrategy := func(tc *testCase) {
  749. fakeProvider.SetSecretFn = func() error {
  750. return nil
  751. }
  752. tc.pushsecret = &v1alpha1.PushSecret{
  753. ObjectMeta: metav1.ObjectMeta{
  754. Name: PushSecretName,
  755. Namespace: PushSecretNamespace,
  756. },
  757. Spec: v1alpha1.PushSecretSpec{
  758. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  759. {
  760. Name: PushSecretStore,
  761. Kind: "SecretStore",
  762. },
  763. },
  764. Selector: v1alpha1.PushSecretSelector{
  765. Secret: &v1alpha1.PushSecretSecret{
  766. Name: SecretName,
  767. },
  768. },
  769. Data: []v1alpha1.PushSecretData{
  770. {
  771. ConversionStrategy: v1alpha1.PushSecretConversionReverseUnicode,
  772. Match: v1alpha1.PushSecretMatch{
  773. SecretKey: "some-array[0].entity",
  774. RemoteRef: v1alpha1.PushSecretRemoteRef{
  775. RemoteKey: defaultPath,
  776. },
  777. },
  778. },
  779. },
  780. },
  781. }
  782. tc.secret = &v1.Secret{
  783. ObjectMeta: metav1.ObjectMeta{
  784. Name: SecretName,
  785. Namespace: PushSecretNamespace,
  786. },
  787. Data: map[string][]byte{
  788. "some-array_U005b_0_U005d_.entity": []byte("value"),
  789. },
  790. }
  791. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  792. Eventually(func() bool {
  793. By("checking if Provider value got updated")
  794. secretValue := secret.Data["some-array_U005b_0_U005d_.entity"]
  795. setSecretArgs := fakeProvider.GetPushSecretData()
  796. providerValue, ok := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  797. if !ok {
  798. return false
  799. }
  800. got := providerValue.Value
  801. return bytes.Equal(got, secretValue)
  802. }, time.Second*10, time.Second).Should(BeTrue())
  803. return true
  804. }
  805. }
  806. // if target Secret name is not specified it should use the ExternalSecret name.
  807. syncMatchingLabels := func(tc *testCase) {
  808. fakeProvider.SetSecretFn = func() error {
  809. return nil
  810. }
  811. fakeProvider.DeleteSecretFn = func() error {
  812. return nil
  813. }
  814. tc.pushsecret = &v1alpha1.PushSecret{
  815. ObjectMeta: metav1.ObjectMeta{
  816. Name: PushSecretName,
  817. Namespace: PushSecretNamespace,
  818. },
  819. Spec: v1alpha1.PushSecretSpec{
  820. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  821. {
  822. LabelSelector: &metav1.LabelSelector{
  823. MatchLabels: map[string]string{
  824. "foo": "bar",
  825. },
  826. },
  827. Kind: "SecretStore",
  828. Name: PushSecretStore,
  829. },
  830. },
  831. Selector: v1alpha1.PushSecretSelector{
  832. Secret: &v1alpha1.PushSecretSecret{
  833. Name: SecretName,
  834. },
  835. },
  836. Data: []v1alpha1.PushSecretData{
  837. {
  838. Match: v1alpha1.PushSecretMatch{
  839. SecretKey: defaultKey,
  840. RemoteRef: v1alpha1.PushSecretRemoteRef{
  841. RemoteKey: defaultPath,
  842. },
  843. },
  844. },
  845. },
  846. },
  847. }
  848. tc.store = &esv1.SecretStore{
  849. TypeMeta: metav1.TypeMeta{
  850. Kind: "SecretStore",
  851. },
  852. ObjectMeta: metav1.ObjectMeta{
  853. Name: PushSecretStore,
  854. Namespace: PushSecretNamespace,
  855. Labels: map[string]string{
  856. "foo": "bar",
  857. },
  858. },
  859. Spec: esv1.SecretStoreSpec{
  860. Provider: &esv1.SecretStoreProvider{
  861. Fake: &esv1.FakeProvider{
  862. Data: []esv1.FakeProviderData{},
  863. },
  864. },
  865. },
  866. }
  867. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  868. secretValue := secret.Data[defaultKey]
  869. setSecretArgs := fakeProvider.GetPushSecretData()
  870. providerValue := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  871. expected := v1alpha1.PushSecretStatusCondition{
  872. Type: v1alpha1.PushSecretReady,
  873. Status: v1.ConditionTrue,
  874. Reason: v1alpha1.ReasonSynced,
  875. Message: "PushSecret synced successfully",
  876. }
  877. return bytes.Equal(secretValue, providerValue) && checkCondition(ps.Status, expected)
  878. }
  879. }
  880. syncWithClusterStore := func(tc *testCase) {
  881. fakeProvider.SetSecretFn = func() error {
  882. return nil
  883. }
  884. tc.store = &esv1.ClusterSecretStore{
  885. TypeMeta: metav1.TypeMeta{
  886. Kind: "ClusterSecretStore",
  887. },
  888. ObjectMeta: metav1.ObjectMeta{
  889. Name: PushSecretStore,
  890. },
  891. Spec: esv1.SecretStoreSpec{
  892. Provider: &esv1.SecretStoreProvider{
  893. Fake: &esv1.FakeProvider{
  894. Data: []esv1.FakeProviderData{},
  895. },
  896. },
  897. },
  898. }
  899. tc.pushsecret.Spec.SecretStoreRefs[0].Kind = "ClusterSecretStore"
  900. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  901. secretValue := secret.Data[defaultKey]
  902. setSecretArgs := fakeProvider.GetPushSecretData()
  903. providerValue := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  904. expected := v1alpha1.PushSecretStatusCondition{
  905. Type: v1alpha1.PushSecretReady,
  906. Status: v1.ConditionTrue,
  907. Reason: v1alpha1.ReasonSynced,
  908. Message: "PushSecret synced successfully",
  909. }
  910. return bytes.Equal(secretValue, providerValue) && checkCondition(ps.Status, expected)
  911. }
  912. }
  913. syncWithGenerator := func(tc *testCase) {
  914. fakeProvider.SetSecretFn = func() error {
  915. return nil
  916. }
  917. tc.pushsecret.Spec.Selector.Secret = nil
  918. tc.pushsecret.Spec.Selector.GeneratorRef = &esv1.GeneratorRef{
  919. APIVersion: "generators.external-secrets.io/v1alpha1",
  920. Kind: "Fake",
  921. Name: "test",
  922. }
  923. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  924. setSecretArgs := fakeProvider.GetPushSecretData()
  925. providerValue := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  926. expected := v1alpha1.PushSecretStatusCondition{
  927. Type: v1alpha1.PushSecretReady,
  928. Status: v1.ConditionTrue,
  929. Reason: v1alpha1.ReasonSynced,
  930. Message: "PushSecret synced successfully",
  931. }
  932. return bytes.Equal([]byte("foo-bar-from-generator"), providerValue) && checkCondition(ps.Status, expected)
  933. }
  934. }
  935. // if target Secret name is not specified it should use the ExternalSecret name.
  936. syncWithClusterStoreMatchingLabels := func(tc *testCase) {
  937. fakeProvider.SetSecretFn = func() error {
  938. return nil
  939. }
  940. tc.pushsecret = &v1alpha1.PushSecret{
  941. ObjectMeta: metav1.ObjectMeta{
  942. Name: PushSecretName,
  943. Namespace: PushSecretNamespace,
  944. },
  945. Spec: v1alpha1.PushSecretSpec{
  946. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  947. {
  948. LabelSelector: &metav1.LabelSelector{
  949. MatchLabels: map[string]string{
  950. "foo": "bar",
  951. },
  952. },
  953. Kind: "ClusterSecretStore",
  954. Name: PushSecretStore,
  955. },
  956. },
  957. Selector: v1alpha1.PushSecretSelector{
  958. Secret: &v1alpha1.PushSecretSecret{
  959. Name: SecretName,
  960. },
  961. },
  962. Data: []v1alpha1.PushSecretData{
  963. {
  964. Match: v1alpha1.PushSecretMatch{
  965. SecretKey: defaultKey,
  966. RemoteRef: v1alpha1.PushSecretRemoteRef{
  967. RemoteKey: defaultPath,
  968. },
  969. },
  970. },
  971. },
  972. },
  973. }
  974. tc.store = &esv1.ClusterSecretStore{
  975. ObjectMeta: metav1.ObjectMeta{
  976. Name: PushSecretStore,
  977. Labels: map[string]string{
  978. "foo": "bar",
  979. },
  980. },
  981. Spec: esv1.SecretStoreSpec{
  982. Provider: &esv1.SecretStoreProvider{
  983. Fake: &esv1.FakeProvider{
  984. Data: []esv1.FakeProviderData{},
  985. },
  986. },
  987. },
  988. }
  989. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  990. secretValue := secret.Data[defaultKey]
  991. setSecretArgs := fakeProvider.GetPushSecretData()
  992. providerValue := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  993. expected := v1alpha1.PushSecretStatusCondition{
  994. Type: v1alpha1.PushSecretReady,
  995. Status: v1.ConditionTrue,
  996. Reason: v1alpha1.ReasonSynced,
  997. Message: "PushSecret synced successfully",
  998. }
  999. return bytes.Equal(secretValue, providerValue) && checkCondition(ps.Status, expected)
  1000. }
  1001. }
  1002. // if target Secret name is not specified it should use the ExternalSecret name.
  1003. failNoSecret := func(tc *testCase) {
  1004. fakeProvider.SetSecretFn = func() error {
  1005. return nil
  1006. }
  1007. tc.secret = nil
  1008. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1009. expected := v1alpha1.PushSecretStatusCondition{
  1010. Type: v1alpha1.PushSecretReady,
  1011. Status: v1.ConditionFalse,
  1012. Reason: v1alpha1.ReasonErrored,
  1013. Message: "could not get source secret",
  1014. }
  1015. return checkCondition(ps.Status, expected)
  1016. }
  1017. }
  1018. // if target Secret name is not specified it should use the ExternalSecret name.
  1019. failNoSecretKey := func(tc *testCase) {
  1020. fakeProvider.SetSecretFn = func() error {
  1021. return nil
  1022. }
  1023. tc.pushsecret.Spec.Data[0].Match.SecretKey = "unexisting"
  1024. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1025. expected := v1alpha1.PushSecretStatusCondition{
  1026. Type: v1alpha1.PushSecretReady,
  1027. Status: v1.ConditionFalse,
  1028. Reason: v1alpha1.ReasonErrored,
  1029. Message: "set secret failed: secret key unexisting does not exist",
  1030. }
  1031. return checkCondition(ps.Status, expected)
  1032. }
  1033. }
  1034. // if target Secret name is not specified it should use the ExternalSecret name.
  1035. failNoSecretStore := func(tc *testCase) {
  1036. fakeProvider.SetSecretFn = func() error {
  1037. return nil
  1038. }
  1039. tc.store = nil
  1040. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1041. expected := v1alpha1.PushSecretStatusCondition{
  1042. Type: v1alpha1.PushSecretReady,
  1043. Status: v1.ConditionFalse,
  1044. Reason: v1alpha1.ReasonErrored,
  1045. Message: "could not get SecretStore \"test-store\", secretstores.external-secrets.io \"test-store\" not found",
  1046. }
  1047. return checkCondition(ps.Status, expected)
  1048. }
  1049. }
  1050. // if target Secret name is not specified it should use the ExternalSecret name.
  1051. failNoClusterStore := func(tc *testCase) {
  1052. fakeProvider.SetSecretFn = func() error {
  1053. return nil
  1054. }
  1055. tc.store = nil
  1056. tc.pushsecret.Spec.SecretStoreRefs[0].Kind = "ClusterSecretStore"
  1057. tc.pushsecret.Spec.SecretStoreRefs[0].Name = "unexisting"
  1058. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1059. expected := v1alpha1.PushSecretStatusCondition{
  1060. Type: v1alpha1.PushSecretReady,
  1061. Status: v1.ConditionFalse,
  1062. Reason: v1alpha1.ReasonErrored,
  1063. Message: "could not get ClusterSecretStore \"unexisting\", clustersecretstores.external-secrets.io \"unexisting\" not found",
  1064. }
  1065. return checkCondition(ps.Status, expected)
  1066. }
  1067. }
  1068. // if target Secret name is not specified it should use the ExternalSecret name.
  1069. setSecretFail := func(tc *testCase) {
  1070. fakeProvider.SetSecretFn = func() error {
  1071. return errors.New("boom")
  1072. }
  1073. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1074. expected := v1alpha1.PushSecretStatusCondition{
  1075. Type: v1alpha1.PushSecretReady,
  1076. Status: v1.ConditionFalse,
  1077. Reason: v1alpha1.ReasonErrored,
  1078. Message: "set secret failed: could not write remote ref key to target secretstore test-store: boom",
  1079. }
  1080. return checkCondition(ps.Status, expected)
  1081. }
  1082. }
  1083. // if target Secret name is not specified it should use the ExternalSecret name.
  1084. newClientFail := func(tc *testCase) {
  1085. fakeProvider.NewFn = func(context.Context, esv1.GenericStore, client.Client, string) (esv1.SecretsClient, error) {
  1086. return nil, errors.New("boom")
  1087. }
  1088. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1089. expected := v1alpha1.PushSecretStatusCondition{
  1090. Type: v1alpha1.PushSecretReady,
  1091. Status: v1.ConditionFalse,
  1092. Reason: v1alpha1.ReasonErrored,
  1093. Message: "set secret failed: could not get secrets client for store test-store: boom",
  1094. }
  1095. return checkCondition(ps.Status, expected)
  1096. }
  1097. }
  1098. // SecretStores in different namespace than PushSecret should not be selected.
  1099. secretStoreDifferentNamespace := func(tc *testCase) {
  1100. fakeProvider.SetSecretFn = func() error {
  1101. return nil
  1102. }
  1103. // Create the SecretStore in a different namespace
  1104. tc.store = &esv1.SecretStore{
  1105. ObjectMeta: metav1.ObjectMeta{
  1106. Name: "other-ns-store",
  1107. Namespace: OtherNamespace,
  1108. Labels: map[string]string{
  1109. "foo": "bar",
  1110. },
  1111. },
  1112. TypeMeta: metav1.TypeMeta{
  1113. Kind: "SecretStore",
  1114. },
  1115. Spec: esv1.SecretStoreSpec{
  1116. Provider: &esv1.SecretStoreProvider{
  1117. Fake: &esv1.FakeProvider{
  1118. Data: []esv1.FakeProviderData{},
  1119. },
  1120. },
  1121. },
  1122. }
  1123. // Use label selector to select SecretStores
  1124. tc.pushsecret.Spec.SecretStoreRefs = []v1alpha1.PushSecretStoreRef{
  1125. {
  1126. Kind: "SecretStore",
  1127. LabelSelector: &metav1.LabelSelector{
  1128. MatchLabels: map[string]string{
  1129. "foo": "bar",
  1130. },
  1131. },
  1132. },
  1133. }
  1134. // Should not select the SecretStore in a different namespace
  1135. // (if so, it would fail to find it in the same namespace and be reflected in the status)
  1136. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1137. // Assert that the status is never updated (no SecretStores found)
  1138. Consistently(func() bool {
  1139. err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(ps), ps)
  1140. if err != nil {
  1141. return false
  1142. }
  1143. return len(ps.Status.Conditions) == 0
  1144. }, timeout, interval).Should(BeTrue())
  1145. return true
  1146. }
  1147. }
  1148. // Secrets in different namespace than PushSecret should not be selected.
  1149. secretDifferentNamespace := func(tc *testCase) {
  1150. fakeProvider.SetSecretFn = func() error {
  1151. return nil
  1152. }
  1153. // Create the Secret in a different namespace
  1154. tc.secret = &v1.Secret{
  1155. ObjectMeta: metav1.ObjectMeta{
  1156. Name: SecretName,
  1157. Namespace: OtherNamespace,
  1158. Labels: map[string]string{
  1159. "foo": "bar",
  1160. },
  1161. },
  1162. Data: map[string][]byte{
  1163. defaultKey: []byte(defaultVal),
  1164. },
  1165. }
  1166. // Use label selector to select Secrets
  1167. tc.pushsecret.Spec.Selector.Secret = &v1alpha1.PushSecretSecret{
  1168. Selector: &metav1.LabelSelector{
  1169. MatchLabels: map[string]string{
  1170. "foo": "bar",
  1171. },
  1172. },
  1173. }
  1174. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1175. Eventually(func() bool {
  1176. // We should not be able to reference a secret across namespaces,
  1177. // the map should be empty.
  1178. Expect(fakeProvider.GetPushSecretData()).To(BeEmpty())
  1179. return true
  1180. }, time.Second*10, time.Second).Should(BeTrue())
  1181. return true
  1182. }
  1183. }
  1184. DescribeTable("When reconciling a PushSecret",
  1185. func(tweaks ...testTweaks) {
  1186. tc := makeDefaultTestcase()
  1187. for _, tweak := range tweaks {
  1188. tweak(tc)
  1189. }
  1190. ctx := context.Background()
  1191. By("creating a secret store, secret and pushsecret")
  1192. if tc.store != nil {
  1193. Expect(k8sClient.Create(ctx, tc.store)).To(Succeed())
  1194. }
  1195. if tc.secret != nil {
  1196. Expect(k8sClient.Create(ctx, tc.secret)).To(Succeed())
  1197. }
  1198. if tc.pushsecret != nil {
  1199. Expect(k8sClient.Create(ctx, tc.pushsecret)).Should(Succeed())
  1200. }
  1201. time.Sleep(2 * time.Second) // prevents race conditions during tests causing failures
  1202. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  1203. createdPS := &v1alpha1.PushSecret{}
  1204. By("checking the pushSecret condition")
  1205. Eventually(func() bool {
  1206. err := k8sClient.Get(ctx, psKey, createdPS)
  1207. if err != nil {
  1208. return false
  1209. }
  1210. return tc.assert(createdPS, tc.secret)
  1211. }, timeout, interval).Should(BeTrue())
  1212. // this must be optional so we can test faulty es configuration
  1213. },
  1214. Entry("should sync", syncSuccessfully),
  1215. Entry("should not update existing secret if UpdatePolicy=IfNotExists", updateIfNotExists),
  1216. Entry("should only update parts of secret that don't already exist if UpdatePolicy=IfNotExists", updateIfNotExistsPartialSecrets),
  1217. Entry("should update the PushSecret status correctly if UpdatePolicy=IfNotExists", updateIfNotExistsSyncStatus),
  1218. Entry("should fail if secret existence cannot be verified if UpdatePolicy=IfNotExists", updateIfNotExistsSyncFailed),
  1219. Entry("should sync with template", syncSuccessfullyWithTemplate),
  1220. Entry("should sync with template reusing keys", syncSuccessfullyReusingKeys),
  1221. Entry("should sync with conversion strategy", syncSuccessfullyWithConversionStrategy),
  1222. Entry("should delete if DeletionPolicy=Delete", syncAndDeleteSuccessfully),
  1223. Entry("should delete after DeletionPolicy changed from Delete to None", syncChangePolicyAndDeleteSuccessfully),
  1224. Entry("should track deletion tasks if Delete fails", failDelete),
  1225. Entry("should track deleted stores if Delete fails", failDeleteStore),
  1226. Entry("should delete all secrets if SecretStore changes", deleteWholeStore),
  1227. Entry("should sync to stores matching labels", syncMatchingLabels),
  1228. Entry("should sync with ClusterStore", syncWithClusterStore),
  1229. Entry("should sync with ClusterStore matching labels", syncWithClusterStoreMatchingLabels),
  1230. Entry("should sync with Generator", syncWithGenerator),
  1231. Entry("should fail if Secret is not created", failNoSecret),
  1232. Entry("should fail if Secret Key does not exist", failNoSecretKey),
  1233. Entry("should fail if SetSecret fails", setSecretFail),
  1234. Entry("should fail if no valid SecretStore", failNoSecretStore),
  1235. Entry("should fail if no valid ClusterSecretStore", failNoClusterStore),
  1236. Entry("should fail if NewClient fails", newClientFail),
  1237. Entry("should not sync to SecretStore in different namespace", secretStoreDifferentNamespace),
  1238. Entry("should not reference secret in different namespace", secretDifferentNamespace),
  1239. )
  1240. })
  1241. var _ = Describe("PushSecret Controller Un/Managed Stores", func() {
  1242. const (
  1243. PushSecretName = "test-ps"
  1244. ManagedPushSecretStore1 = "test-managed-store-1"
  1245. ManagedPushSecretStore2 = "test-managed-store-2"
  1246. UnmanagedPushSecretStore1 = "test-unmanaged-store-1"
  1247. UnmanagedPushSecretStore2 = "test-unmanaged-store-2"
  1248. SecretName = "test-secret"
  1249. )
  1250. var PushSecretNamespace string
  1251. PushSecretStores := []string{ManagedPushSecretStore1, ManagedPushSecretStore2, UnmanagedPushSecretStore1, UnmanagedPushSecretStore2}
  1252. // if we are in debug and need to increase the timeout for testing, we can do so by using an env var
  1253. if customTimeout := os.Getenv("TEST_CUSTOM_TIMEOUT_SEC"); customTimeout != "" {
  1254. if t, err := strconv.Atoi(customTimeout); err == nil {
  1255. timeout = time.Second * time.Duration(t)
  1256. }
  1257. }
  1258. BeforeEach(func() {
  1259. var err error
  1260. PushSecretNamespace, err = ctest.CreateNamespace("test-ns", k8sClient)
  1261. Expect(err).ToNot(HaveOccurred())
  1262. fakeProvider.Reset()
  1263. })
  1264. AfterEach(func() {
  1265. k8sClient.Delete(context.Background(), &v1alpha1.PushSecret{
  1266. ObjectMeta: metav1.ObjectMeta{
  1267. Name: PushSecretName,
  1268. Namespace: PushSecretNamespace,
  1269. },
  1270. })
  1271. // give a time for reconciler to remove finalizers before removing SecretStores
  1272. time.Sleep(2 * time.Second)
  1273. for _, psstore := range PushSecretStores {
  1274. k8sClient.Delete(context.Background(), &esv1.SecretStore{
  1275. ObjectMeta: metav1.ObjectMeta{
  1276. Name: psstore,
  1277. Namespace: PushSecretNamespace,
  1278. },
  1279. })
  1280. k8sClient.Delete(context.Background(), &esv1.ClusterSecretStore{
  1281. ObjectMeta: metav1.ObjectMeta{
  1282. Name: psstore,
  1283. },
  1284. })
  1285. }
  1286. k8sClient.Delete(context.Background(), &v1.Secret{
  1287. ObjectMeta: metav1.ObjectMeta{
  1288. Name: SecretName,
  1289. Namespace: PushSecretNamespace,
  1290. },
  1291. })
  1292. Expect(k8sClient.Delete(context.Background(), &v1.Namespace{
  1293. ObjectMeta: metav1.ObjectMeta{
  1294. Name: PushSecretNamespace,
  1295. },
  1296. })).To(Succeed())
  1297. })
  1298. const (
  1299. defaultKey = "key"
  1300. defaultVal = "value"
  1301. defaultPath = "path/to/key"
  1302. )
  1303. makeDefaultTestcase := func() *testCase {
  1304. return &testCase{
  1305. pushsecret: &v1alpha1.PushSecret{
  1306. ObjectMeta: metav1.ObjectMeta{
  1307. Name: PushSecretName,
  1308. Namespace: PushSecretNamespace,
  1309. },
  1310. Spec: v1alpha1.PushSecretSpec{
  1311. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  1312. {
  1313. Name: ManagedPushSecretStore1,
  1314. Kind: "SecretStore",
  1315. },
  1316. },
  1317. Selector: v1alpha1.PushSecretSelector{
  1318. Secret: &v1alpha1.PushSecretSecret{
  1319. Name: SecretName,
  1320. },
  1321. },
  1322. Data: []v1alpha1.PushSecretData{
  1323. {
  1324. Match: v1alpha1.PushSecretMatch{
  1325. SecretKey: defaultKey,
  1326. RemoteRef: v1alpha1.PushSecretRemoteRef{
  1327. RemoteKey: defaultPath,
  1328. },
  1329. },
  1330. },
  1331. },
  1332. },
  1333. },
  1334. secret: &v1.Secret{
  1335. ObjectMeta: metav1.ObjectMeta{
  1336. Name: SecretName,
  1337. Namespace: PushSecretNamespace,
  1338. },
  1339. Data: map[string][]byte{
  1340. defaultKey: []byte(defaultVal),
  1341. },
  1342. },
  1343. managedStore1: &esv1.SecretStore{
  1344. ObjectMeta: metav1.ObjectMeta{
  1345. Name: ManagedPushSecretStore1,
  1346. Namespace: PushSecretNamespace,
  1347. },
  1348. TypeMeta: metav1.TypeMeta{
  1349. Kind: "SecretStore",
  1350. },
  1351. Spec: esv1.SecretStoreSpec{
  1352. Provider: &esv1.SecretStoreProvider{
  1353. Fake: &esv1.FakeProvider{
  1354. Data: []esv1.FakeProviderData{},
  1355. },
  1356. },
  1357. },
  1358. },
  1359. managedStore2: &esv1.SecretStore{
  1360. ObjectMeta: metav1.ObjectMeta{
  1361. Name: ManagedPushSecretStore2,
  1362. Namespace: PushSecretNamespace,
  1363. },
  1364. TypeMeta: metav1.TypeMeta{
  1365. Kind: "SecretStore",
  1366. },
  1367. Spec: esv1.SecretStoreSpec{
  1368. Provider: &esv1.SecretStoreProvider{
  1369. Fake: &esv1.FakeProvider{
  1370. Data: []esv1.FakeProviderData{},
  1371. },
  1372. },
  1373. },
  1374. },
  1375. unmanagedStore1: &esv1.SecretStore{
  1376. ObjectMeta: metav1.ObjectMeta{
  1377. Name: UnmanagedPushSecretStore1,
  1378. Namespace: PushSecretNamespace,
  1379. },
  1380. TypeMeta: metav1.TypeMeta{
  1381. Kind: "SecretStore",
  1382. },
  1383. Spec: esv1.SecretStoreSpec{
  1384. Provider: &esv1.SecretStoreProvider{
  1385. Fake: &esv1.FakeProvider{
  1386. Data: []esv1.FakeProviderData{},
  1387. },
  1388. },
  1389. Controller: "not-managed",
  1390. },
  1391. },
  1392. unmanagedStore2: &esv1.SecretStore{
  1393. ObjectMeta: metav1.ObjectMeta{
  1394. Name: UnmanagedPushSecretStore2,
  1395. Namespace: PushSecretNamespace,
  1396. },
  1397. TypeMeta: metav1.TypeMeta{
  1398. Kind: "SecretStore",
  1399. },
  1400. Spec: esv1.SecretStoreSpec{
  1401. Provider: &esv1.SecretStoreProvider{
  1402. Fake: &esv1.FakeProvider{
  1403. Data: []esv1.FakeProviderData{},
  1404. },
  1405. },
  1406. Controller: "not-managed",
  1407. },
  1408. },
  1409. }
  1410. }
  1411. multipleManagedStoresSyncsSuccessfully := func(tc *testCase) {
  1412. fakeProvider.SetSecretFn = func() error {
  1413. return nil
  1414. }
  1415. tc.pushsecret.Spec.SecretStoreRefs = append(tc.pushsecret.Spec.SecretStoreRefs,
  1416. v1alpha1.PushSecretStoreRef{
  1417. Name: ManagedPushSecretStore2,
  1418. Kind: "SecretStore",
  1419. },
  1420. )
  1421. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1422. Eventually(func() bool {
  1423. By("checking if Provider value got updated")
  1424. secretValue := secret.Data[defaultKey]
  1425. setSecretArgs := fakeProvider.GetPushSecretData()
  1426. providerValue, ok := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  1427. if !ok {
  1428. return false
  1429. }
  1430. got := providerValue.Value
  1431. return bytes.Equal(got, secretValue)
  1432. }, time.Second*10, time.Second).Should(BeTrue())
  1433. return true
  1434. }
  1435. }
  1436. skipUnmanagedStores := func(tc *testCase) {
  1437. tc.pushsecret.Spec.SecretStoreRefs = []v1alpha1.PushSecretStoreRef{
  1438. {
  1439. Name: UnmanagedPushSecretStore1,
  1440. Kind: "SecretStore",
  1441. },
  1442. {
  1443. Name: UnmanagedPushSecretStore2,
  1444. Kind: "SecretStore",
  1445. },
  1446. }
  1447. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1448. return len(ps.Status.Conditions) == 0
  1449. }
  1450. }
  1451. warnUnmanagedStoresAndSyncManagedStores := func(tc *testCase) {
  1452. fakeProvider.SetSecretFn = func() error {
  1453. return nil
  1454. }
  1455. tc.pushsecret.Spec.SecretStoreRefs = []v1alpha1.PushSecretStoreRef{
  1456. {
  1457. Name: ManagedPushSecretStore1,
  1458. Kind: "SecretStore",
  1459. },
  1460. {
  1461. Name: ManagedPushSecretStore2,
  1462. Kind: "SecretStore",
  1463. },
  1464. {
  1465. Name: UnmanagedPushSecretStore1,
  1466. Kind: "SecretStore",
  1467. },
  1468. {
  1469. Name: UnmanagedPushSecretStore2,
  1470. Kind: "SecretStore",
  1471. },
  1472. }
  1473. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1474. Eventually(func() bool {
  1475. By("checking if Provider value got updated")
  1476. secretValue := secret.Data[defaultKey]
  1477. setSecretArgs := fakeProvider.GetPushSecretData()
  1478. providerValue, ok := setSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  1479. if !ok {
  1480. return false
  1481. }
  1482. got := providerValue.Value
  1483. return bytes.Equal(got, secretValue)
  1484. }, time.Second*10, time.Second).Should(BeTrue())
  1485. return true
  1486. }
  1487. }
  1488. DescribeTable("When reconciling a PushSecret with multiple secret stores",
  1489. func(tweaks ...testTweaks) {
  1490. tc := makeDefaultTestcase()
  1491. for _, tweak := range tweaks {
  1492. tweak(tc)
  1493. }
  1494. ctx := context.Background()
  1495. By("creating secret stores, a secret and a pushsecret")
  1496. if tc.managedStore1 != nil {
  1497. Expect(k8sClient.Create(ctx, tc.managedStore1)).To(Succeed())
  1498. }
  1499. if tc.managedStore2 != nil {
  1500. Expect(k8sClient.Create(ctx, tc.managedStore2)).To(Succeed())
  1501. }
  1502. if tc.unmanagedStore1 != nil {
  1503. Expect(k8sClient.Create(ctx, tc.unmanagedStore1)).To(Succeed())
  1504. }
  1505. if tc.unmanagedStore2 != nil {
  1506. Expect(k8sClient.Create(ctx, tc.unmanagedStore2)).To(Succeed())
  1507. }
  1508. if tc.secret != nil {
  1509. Expect(k8sClient.Create(ctx, tc.secret)).To(Succeed())
  1510. }
  1511. if tc.pushsecret != nil {
  1512. Expect(k8sClient.Create(ctx, tc.pushsecret)).Should(Succeed())
  1513. }
  1514. time.Sleep(2 * time.Second) // prevents race conditions during tests causing failures
  1515. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  1516. createdPS := &v1alpha1.PushSecret{}
  1517. By("checking the pushSecret condition")
  1518. Eventually(func() bool {
  1519. err := k8sClient.Get(ctx, psKey, createdPS)
  1520. if err != nil {
  1521. return false
  1522. }
  1523. return tc.assert(createdPS, tc.secret)
  1524. }, timeout, interval).Should(BeTrue())
  1525. // this must be optional so we can test faulty es configuration
  1526. },
  1527. Entry("should sync successfully if there are multiple managed stores", multipleManagedStoresSyncsSuccessfully),
  1528. Entry("should skip unmanaged stores", skipUnmanagedStores),
  1529. Entry("should skip unmanaged stores and sync managed stores", warnUnmanagedStoresAndSyncManagedStores),
  1530. )
  1531. })