pushsecret_controller_test.go 49 KB

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