pushsecret_controller_test.go 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430
  1. /*
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. package pushsecret
  13. import (
  14. "bytes"
  15. "context"
  16. "errors"
  17. "fmt"
  18. "os"
  19. "strconv"
  20. "time"
  21. v1 "k8s.io/api/core/v1"
  22. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  23. "k8s.io/apimachinery/pkg/types"
  24. "sigs.k8s.io/controller-runtime/pkg/client"
  25. "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
  26. "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  27. genv1alpha1 "github.com/external-secrets/external-secrets/apis/generators/v1alpha1"
  28. ctest "github.com/external-secrets/external-secrets/pkg/controllers/commontest"
  29. "github.com/external-secrets/external-secrets/pkg/controllers/pushsecret/psmetrics"
  30. "github.com/external-secrets/external-secrets/pkg/provider/testing/fake"
  31. . "github.com/onsi/ginkgo/v2"
  32. . "github.com/onsi/gomega"
  33. )
  34. var (
  35. fakeProvider *fake.Client
  36. timeout = time.Second * 10
  37. interval = time.Millisecond * 250
  38. )
  39. type testCase struct {
  40. store v1beta1.GenericStore
  41. managedStore1 v1beta1.GenericStore
  42. managedStore2 v1beta1.GenericStore
  43. unmanagedStore1 v1beta1.GenericStore
  44. unmanagedStore2 v1beta1.GenericStore
  45. pushsecret *v1alpha1.PushSecret
  46. secret *v1.Secret
  47. assert func(pushsecret *v1alpha1.PushSecret, secret *v1.Secret) bool
  48. }
  49. func init() {
  50. fakeProvider = fake.New()
  51. v1beta1.ForceRegister(fakeProvider, &v1beta1.SecretStoreProvider{
  52. Fake: &v1beta1.FakeProvider{},
  53. })
  54. psmetrics.SetUpMetrics()
  55. }
  56. func checkCondition(status v1alpha1.PushSecretStatus, cond v1alpha1.PushSecretStatusCondition) bool {
  57. fmt.Printf("status: %+v\ncond: %+v\n", status.Conditions, cond)
  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 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. fakeProvider.Reset()
  87. Expect(k8sClient.Create(context.Background(), &genv1alpha1.Fake{
  88. TypeMeta: metav1.TypeMeta{
  89. Kind: "Fake",
  90. APIVersion: "generators.external-secrets.io/v1alpha1",
  91. },
  92. ObjectMeta: metav1.ObjectMeta{
  93. Name: "test",
  94. Namespace: PushSecretNamespace,
  95. },
  96. Spec: genv1alpha1.FakeSpec{
  97. Data: map[string]string{
  98. "key": "foo-bar-from-generator",
  99. },
  100. }})).ToNot(HaveOccurred())
  101. })
  102. AfterEach(func() {
  103. k8sClient.Delete(context.Background(), &v1alpha1.PushSecret{
  104. ObjectMeta: metav1.ObjectMeta{
  105. Name: PushSecretName,
  106. Namespace: PushSecretNamespace,
  107. },
  108. })
  109. // give a time for reconciler to remove finalizers before removing SecretStores
  110. // TODO: Secret Stores should have finalizers bound to PushSecrets if DeletionPolicy == Delete
  111. time.Sleep(2 * time.Second)
  112. k8sClient.Delete(context.Background(), &v1beta1.SecretStore{
  113. ObjectMeta: metav1.ObjectMeta{
  114. Name: PushSecretStore,
  115. Namespace: PushSecretNamespace,
  116. },
  117. })
  118. k8sClient.Delete(context.Background(), &v1beta1.ClusterSecretStore{
  119. ObjectMeta: metav1.ObjectMeta{
  120. Name: PushSecretStore,
  121. },
  122. })
  123. k8sClient.Delete(context.Background(), &v1.Secret{
  124. ObjectMeta: metav1.ObjectMeta{
  125. Name: SecretName,
  126. Namespace: PushSecretNamespace,
  127. },
  128. })
  129. Expect(k8sClient.Delete(context.Background(), &v1.Namespace{
  130. ObjectMeta: metav1.ObjectMeta{
  131. Name: PushSecretNamespace,
  132. },
  133. })).To(Succeed())
  134. })
  135. const (
  136. defaultKey = "key"
  137. defaultVal = "value"
  138. defaultPath = "path/to/key"
  139. otherKey = "other-key"
  140. otherVal = "other-value"
  141. otherPath = "path/to/other-key"
  142. newKey = "new-key"
  143. newVal = "new-value"
  144. storePrefixTemplate = "SecretStore/%v"
  145. )
  146. makeDefaultTestcase := func() *testCase {
  147. return &testCase{
  148. pushsecret: &v1alpha1.PushSecret{
  149. ObjectMeta: metav1.ObjectMeta{
  150. Name: PushSecretName,
  151. Namespace: PushSecretNamespace,
  152. },
  153. Spec: v1alpha1.PushSecretSpec{
  154. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  155. {
  156. Name: PushSecretStore,
  157. Kind: "SecretStore",
  158. },
  159. },
  160. Selector: v1alpha1.PushSecretSelector{
  161. Secret: &v1alpha1.PushSecretSecret{
  162. Name: SecretName,
  163. },
  164. },
  165. Data: []v1alpha1.PushSecretData{
  166. {
  167. Match: v1alpha1.PushSecretMatch{
  168. SecretKey: defaultKey,
  169. RemoteRef: v1alpha1.PushSecretRemoteRef{
  170. RemoteKey: defaultPath,
  171. },
  172. },
  173. },
  174. },
  175. },
  176. },
  177. secret: &v1.Secret{
  178. ObjectMeta: metav1.ObjectMeta{
  179. Name: SecretName,
  180. Namespace: PushSecretNamespace,
  181. },
  182. Data: map[string][]byte{
  183. defaultKey: []byte(defaultVal),
  184. },
  185. },
  186. store: &v1beta1.SecretStore{
  187. ObjectMeta: metav1.ObjectMeta{
  188. Name: PushSecretStore,
  189. Namespace: PushSecretNamespace,
  190. },
  191. TypeMeta: metav1.TypeMeta{
  192. Kind: "SecretStore",
  193. },
  194. Spec: v1beta1.SecretStoreSpec{
  195. Provider: &v1beta1.SecretStoreProvider{
  196. Fake: &v1beta1.FakeProvider{
  197. Data: []v1beta1.FakeProviderData{},
  198. },
  199. },
  200. },
  201. },
  202. }
  203. }
  204. // if target Secret name is not specified it should use the ExternalSecret name.
  205. syncSuccessfully := func(tc *testCase) {
  206. fakeProvider.SetSecretFn = func() error {
  207. return nil
  208. }
  209. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  210. Eventually(func() bool {
  211. By("checking if Provider value got updated")
  212. secretValue := secret.Data[defaultKey]
  213. providerValue, ok := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  214. if !ok {
  215. return false
  216. }
  217. got := providerValue.Value
  218. return bytes.Equal(got, secretValue)
  219. }, time.Second*10, time.Second).Should(BeTrue())
  220. return true
  221. }
  222. }
  223. updateIfNotExists := func(tc *testCase) {
  224. fakeProvider.SetSecretFn = func() error {
  225. return nil
  226. }
  227. fakeProvider.SecretExistsFn = func(ctx context.Context, ref v1beta1.PushSecretRemoteRef) (bool, error) {
  228. _, ok := fakeProvider.SetSecretArgs[ref.GetRemoteKey()]
  229. return ok, nil
  230. }
  231. tc.pushsecret.Spec.UpdatePolicy = v1alpha1.PushSecretUpdatePolicyIfNotExists
  232. initialValue := fakeProvider.SetSecretArgs[tc.pushsecret.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  233. tc.secret.Data[defaultKey] = []byte(newVal)
  234. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  235. Eventually(func() bool {
  236. By("checking if Provider value did not get updated")
  237. Expect(k8sClient.Update(context.Background(), secret, &client.UpdateOptions{})).Should(Succeed())
  238. providerValue, ok := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  239. if !ok {
  240. return false
  241. }
  242. got := providerValue.Value
  243. return bytes.Equal(got, initialValue)
  244. }, time.Second*10, time.Second).Should(BeTrue())
  245. return true
  246. }
  247. }
  248. updateIfNotExistsPartialSecrets := func(tc *testCase) {
  249. fakeProvider.SetSecretFn = func() error {
  250. return nil
  251. }
  252. fakeProvider.SecretExistsFn = func(ctx context.Context, ref v1beta1.PushSecretRemoteRef) (bool, error) {
  253. _, ok := fakeProvider.SetSecretArgs[ref.GetRemoteKey()]
  254. return ok, nil
  255. }
  256. tc.pushsecret.Spec.UpdatePolicy = v1alpha1.PushSecretUpdatePolicyIfNotExists
  257. tc.pushsecret.Spec.Data = append(tc.pushsecret.Spec.Data, v1alpha1.PushSecretData{
  258. Match: v1alpha1.PushSecretMatch{
  259. SecretKey: otherKey,
  260. RemoteRef: v1alpha1.PushSecretRemoteRef{
  261. RemoteKey: otherPath,
  262. },
  263. },
  264. })
  265. initialValue := fakeProvider.SetSecretArgs[tc.pushsecret.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  266. tc.secret.Data[defaultKey] = []byte(newVal) // change initial value in secret
  267. tc.secret.Data[otherKey] = []byte(otherVal)
  268. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  269. Eventually(func() bool {
  270. By("checking if only not existing Provider value got updated")
  271. Expect(k8sClient.Update(context.Background(), secret, &client.UpdateOptions{})).Should(Succeed())
  272. providerValue, ok := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  273. if !ok {
  274. return false
  275. }
  276. got := providerValue.Value
  277. otherProviderValue, ok := fakeProvider.SetSecretArgs[ps.Spec.Data[1].Match.RemoteRef.RemoteKey]
  278. if !ok {
  279. return false
  280. }
  281. gotOther := otherProviderValue.Value
  282. return bytes.Equal(gotOther, tc.secret.Data[otherKey]) && bytes.Equal(got, initialValue)
  283. }, time.Second*10, time.Second).Should(BeTrue())
  284. return true
  285. }
  286. }
  287. updateIfNotExistsSyncStatus := func(tc *testCase) {
  288. fakeProvider.SetSecretFn = func() error {
  289. return nil
  290. }
  291. fakeProvider.SecretExistsFn = func(ctx context.Context, ref v1beta1.PushSecretRemoteRef) (bool, error) {
  292. _, ok := fakeProvider.SetSecretArgs[ref.GetRemoteKey()]
  293. return ok, nil
  294. }
  295. tc.pushsecret.Spec.UpdatePolicy = v1alpha1.PushSecretUpdatePolicyIfNotExists
  296. tc.pushsecret.Spec.Data = append(tc.pushsecret.Spec.Data, v1alpha1.PushSecretData{
  297. Match: v1alpha1.PushSecretMatch{
  298. SecretKey: otherKey,
  299. RemoteRef: v1alpha1.PushSecretRemoteRef{
  300. RemoteKey: otherPath,
  301. },
  302. },
  303. })
  304. tc.secret.Data[defaultKey] = []byte(newVal)
  305. tc.secret.Data[otherKey] = []byte(otherVal)
  306. updatedPS := &v1alpha1.PushSecret{}
  307. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  308. Eventually(func() bool {
  309. By("checking if PushSecret status gets updated correctly with UpdatePolicy=IfNotExists")
  310. Expect(k8sClient.Update(context.Background(), secret, &client.UpdateOptions{})).Should(Succeed())
  311. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  312. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  313. if err != nil {
  314. return false
  315. }
  316. _, ok := updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][defaultPath]
  317. if !ok {
  318. return false
  319. }
  320. _, ok = updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][otherPath]
  321. if !ok {
  322. return false
  323. }
  324. expected := v1alpha1.PushSecretStatusCondition{
  325. Type: v1alpha1.PushSecretReady,
  326. Status: v1.ConditionTrue,
  327. Reason: v1alpha1.ReasonSynced,
  328. Message: "PushSecret synced successfully. Existing secrets in providers unchanged.",
  329. }
  330. return checkCondition(ps.Status, expected)
  331. }, time.Second*10, time.Second).Should(BeTrue())
  332. return true
  333. }
  334. }
  335. updateIfNotExistsSyncFailed := func(tc *testCase) {
  336. fakeProvider.SetSecretFn = func() error {
  337. return nil
  338. }
  339. fakeProvider.SecretExistsFn = func(ctx context.Context, ref v1beta1.PushSecretRemoteRef) (bool, error) {
  340. return false, errors.New("don't know")
  341. }
  342. tc.pushsecret.Spec.UpdatePolicy = v1alpha1.PushSecretUpdatePolicyIfNotExists
  343. initialValue := fakeProvider.SetSecretArgs[tc.pushsecret.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  344. tc.secret.Data[defaultKey] = []byte(newVal)
  345. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  346. Eventually(func() bool {
  347. By("checking if sync failed if secret existence cannot be verified in Provider")
  348. providerValue, ok := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  349. if !ok {
  350. return false
  351. }
  352. got := providerValue.Value
  353. expected := v1alpha1.PushSecretStatusCondition{
  354. Type: v1alpha1.PushSecretReady,
  355. Status: v1.ConditionFalse,
  356. Reason: v1alpha1.ReasonErrored,
  357. Message: "set secret failed: could not verify if secret exists in store: don't know",
  358. }
  359. return checkCondition(ps.Status, expected) && bytes.Equal(got, initialValue)
  360. }, time.Second*10, time.Second).Should(BeTrue())
  361. return true
  362. }
  363. }
  364. // if target Secret name is not specified it should use the ExternalSecret name.
  365. syncSuccessfullyWithTemplate := func(tc *testCase) {
  366. fakeProvider.SetSecretFn = func() error {
  367. return nil
  368. }
  369. tc.pushsecret = &v1alpha1.PushSecret{
  370. ObjectMeta: metav1.ObjectMeta{
  371. Name: PushSecretName,
  372. Namespace: PushSecretNamespace,
  373. },
  374. Spec: v1alpha1.PushSecretSpec{
  375. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  376. {
  377. Name: PushSecretStore,
  378. Kind: "SecretStore",
  379. },
  380. },
  381. Selector: v1alpha1.PushSecretSelector{
  382. Secret: &v1alpha1.PushSecretSecret{
  383. Name: SecretName,
  384. },
  385. },
  386. Data: []v1alpha1.PushSecretData{
  387. {
  388. Match: v1alpha1.PushSecretMatch{
  389. SecretKey: defaultKey,
  390. RemoteRef: v1alpha1.PushSecretRemoteRef{
  391. RemoteKey: defaultPath,
  392. },
  393. },
  394. },
  395. },
  396. Template: &v1beta1.ExternalSecretTemplate{
  397. Metadata: v1beta1.ExternalSecretTemplateMetadata{
  398. Labels: map[string]string{
  399. "foos": "ball",
  400. },
  401. Annotations: map[string]string{
  402. "hihi": "ga",
  403. },
  404. },
  405. Type: v1.SecretTypeOpaque,
  406. EngineVersion: v1beta1.TemplateEngineV2,
  407. Data: map[string]string{
  408. defaultKey: "{{ .key | toString | upper }} was 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. providerValue, ok := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  417. if !ok {
  418. return false
  419. }
  420. got := providerValue.Value
  421. return bytes.Equal(got, []byte("VALUE was templated"))
  422. }, time.Second*10, time.Second).Should(BeTrue())
  423. return true
  424. }
  425. }
  426. // if target Secret name is not specified it should use the ExternalSecret name.
  427. syncAndDeleteSuccessfully := func(tc *testCase) {
  428. fakeProvider.SetSecretFn = func() error {
  429. return nil
  430. }
  431. tc.pushsecret = &v1alpha1.PushSecret{
  432. ObjectMeta: metav1.ObjectMeta{
  433. Name: PushSecretName,
  434. Namespace: PushSecretNamespace,
  435. },
  436. Spec: v1alpha1.PushSecretSpec{
  437. DeletionPolicy: v1alpha1.PushSecretDeletionPolicyDelete,
  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. },
  460. }
  461. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  462. ps.Spec.Data[0].Match.RemoteRef.RemoteKey = newKey
  463. updatedPS := &v1alpha1.PushSecret{}
  464. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  465. Eventually(func() bool {
  466. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  467. By("checking if Provider value got updated")
  468. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  469. if err != nil {
  470. return false
  471. }
  472. key, ok := updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][newKey]
  473. if !ok {
  474. return false
  475. }
  476. return key.Match.SecretKey == defaultKey
  477. }, time.Second*10, time.Second).Should(BeTrue())
  478. return true
  479. }
  480. }
  481. // if PushSecret's DeletionPolicy is cleared, it should delete successfully
  482. syncChangePolicyAndDeleteSuccessfully := func(tc *testCase) {
  483. fakeProvider.SetSecretFn = func() error {
  484. return nil
  485. }
  486. tc.pushsecret = &v1alpha1.PushSecret{
  487. ObjectMeta: metav1.ObjectMeta{
  488. Name: PushSecretName,
  489. Namespace: PushSecretNamespace,
  490. },
  491. Spec: v1alpha1.PushSecretSpec{
  492. DeletionPolicy: v1alpha1.PushSecretDeletionPolicyDelete,
  493. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  494. {
  495. Name: PushSecretStore,
  496. Kind: "SecretStore",
  497. },
  498. },
  499. Selector: v1alpha1.PushSecretSelector{
  500. Secret: &v1alpha1.PushSecretSecret{
  501. Name: SecretName,
  502. },
  503. },
  504. Data: []v1alpha1.PushSecretData{
  505. {
  506. Match: v1alpha1.PushSecretMatch{
  507. SecretKey: defaultKey,
  508. RemoteRef: v1alpha1.PushSecretRemoteRef{
  509. RemoteKey: defaultPath,
  510. },
  511. },
  512. },
  513. },
  514. },
  515. }
  516. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  517. ps.Spec.DeletionPolicy = v1alpha1.PushSecretDeletionPolicyNone
  518. updatedPS := &v1alpha1.PushSecret{}
  519. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  520. Expect(k8sClient.Delete(context.Background(), ps, &client.DeleteOptions{})).Should(Succeed())
  521. Eventually(func() bool {
  522. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  523. By("checking if Get PushSecret returns not found")
  524. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  525. if err != nil && client.IgnoreNotFound(err) == nil {
  526. return true
  527. }
  528. return false
  529. }, time.Second*10, time.Second).Should(BeTrue())
  530. return true
  531. }
  532. }
  533. failDelete := func(tc *testCase) {
  534. fakeProvider.SetSecretFn = func() error {
  535. return nil
  536. }
  537. fakeProvider.DeleteSecretFn = func() error {
  538. return errors.New("Nope")
  539. }
  540. tc.pushsecret = &v1alpha1.PushSecret{
  541. ObjectMeta: metav1.ObjectMeta{
  542. Name: PushSecretName,
  543. Namespace: PushSecretNamespace,
  544. },
  545. Spec: v1alpha1.PushSecretSpec{
  546. DeletionPolicy: v1alpha1.PushSecretDeletionPolicyDelete,
  547. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  548. {
  549. Name: PushSecretStore,
  550. Kind: "SecretStore",
  551. },
  552. },
  553. Selector: v1alpha1.PushSecretSelector{
  554. Secret: &v1alpha1.PushSecretSecret{
  555. Name: SecretName,
  556. },
  557. },
  558. Data: []v1alpha1.PushSecretData{
  559. {
  560. Match: v1alpha1.PushSecretMatch{
  561. SecretKey: defaultKey,
  562. RemoteRef: v1alpha1.PushSecretRemoteRef{
  563. RemoteKey: defaultPath,
  564. },
  565. },
  566. },
  567. },
  568. },
  569. }
  570. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  571. ps.Spec.Data[0].Match.RemoteRef.RemoteKey = newKey
  572. updatedPS := &v1alpha1.PushSecret{}
  573. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  574. Eventually(func() bool {
  575. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  576. By("checking if synced secrets correspond to both keys")
  577. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  578. if err != nil {
  579. return false
  580. }
  581. _, ok := updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][newKey]
  582. if !ok {
  583. return false
  584. }
  585. _, ok = updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][defaultPath]
  586. return ok
  587. }, time.Second*10, time.Second).Should(BeTrue())
  588. return true
  589. }
  590. }
  591. failDeleteStore := func(tc *testCase) {
  592. fakeProvider.SetSecretFn = func() error {
  593. return nil
  594. }
  595. fakeProvider.DeleteSecretFn = func() error {
  596. return errors.New("boom")
  597. }
  598. tc.pushsecret.Spec.DeletionPolicy = v1alpha1.PushSecretDeletionPolicyDelete
  599. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  600. secondStore := &v1beta1.SecretStore{
  601. ObjectMeta: metav1.ObjectMeta{
  602. Name: "new-store",
  603. Namespace: PushSecretNamespace,
  604. },
  605. TypeMeta: metav1.TypeMeta{
  606. Kind: "SecretStore",
  607. },
  608. Spec: v1beta1.SecretStoreSpec{
  609. Provider: &v1beta1.SecretStoreProvider{
  610. Fake: &v1beta1.FakeProvider{
  611. Data: []v1beta1.FakeProviderData{},
  612. },
  613. },
  614. },
  615. }
  616. Expect(k8sClient.Create(context.Background(), secondStore, &client.CreateOptions{})).Should(Succeed())
  617. ps.Spec.SecretStoreRefs[0].Name = "new-store"
  618. updatedPS := &v1alpha1.PushSecret{}
  619. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  620. Eventually(func() bool {
  621. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  622. By("checking if Provider value got updated")
  623. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  624. if err != nil {
  625. return false
  626. }
  627. syncedLen := len(updatedPS.Status.SyncedPushSecrets)
  628. return syncedLen == 2
  629. }, time.Second*10, time.Second).Should(BeTrue())
  630. return true
  631. }
  632. }
  633. deleteWholeStore := func(tc *testCase) {
  634. fakeProvider.SetSecretFn = func() error {
  635. return nil
  636. }
  637. fakeProvider.DeleteSecretFn = func() error {
  638. return nil
  639. }
  640. tc.pushsecret.Spec.DeletionPolicy = v1alpha1.PushSecretDeletionPolicyDelete
  641. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  642. secondStore := &v1beta1.SecretStore{
  643. ObjectMeta: metav1.ObjectMeta{
  644. Name: "new-store",
  645. Namespace: PushSecretNamespace,
  646. },
  647. TypeMeta: metav1.TypeMeta{
  648. Kind: "SecretStore",
  649. },
  650. Spec: v1beta1.SecretStoreSpec{
  651. Provider: &v1beta1.SecretStoreProvider{
  652. Fake: &v1beta1.FakeProvider{
  653. Data: []v1beta1.FakeProviderData{},
  654. },
  655. },
  656. },
  657. }
  658. Expect(k8sClient.Create(context.Background(), secondStore, &client.CreateOptions{})).Should(Succeed())
  659. ps.Spec.SecretStoreRefs[0].Name = "new-store"
  660. updatedPS := &v1alpha1.PushSecret{}
  661. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  662. Eventually(func() bool {
  663. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  664. By("checking if Provider value got updated")
  665. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  666. if err != nil {
  667. return false
  668. }
  669. key, ok := updatedPS.Status.SyncedPushSecrets["SecretStore/new-store"][defaultPath]
  670. if !ok {
  671. return false
  672. }
  673. syncedLen := len(updatedPS.Status.SyncedPushSecrets)
  674. if syncedLen != 1 {
  675. return false
  676. }
  677. return key.Match.SecretKey == defaultKey
  678. }, time.Second*10, time.Second).Should(BeTrue())
  679. return true
  680. }
  681. }
  682. // if conversion strategy is defined, revert the keys based on the strategy.
  683. syncSuccessfullyWithConversionStrategy := func(tc *testCase) {
  684. fakeProvider.SetSecretFn = func() error {
  685. return nil
  686. }
  687. tc.pushsecret = &v1alpha1.PushSecret{
  688. ObjectMeta: metav1.ObjectMeta{
  689. Name: PushSecretName,
  690. Namespace: PushSecretNamespace,
  691. },
  692. Spec: v1alpha1.PushSecretSpec{
  693. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  694. {
  695. Name: PushSecretStore,
  696. Kind: "SecretStore",
  697. },
  698. },
  699. Selector: v1alpha1.PushSecretSelector{
  700. Secret: &v1alpha1.PushSecretSecret{
  701. Name: SecretName,
  702. },
  703. },
  704. Data: []v1alpha1.PushSecretData{
  705. {
  706. ConversionStrategy: v1alpha1.PushSecretConversionReverseUnicode,
  707. Match: v1alpha1.PushSecretMatch{
  708. SecretKey: "some-array[0].entity",
  709. RemoteRef: v1alpha1.PushSecretRemoteRef{
  710. RemoteKey: "path/to/key",
  711. },
  712. },
  713. },
  714. },
  715. },
  716. }
  717. tc.secret = &v1.Secret{
  718. ObjectMeta: metav1.ObjectMeta{
  719. Name: SecretName,
  720. Namespace: PushSecretNamespace,
  721. },
  722. Data: map[string][]byte{
  723. "some-array_U005b_0_U005d_.entity": []byte("value"),
  724. },
  725. }
  726. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  727. Eventually(func() bool {
  728. By("checking if Provider value got updated")
  729. secretValue := secret.Data["some-array_U005b_0_U005d_.entity"]
  730. providerValue, ok := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  731. if !ok {
  732. return false
  733. }
  734. got := providerValue.Value
  735. return bytes.Equal(got, secretValue)
  736. }, time.Second*10, time.Second).Should(BeTrue())
  737. return true
  738. }
  739. }
  740. // if target Secret name is not specified it should use the ExternalSecret name.
  741. syncMatchingLabels := func(tc *testCase) {
  742. fakeProvider.SetSecretFn = func() error {
  743. return nil
  744. }
  745. fakeProvider.DeleteSecretFn = func() error {
  746. return nil
  747. }
  748. tc.pushsecret = &v1alpha1.PushSecret{
  749. ObjectMeta: metav1.ObjectMeta{
  750. Name: PushSecretName,
  751. Namespace: PushSecretNamespace,
  752. },
  753. Spec: v1alpha1.PushSecretSpec{
  754. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  755. {
  756. LabelSelector: &metav1.LabelSelector{
  757. MatchLabels: map[string]string{
  758. "foo": "bar",
  759. },
  760. },
  761. Kind: "SecretStore",
  762. Name: PushSecretStore,
  763. },
  764. },
  765. Selector: v1alpha1.PushSecretSelector{
  766. Secret: &v1alpha1.PushSecretSecret{
  767. Name: SecretName,
  768. },
  769. },
  770. Data: []v1alpha1.PushSecretData{
  771. {
  772. Match: v1alpha1.PushSecretMatch{
  773. SecretKey: defaultKey,
  774. RemoteRef: v1alpha1.PushSecretRemoteRef{
  775. RemoteKey: defaultPath,
  776. },
  777. },
  778. },
  779. },
  780. },
  781. }
  782. tc.store = &v1beta1.SecretStore{
  783. TypeMeta: metav1.TypeMeta{
  784. Kind: "SecretStore",
  785. },
  786. ObjectMeta: metav1.ObjectMeta{
  787. Name: PushSecretStore,
  788. Namespace: PushSecretNamespace,
  789. Labels: map[string]string{
  790. "foo": "bar",
  791. },
  792. },
  793. Spec: v1beta1.SecretStoreSpec{
  794. Provider: &v1beta1.SecretStoreProvider{
  795. Fake: &v1beta1.FakeProvider{
  796. Data: []v1beta1.FakeProviderData{},
  797. },
  798. },
  799. },
  800. }
  801. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  802. secretValue := secret.Data[defaultKey]
  803. providerValue := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  804. expected := v1alpha1.PushSecretStatusCondition{
  805. Type: v1alpha1.PushSecretReady,
  806. Status: v1.ConditionTrue,
  807. Reason: v1alpha1.ReasonSynced,
  808. Message: "PushSecret synced successfully",
  809. }
  810. return bytes.Equal(secretValue, providerValue) && checkCondition(ps.Status, expected)
  811. }
  812. }
  813. syncWithClusterStore := func(tc *testCase) {
  814. fakeProvider.SetSecretFn = func() error {
  815. return nil
  816. }
  817. tc.store = &v1beta1.ClusterSecretStore{
  818. TypeMeta: metav1.TypeMeta{
  819. Kind: "ClusterSecretStore",
  820. },
  821. ObjectMeta: metav1.ObjectMeta{
  822. Name: PushSecretStore,
  823. },
  824. Spec: v1beta1.SecretStoreSpec{
  825. Provider: &v1beta1.SecretStoreProvider{
  826. Fake: &v1beta1.FakeProvider{
  827. Data: []v1beta1.FakeProviderData{},
  828. },
  829. },
  830. },
  831. }
  832. tc.pushsecret.Spec.SecretStoreRefs[0].Kind = "ClusterSecretStore"
  833. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  834. secretValue := secret.Data[defaultKey]
  835. providerValue := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  836. expected := v1alpha1.PushSecretStatusCondition{
  837. Type: v1alpha1.PushSecretReady,
  838. Status: v1.ConditionTrue,
  839. Reason: v1alpha1.ReasonSynced,
  840. Message: "PushSecret synced successfully",
  841. }
  842. return bytes.Equal(secretValue, providerValue) && checkCondition(ps.Status, expected)
  843. }
  844. }
  845. syncWithGenerator := func(tc *testCase) {
  846. fakeProvider.SetSecretFn = func() error {
  847. return nil
  848. }
  849. tc.pushsecret.Spec.Selector.Secret = nil
  850. tc.pushsecret.Spec.Selector.GeneratorRef = &v1beta1.GeneratorRef{
  851. APIVersion: "generators.external-secrets.io/v1alpha1",
  852. Kind: "Fake",
  853. Name: "test",
  854. }
  855. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  856. providerValue := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  857. expected := v1alpha1.PushSecretStatusCondition{
  858. Type: v1alpha1.PushSecretReady,
  859. Status: v1.ConditionTrue,
  860. Reason: v1alpha1.ReasonSynced,
  861. Message: "PushSecret synced successfully",
  862. }
  863. return bytes.Equal([]byte("foo-bar-from-generator"), providerValue) && checkCondition(ps.Status, expected)
  864. }
  865. }
  866. // if target Secret name is not specified it should use the ExternalSecret name.
  867. syncWithClusterStoreMatchingLabels := func(tc *testCase) {
  868. fakeProvider.SetSecretFn = func() error {
  869. return nil
  870. }
  871. tc.pushsecret = &v1alpha1.PushSecret{
  872. ObjectMeta: metav1.ObjectMeta{
  873. Name: PushSecretName,
  874. Namespace: PushSecretNamespace,
  875. },
  876. Spec: v1alpha1.PushSecretSpec{
  877. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  878. {
  879. LabelSelector: &metav1.LabelSelector{
  880. MatchLabels: map[string]string{
  881. "foo": "bar",
  882. },
  883. },
  884. Kind: "ClusterSecretStore",
  885. Name: PushSecretStore,
  886. },
  887. },
  888. Selector: v1alpha1.PushSecretSelector{
  889. Secret: &v1alpha1.PushSecretSecret{
  890. Name: SecretName,
  891. },
  892. },
  893. Data: []v1alpha1.PushSecretData{
  894. {
  895. Match: v1alpha1.PushSecretMatch{
  896. SecretKey: defaultKey,
  897. RemoteRef: v1alpha1.PushSecretRemoteRef{
  898. RemoteKey: defaultPath,
  899. },
  900. },
  901. },
  902. },
  903. },
  904. }
  905. tc.store = &v1beta1.ClusterSecretStore{
  906. ObjectMeta: metav1.ObjectMeta{
  907. Name: PushSecretStore,
  908. Labels: map[string]string{
  909. "foo": "bar",
  910. },
  911. },
  912. Spec: v1beta1.SecretStoreSpec{
  913. Provider: &v1beta1.SecretStoreProvider{
  914. Fake: &v1beta1.FakeProvider{
  915. Data: []v1beta1.FakeProviderData{},
  916. },
  917. },
  918. },
  919. }
  920. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  921. secretValue := secret.Data[defaultKey]
  922. providerValue := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  923. expected := v1alpha1.PushSecretStatusCondition{
  924. Type: v1alpha1.PushSecretReady,
  925. Status: v1.ConditionTrue,
  926. Reason: v1alpha1.ReasonSynced,
  927. Message: "PushSecret synced successfully",
  928. }
  929. return bytes.Equal(secretValue, providerValue) && checkCondition(ps.Status, expected)
  930. }
  931. }
  932. // if target Secret name is not specified it should use the ExternalSecret name.
  933. failNoSecret := func(tc *testCase) {
  934. fakeProvider.SetSecretFn = func() error {
  935. return nil
  936. }
  937. tc.secret = nil
  938. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  939. expected := v1alpha1.PushSecretStatusCondition{
  940. Type: v1alpha1.PushSecretReady,
  941. Status: v1.ConditionFalse,
  942. Reason: v1alpha1.ReasonErrored,
  943. Message: "could not get source secret",
  944. }
  945. return checkCondition(ps.Status, expected)
  946. }
  947. }
  948. // if target Secret name is not specified it should use the ExternalSecret name.
  949. failNoSecretKey := func(tc *testCase) {
  950. fakeProvider.SetSecretFn = func() error {
  951. return nil
  952. }
  953. tc.pushsecret.Spec.Data[0].Match.SecretKey = "unexisting"
  954. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  955. expected := v1alpha1.PushSecretStatusCondition{
  956. Type: v1alpha1.PushSecretReady,
  957. Status: v1.ConditionFalse,
  958. Reason: v1alpha1.ReasonErrored,
  959. Message: "set secret failed: secret key unexisting does not exist",
  960. }
  961. return checkCondition(ps.Status, expected)
  962. }
  963. }
  964. // if target Secret name is not specified it should use the ExternalSecret name.
  965. failNoSecretStore := func(tc *testCase) {
  966. fakeProvider.SetSecretFn = func() error {
  967. return nil
  968. }
  969. tc.store = nil
  970. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  971. expected := v1alpha1.PushSecretStatusCondition{
  972. Type: v1alpha1.PushSecretReady,
  973. Status: v1.ConditionFalse,
  974. Reason: v1alpha1.ReasonErrored,
  975. Message: "could not get SecretStore \"test-store\", secretstores.external-secrets.io \"test-store\" not found",
  976. }
  977. return checkCondition(ps.Status, expected)
  978. }
  979. }
  980. // if target Secret name is not specified it should use the ExternalSecret name.
  981. failNoClusterStore := func(tc *testCase) {
  982. fakeProvider.SetSecretFn = func() error {
  983. return nil
  984. }
  985. tc.store = nil
  986. tc.pushsecret.Spec.SecretStoreRefs[0].Kind = "ClusterSecretStore"
  987. tc.pushsecret.Spec.SecretStoreRefs[0].Name = "unexisting"
  988. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  989. expected := v1alpha1.PushSecretStatusCondition{
  990. Type: v1alpha1.PushSecretReady,
  991. Status: v1.ConditionFalse,
  992. Reason: v1alpha1.ReasonErrored,
  993. Message: "could not get ClusterSecretStore \"unexisting\", clustersecretstores.external-secrets.io \"unexisting\" not found",
  994. }
  995. return checkCondition(ps.Status, expected)
  996. }
  997. }
  998. // if target Secret name is not specified it should use the ExternalSecret name.
  999. setSecretFail := func(tc *testCase) {
  1000. fakeProvider.SetSecretFn = func() error {
  1001. return errors.New("boom")
  1002. }
  1003. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1004. expected := v1alpha1.PushSecretStatusCondition{
  1005. Type: v1alpha1.PushSecretReady,
  1006. Status: v1.ConditionFalse,
  1007. Reason: v1alpha1.ReasonErrored,
  1008. Message: "set secret failed: could not write remote ref key to target secretstore test-store: boom",
  1009. }
  1010. return checkCondition(ps.Status, expected)
  1011. }
  1012. }
  1013. // if target Secret name is not specified it should use the ExternalSecret name.
  1014. newClientFail := func(tc *testCase) {
  1015. fakeProvider.NewFn = func(context.Context, v1beta1.GenericStore, client.Client, string) (v1beta1.SecretsClient, error) {
  1016. return nil, errors.New("boom")
  1017. }
  1018. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1019. expected := v1alpha1.PushSecretStatusCondition{
  1020. Type: v1alpha1.PushSecretReady,
  1021. Status: v1.ConditionFalse,
  1022. Reason: v1alpha1.ReasonErrored,
  1023. Message: "set secret failed: could not get secrets client for store test-store: boom",
  1024. }
  1025. return checkCondition(ps.Status, expected)
  1026. }
  1027. }
  1028. DescribeTable("When reconciling a PushSecret",
  1029. func(tweaks ...testTweaks) {
  1030. tc := makeDefaultTestcase()
  1031. for _, tweak := range tweaks {
  1032. tweak(tc)
  1033. }
  1034. ctx := context.Background()
  1035. By("creating a secret store, secret and pushsecret")
  1036. if tc.store != nil {
  1037. Expect(k8sClient.Create(ctx, tc.store)).To(Succeed())
  1038. }
  1039. if tc.secret != nil {
  1040. Expect(k8sClient.Create(ctx, tc.secret)).To(Succeed())
  1041. }
  1042. if tc.pushsecret != nil {
  1043. Expect(k8sClient.Create(ctx, tc.pushsecret)).Should(Succeed())
  1044. }
  1045. time.Sleep(2 * time.Second) // prevents race conditions during tests causing failures
  1046. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  1047. createdPS := &v1alpha1.PushSecret{}
  1048. By("checking the pushSecret condition")
  1049. Eventually(func() bool {
  1050. err := k8sClient.Get(ctx, psKey, createdPS)
  1051. if err != nil {
  1052. return false
  1053. }
  1054. return tc.assert(createdPS, tc.secret)
  1055. }, timeout, interval).Should(BeTrue())
  1056. // this must be optional so we can test faulty es configuration
  1057. },
  1058. Entry("should sync", syncSuccessfully),
  1059. Entry("should not update existing secret if UpdatePolicy=IfNotExists", updateIfNotExists),
  1060. Entry("should only update parts of secret that don't already exist if UpdatePolicy=IfNotExists", updateIfNotExistsPartialSecrets),
  1061. Entry("should update the PushSecret status correctly if UpdatePolicy=IfNotExists", updateIfNotExistsSyncStatus),
  1062. Entry("should fail if secret existence cannot be verified if UpdatePolicy=IfNotExists", updateIfNotExistsSyncFailed),
  1063. Entry("should sync with template", syncSuccessfullyWithTemplate),
  1064. Entry("should sync with conversion strategy", syncSuccessfullyWithConversionStrategy),
  1065. Entry("should delete if DeletionPolicy=Delete", syncAndDeleteSuccessfully),
  1066. Entry("should delete after DeletionPolicy changed from Delete to None", syncChangePolicyAndDeleteSuccessfully),
  1067. Entry("should track deletion tasks if Delete fails", failDelete),
  1068. Entry("should track deleted stores if Delete fails", failDeleteStore),
  1069. Entry("should delete all secrets if SecretStore changes", deleteWholeStore),
  1070. Entry("should sync to stores matching labels", syncMatchingLabels),
  1071. Entry("should sync with ClusterStore", syncWithClusterStore),
  1072. Entry("should sync with ClusterStore matching labels", syncWithClusterStoreMatchingLabels),
  1073. Entry("should sync with Generator", syncWithGenerator),
  1074. Entry("should fail if Secret is not created", failNoSecret),
  1075. Entry("should fail if Secret Key does not exist", failNoSecretKey),
  1076. Entry("should fail if SetSecret fails", setSecretFail),
  1077. Entry("should fail if no valid SecretStore", failNoSecretStore),
  1078. Entry("should fail if no valid ClusterSecretStore", failNoClusterStore),
  1079. Entry("should fail if NewClient fails", newClientFail),
  1080. )
  1081. })
  1082. var _ = Describe("PushSecret Controller Un/Managed Stores", func() {
  1083. const (
  1084. PushSecretName = "test-ps"
  1085. ManagedPushSecretStore1 = "test-managed-store-1"
  1086. ManagedPushSecretStore2 = "test-managed-store-2"
  1087. UnmanagedPushSecretStore1 = "test-unmanaged-store-1"
  1088. UnmanagedPushSecretStore2 = "test-unmanaged-store-2"
  1089. SecretName = "test-secret"
  1090. )
  1091. var PushSecretNamespace string
  1092. PushSecretStores := []string{ManagedPushSecretStore1, ManagedPushSecretStore2, UnmanagedPushSecretStore1, UnmanagedPushSecretStore2}
  1093. // if we are in debug and need to increase the timeout for testing, we can do so by using an env var
  1094. if customTimeout := os.Getenv("TEST_CUSTOM_TIMEOUT_SEC"); customTimeout != "" {
  1095. if t, err := strconv.Atoi(customTimeout); err == nil {
  1096. timeout = time.Second * time.Duration(t)
  1097. }
  1098. }
  1099. BeforeEach(func() {
  1100. var err error
  1101. PushSecretNamespace, err = ctest.CreateNamespace("test-ns", k8sClient)
  1102. Expect(err).ToNot(HaveOccurred())
  1103. fakeProvider.Reset()
  1104. })
  1105. AfterEach(func() {
  1106. k8sClient.Delete(context.Background(), &v1alpha1.PushSecret{
  1107. ObjectMeta: metav1.ObjectMeta{
  1108. Name: PushSecretName,
  1109. Namespace: PushSecretNamespace,
  1110. },
  1111. })
  1112. // give a time for reconciler to remove finalizers before removing SecretStores
  1113. // TODO: Secret Stores should have finalizers bound to PushSecrets if DeletionPolicy == Delete
  1114. time.Sleep(2 * time.Second)
  1115. for _, psstore := range PushSecretStores {
  1116. k8sClient.Delete(context.Background(), &v1beta1.SecretStore{
  1117. ObjectMeta: metav1.ObjectMeta{
  1118. Name: psstore,
  1119. Namespace: PushSecretNamespace,
  1120. },
  1121. })
  1122. k8sClient.Delete(context.Background(), &v1beta1.ClusterSecretStore{
  1123. ObjectMeta: metav1.ObjectMeta{
  1124. Name: psstore,
  1125. },
  1126. })
  1127. }
  1128. k8sClient.Delete(context.Background(), &v1.Secret{
  1129. ObjectMeta: metav1.ObjectMeta{
  1130. Name: SecretName,
  1131. Namespace: PushSecretNamespace,
  1132. },
  1133. })
  1134. Expect(k8sClient.Delete(context.Background(), &v1.Namespace{
  1135. ObjectMeta: metav1.ObjectMeta{
  1136. Name: PushSecretNamespace,
  1137. },
  1138. })).To(Succeed())
  1139. })
  1140. const (
  1141. defaultKey = "key"
  1142. defaultVal = "value"
  1143. defaultPath = "path/to/key"
  1144. otherKey = "other-key"
  1145. otherVal = "other-value"
  1146. otherPath = "path/to/other-key"
  1147. newKey = "new-key"
  1148. newVal = "new-value"
  1149. storePrefixTemplate = "SecretStore/%v"
  1150. )
  1151. makeDefaultTestcase := func() *testCase {
  1152. return &testCase{
  1153. pushsecret: &v1alpha1.PushSecret{
  1154. ObjectMeta: metav1.ObjectMeta{
  1155. Name: PushSecretName,
  1156. Namespace: PushSecretNamespace,
  1157. },
  1158. Spec: v1alpha1.PushSecretSpec{
  1159. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  1160. {
  1161. Name: ManagedPushSecretStore1,
  1162. Kind: "SecretStore",
  1163. },
  1164. },
  1165. Selector: v1alpha1.PushSecretSelector{
  1166. Secret: &v1alpha1.PushSecretSecret{
  1167. Name: SecretName,
  1168. },
  1169. },
  1170. Data: []v1alpha1.PushSecretData{
  1171. {
  1172. Match: v1alpha1.PushSecretMatch{
  1173. SecretKey: defaultKey,
  1174. RemoteRef: v1alpha1.PushSecretRemoteRef{
  1175. RemoteKey: defaultPath,
  1176. },
  1177. },
  1178. },
  1179. },
  1180. },
  1181. },
  1182. secret: &v1.Secret{
  1183. ObjectMeta: metav1.ObjectMeta{
  1184. Name: SecretName,
  1185. Namespace: PushSecretNamespace,
  1186. },
  1187. Data: map[string][]byte{
  1188. defaultKey: []byte(defaultVal),
  1189. },
  1190. },
  1191. managedStore1: &v1beta1.SecretStore{
  1192. ObjectMeta: metav1.ObjectMeta{
  1193. Name: ManagedPushSecretStore1,
  1194. Namespace: PushSecretNamespace,
  1195. },
  1196. TypeMeta: metav1.TypeMeta{
  1197. Kind: "SecretStore",
  1198. },
  1199. Spec: v1beta1.SecretStoreSpec{
  1200. Provider: &v1beta1.SecretStoreProvider{
  1201. Fake: &v1beta1.FakeProvider{
  1202. Data: []v1beta1.FakeProviderData{},
  1203. },
  1204. },
  1205. },
  1206. },
  1207. managedStore2: &v1beta1.SecretStore{
  1208. ObjectMeta: metav1.ObjectMeta{
  1209. Name: ManagedPushSecretStore2,
  1210. Namespace: PushSecretNamespace,
  1211. },
  1212. TypeMeta: metav1.TypeMeta{
  1213. Kind: "SecretStore",
  1214. },
  1215. Spec: v1beta1.SecretStoreSpec{
  1216. Provider: &v1beta1.SecretStoreProvider{
  1217. Fake: &v1beta1.FakeProvider{
  1218. Data: []v1beta1.FakeProviderData{},
  1219. },
  1220. },
  1221. },
  1222. },
  1223. unmanagedStore1: &v1beta1.SecretStore{
  1224. ObjectMeta: metav1.ObjectMeta{
  1225. Name: UnmanagedPushSecretStore1,
  1226. Namespace: PushSecretNamespace,
  1227. },
  1228. TypeMeta: metav1.TypeMeta{
  1229. Kind: "SecretStore",
  1230. },
  1231. Spec: v1beta1.SecretStoreSpec{
  1232. Provider: &v1beta1.SecretStoreProvider{
  1233. Fake: &v1beta1.FakeProvider{
  1234. Data: []v1beta1.FakeProviderData{},
  1235. },
  1236. },
  1237. Controller: "not-managed",
  1238. },
  1239. },
  1240. unmanagedStore2: &v1beta1.SecretStore{
  1241. ObjectMeta: metav1.ObjectMeta{
  1242. Name: UnmanagedPushSecretStore2,
  1243. Namespace: PushSecretNamespace,
  1244. },
  1245. TypeMeta: metav1.TypeMeta{
  1246. Kind: "SecretStore",
  1247. },
  1248. Spec: v1beta1.SecretStoreSpec{
  1249. Provider: &v1beta1.SecretStoreProvider{
  1250. Fake: &v1beta1.FakeProvider{
  1251. Data: []v1beta1.FakeProviderData{},
  1252. },
  1253. },
  1254. Controller: "not-managed",
  1255. },
  1256. },
  1257. }
  1258. }
  1259. multipleManagedStoresSyncsSuccessfully := func(tc *testCase) {
  1260. fakeProvider.SetSecretFn = func() error {
  1261. return nil
  1262. }
  1263. tc.pushsecret.Spec.SecretStoreRefs = append(tc.pushsecret.Spec.SecretStoreRefs,
  1264. v1alpha1.PushSecretStoreRef{
  1265. Name: ManagedPushSecretStore2,
  1266. Kind: "SecretStore",
  1267. },
  1268. )
  1269. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1270. Eventually(func() bool {
  1271. By("checking if Provider value got updated")
  1272. secretValue := secret.Data[defaultKey]
  1273. providerValue, ok := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  1274. if !ok {
  1275. return false
  1276. }
  1277. got := providerValue.Value
  1278. return bytes.Equal(got, secretValue)
  1279. }, time.Second*10, time.Second).Should(BeTrue())
  1280. return true
  1281. }
  1282. }
  1283. skipUnmanagedStores := func(tc *testCase) {
  1284. tc.pushsecret.Spec.SecretStoreRefs = []v1alpha1.PushSecretStoreRef{
  1285. {
  1286. Name: UnmanagedPushSecretStore1,
  1287. Kind: "SecretStore",
  1288. },
  1289. {
  1290. Name: UnmanagedPushSecretStore2,
  1291. Kind: "SecretStore",
  1292. },
  1293. }
  1294. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1295. return len(ps.Status.Conditions) == 0
  1296. }
  1297. }
  1298. warnUnmanagedStoresAndSyncManagedStores := func(tc *testCase) {
  1299. fakeProvider.SetSecretFn = func() error {
  1300. return nil
  1301. }
  1302. tc.pushsecret.Spec.SecretStoreRefs = []v1alpha1.PushSecretStoreRef{
  1303. {
  1304. Name: ManagedPushSecretStore1,
  1305. Kind: "SecretStore",
  1306. },
  1307. {
  1308. Name: ManagedPushSecretStore2,
  1309. Kind: "SecretStore",
  1310. },
  1311. {
  1312. Name: UnmanagedPushSecretStore1,
  1313. Kind: "SecretStore",
  1314. },
  1315. {
  1316. Name: UnmanagedPushSecretStore2,
  1317. Kind: "SecretStore",
  1318. },
  1319. }
  1320. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1321. Eventually(func() bool {
  1322. By("checking if Provider value got updated")
  1323. secretValue := secret.Data[defaultKey]
  1324. providerValue, ok := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  1325. if !ok {
  1326. return false
  1327. }
  1328. got := providerValue.Value
  1329. return bytes.Equal(got, secretValue)
  1330. }, time.Second*10, time.Second).Should(BeTrue())
  1331. return true
  1332. }
  1333. }
  1334. DescribeTable("When reconciling a PushSecret with multiple secret stores",
  1335. func(tweaks ...testTweaks) {
  1336. tc := makeDefaultTestcase()
  1337. for _, tweak := range tweaks {
  1338. tweak(tc)
  1339. }
  1340. ctx := context.Background()
  1341. By("creating secret stores, a secret and a pushsecret")
  1342. if tc.managedStore1 != nil {
  1343. Expect(k8sClient.Create(ctx, tc.managedStore1)).To(Succeed())
  1344. }
  1345. if tc.managedStore2 != nil {
  1346. Expect(k8sClient.Create(ctx, tc.managedStore2)).To(Succeed())
  1347. }
  1348. if tc.unmanagedStore1 != nil {
  1349. Expect(k8sClient.Create(ctx, tc.unmanagedStore1)).To(Succeed())
  1350. }
  1351. if tc.unmanagedStore2 != nil {
  1352. Expect(k8sClient.Create(ctx, tc.unmanagedStore2)).To(Succeed())
  1353. }
  1354. if tc.secret != nil {
  1355. Expect(k8sClient.Create(ctx, tc.secret)).To(Succeed())
  1356. }
  1357. if tc.pushsecret != nil {
  1358. Expect(k8sClient.Create(ctx, tc.pushsecret)).Should(Succeed())
  1359. }
  1360. time.Sleep(2 * time.Second) // prevents race conditions during tests causing failures
  1361. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  1362. createdPS := &v1alpha1.PushSecret{}
  1363. By("checking the pushSecret condition")
  1364. Eventually(func() bool {
  1365. err := k8sClient.Get(ctx, psKey, createdPS)
  1366. if err != nil {
  1367. return false
  1368. }
  1369. return tc.assert(createdPS, tc.secret)
  1370. }, timeout, interval).Should(BeTrue())
  1371. // this must be optional so we can test faulty es configuration
  1372. },
  1373. Entry("should sync successfully if there are multiple managed stores", multipleManagedStoresSyncsSuccessfully),
  1374. Entry("should skip unmanaged stores", skipUnmanagedStores),
  1375. Entry("should skip unmanaged stores and sync managed stores", warnUnmanagedStoresAndSyncManagedStores),
  1376. )
  1377. })