pushsecret_controller_test.go 44 KB

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