pushsecret_controller_test.go 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485
  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. 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(), &esv1.SecretStore{
  112. ObjectMeta: metav1.ObjectMeta{
  113. Name: PushSecretStore,
  114. Namespace: PushSecretNamespace,
  115. },
  116. })
  117. k8sClient.Delete(context.Background(), &esv1.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: &esv1.SecretStore{
  186. ObjectMeta: metav1.ObjectMeta{
  187. Name: PushSecretStore,
  188. Namespace: PushSecretNamespace,
  189. },
  190. TypeMeta: metav1.TypeMeta{
  191. Kind: "SecretStore",
  192. },
  193. Spec: esv1.SecretStoreSpec{
  194. Provider: &esv1.SecretStoreProvider{
  195. Fake: &esv1.FakeProvider{
  196. Data: []esv1.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 esv1.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 esv1.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 esv1.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 esv1.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. syncSuccessfullyReusingKeys := func(tc *testCase) {
  364. fakeProvider.SetSecretFn = func() error {
  365. return nil
  366. }
  367. tc.pushsecret = &v1alpha1.PushSecret{
  368. ObjectMeta: metav1.ObjectMeta{
  369. Name: PushSecretName,
  370. Namespace: PushSecretNamespace,
  371. },
  372. Spec: v1alpha1.PushSecretSpec{
  373. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  374. {
  375. Name: PushSecretStore,
  376. Kind: "SecretStore",
  377. },
  378. },
  379. Selector: v1alpha1.PushSecretSelector{
  380. Secret: &v1alpha1.PushSecretSecret{
  381. Name: SecretName,
  382. },
  383. },
  384. Data: []v1alpha1.PushSecretData{
  385. {
  386. Match: v1alpha1.PushSecretMatch{
  387. SecretKey: "otherKey",
  388. RemoteRef: v1alpha1.PushSecretRemoteRef{
  389. RemoteKey: defaultPath,
  390. },
  391. },
  392. },
  393. },
  394. Template: &esv1.ExternalSecretTemplate{
  395. Metadata: esv1.ExternalSecretTemplateMetadata{
  396. Labels: map[string]string{
  397. "foos": "ball",
  398. },
  399. Annotations: map[string]string{
  400. "hihi": "ga",
  401. },
  402. },
  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. 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 also 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. syncSuccessfullyWithTemplate := 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. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  437. {
  438. Name: PushSecretStore,
  439. Kind: "SecretStore",
  440. },
  441. },
  442. Selector: v1alpha1.PushSecretSelector{
  443. Secret: &v1alpha1.PushSecretSecret{
  444. Name: SecretName,
  445. },
  446. },
  447. Data: []v1alpha1.PushSecretData{
  448. {
  449. Match: v1alpha1.PushSecretMatch{
  450. SecretKey: defaultKey,
  451. RemoteRef: v1alpha1.PushSecretRemoteRef{
  452. RemoteKey: defaultPath,
  453. },
  454. },
  455. },
  456. },
  457. Template: &esv1.ExternalSecretTemplate{
  458. Metadata: esv1.ExternalSecretTemplateMetadata{
  459. Labels: map[string]string{
  460. "foos": "ball",
  461. },
  462. Annotations: map[string]string{
  463. "hihi": "ga",
  464. },
  465. },
  466. Type: v1.SecretTypeOpaque,
  467. EngineVersion: esv1.TemplateEngineV2,
  468. Data: map[string]string{
  469. defaultKey: "{{ .key | toString | upper }} was templated",
  470. },
  471. },
  472. },
  473. }
  474. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  475. Eventually(func() bool {
  476. By("checking if Provider value got updated")
  477. providerValue, ok := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  478. if !ok {
  479. return false
  480. }
  481. got := providerValue.Value
  482. return bytes.Equal(got, []byte("VALUE was templated"))
  483. }, time.Second*10, time.Second).Should(BeTrue())
  484. return true
  485. }
  486. }
  487. // if target Secret name is not specified it should use the ExternalSecret name.
  488. syncAndDeleteSuccessfully := func(tc *testCase) {
  489. fakeProvider.SetSecretFn = func() error {
  490. return nil
  491. }
  492. tc.pushsecret = &v1alpha1.PushSecret{
  493. ObjectMeta: metav1.ObjectMeta{
  494. Name: PushSecretName,
  495. Namespace: PushSecretNamespace,
  496. },
  497. Spec: v1alpha1.PushSecretSpec{
  498. DeletionPolicy: v1alpha1.PushSecretDeletionPolicyDelete,
  499. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  500. {
  501. Name: PushSecretStore,
  502. Kind: "SecretStore",
  503. },
  504. },
  505. Selector: v1alpha1.PushSecretSelector{
  506. Secret: &v1alpha1.PushSecretSecret{
  507. Name: SecretName,
  508. },
  509. },
  510. Data: []v1alpha1.PushSecretData{
  511. {
  512. Match: v1alpha1.PushSecretMatch{
  513. SecretKey: defaultKey,
  514. RemoteRef: v1alpha1.PushSecretRemoteRef{
  515. RemoteKey: defaultPath,
  516. },
  517. },
  518. },
  519. },
  520. },
  521. }
  522. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  523. ps.Spec.Data[0].Match.RemoteRef.RemoteKey = newKey
  524. updatedPS := &v1alpha1.PushSecret{}
  525. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  526. Eventually(func() bool {
  527. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  528. By("checking if Provider value got updated")
  529. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  530. if err != nil {
  531. return false
  532. }
  533. key, ok := updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][newKey]
  534. if !ok {
  535. return false
  536. }
  537. return key.Match.SecretKey == defaultKey
  538. }, time.Second*10, time.Second).Should(BeTrue())
  539. return true
  540. }
  541. }
  542. // if PushSecret's DeletionPolicy is cleared, it should delete successfully
  543. syncChangePolicyAndDeleteSuccessfully := func(tc *testCase) {
  544. fakeProvider.SetSecretFn = func() error {
  545. return nil
  546. }
  547. tc.pushsecret = &v1alpha1.PushSecret{
  548. ObjectMeta: metav1.ObjectMeta{
  549. Name: PushSecretName,
  550. Namespace: PushSecretNamespace,
  551. },
  552. Spec: v1alpha1.PushSecretSpec{
  553. DeletionPolicy: v1alpha1.PushSecretDeletionPolicyDelete,
  554. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  555. {
  556. Name: PushSecretStore,
  557. Kind: "SecretStore",
  558. },
  559. },
  560. Selector: v1alpha1.PushSecretSelector{
  561. Secret: &v1alpha1.PushSecretSecret{
  562. Name: SecretName,
  563. },
  564. },
  565. Data: []v1alpha1.PushSecretData{
  566. {
  567. Match: v1alpha1.PushSecretMatch{
  568. SecretKey: defaultKey,
  569. RemoteRef: v1alpha1.PushSecretRemoteRef{
  570. RemoteKey: defaultPath,
  571. },
  572. },
  573. },
  574. },
  575. },
  576. }
  577. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  578. ps.Spec.DeletionPolicy = v1alpha1.PushSecretDeletionPolicyNone
  579. updatedPS := &v1alpha1.PushSecret{}
  580. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  581. Expect(k8sClient.Delete(context.Background(), ps, &client.DeleteOptions{})).Should(Succeed())
  582. Eventually(func() bool {
  583. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  584. By("checking if Get PushSecret returns not found")
  585. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  586. if err != nil && client.IgnoreNotFound(err) == nil {
  587. return true
  588. }
  589. return false
  590. }, time.Second*10, time.Second).Should(BeTrue())
  591. return true
  592. }
  593. }
  594. failDelete := func(tc *testCase) {
  595. fakeProvider.SetSecretFn = func() error {
  596. return nil
  597. }
  598. fakeProvider.DeleteSecretFn = func() error {
  599. return errors.New("Nope")
  600. }
  601. tc.pushsecret = &v1alpha1.PushSecret{
  602. ObjectMeta: metav1.ObjectMeta{
  603. Name: PushSecretName,
  604. Namespace: PushSecretNamespace,
  605. },
  606. Spec: v1alpha1.PushSecretSpec{
  607. DeletionPolicy: v1alpha1.PushSecretDeletionPolicyDelete,
  608. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  609. {
  610. Name: PushSecretStore,
  611. Kind: "SecretStore",
  612. },
  613. },
  614. Selector: v1alpha1.PushSecretSelector{
  615. Secret: &v1alpha1.PushSecretSecret{
  616. Name: SecretName,
  617. },
  618. },
  619. Data: []v1alpha1.PushSecretData{
  620. {
  621. Match: v1alpha1.PushSecretMatch{
  622. SecretKey: defaultKey,
  623. RemoteRef: v1alpha1.PushSecretRemoteRef{
  624. RemoteKey: defaultPath,
  625. },
  626. },
  627. },
  628. },
  629. },
  630. }
  631. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  632. ps.Spec.Data[0].Match.RemoteRef.RemoteKey = newKey
  633. updatedPS := &v1alpha1.PushSecret{}
  634. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  635. Eventually(func() bool {
  636. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  637. By("checking if synced secrets correspond to both keys")
  638. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  639. if err != nil {
  640. return false
  641. }
  642. _, ok := updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][newKey]
  643. if !ok {
  644. return false
  645. }
  646. _, ok = updatedPS.Status.SyncedPushSecrets[fmt.Sprintf(storePrefixTemplate, PushSecretStore)][defaultPath]
  647. return ok
  648. }, time.Second*10, time.Second).Should(BeTrue())
  649. return true
  650. }
  651. }
  652. failDeleteStore := func(tc *testCase) {
  653. fakeProvider.SetSecretFn = func() error {
  654. return nil
  655. }
  656. fakeProvider.DeleteSecretFn = func() error {
  657. return errors.New("boom")
  658. }
  659. tc.pushsecret.Spec.DeletionPolicy = v1alpha1.PushSecretDeletionPolicyDelete
  660. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  661. secondStore := &esv1.SecretStore{
  662. ObjectMeta: metav1.ObjectMeta{
  663. Name: "new-store",
  664. Namespace: PushSecretNamespace,
  665. },
  666. TypeMeta: metav1.TypeMeta{
  667. Kind: "SecretStore",
  668. },
  669. Spec: esv1.SecretStoreSpec{
  670. Provider: &esv1.SecretStoreProvider{
  671. Fake: &esv1.FakeProvider{
  672. Data: []esv1.FakeProviderData{},
  673. },
  674. },
  675. },
  676. }
  677. Expect(k8sClient.Create(context.Background(), secondStore, &client.CreateOptions{})).Should(Succeed())
  678. ps.Spec.SecretStoreRefs[0].Name = "new-store"
  679. updatedPS := &v1alpha1.PushSecret{}
  680. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  681. Eventually(func() bool {
  682. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  683. By("checking if Provider value got updated")
  684. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  685. if err != nil {
  686. return false
  687. }
  688. syncedLen := len(updatedPS.Status.SyncedPushSecrets)
  689. return syncedLen == 2
  690. }, time.Second*10, time.Second).Should(BeTrue())
  691. return true
  692. }
  693. }
  694. deleteWholeStore := func(tc *testCase) {
  695. fakeProvider.SetSecretFn = func() error {
  696. return nil
  697. }
  698. fakeProvider.DeleteSecretFn = func() error {
  699. return nil
  700. }
  701. tc.pushsecret.Spec.DeletionPolicy = v1alpha1.PushSecretDeletionPolicyDelete
  702. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  703. secondStore := &esv1.SecretStore{
  704. ObjectMeta: metav1.ObjectMeta{
  705. Name: "new-store",
  706. Namespace: PushSecretNamespace,
  707. },
  708. TypeMeta: metav1.TypeMeta{
  709. Kind: "SecretStore",
  710. },
  711. Spec: esv1.SecretStoreSpec{
  712. Provider: &esv1.SecretStoreProvider{
  713. Fake: &esv1.FakeProvider{
  714. Data: []esv1.FakeProviderData{},
  715. },
  716. },
  717. },
  718. }
  719. Expect(k8sClient.Create(context.Background(), secondStore, &client.CreateOptions{})).Should(Succeed())
  720. ps.Spec.SecretStoreRefs[0].Name = "new-store"
  721. updatedPS := &v1alpha1.PushSecret{}
  722. Expect(k8sClient.Update(context.Background(), ps, &client.UpdateOptions{})).Should(Succeed())
  723. Eventually(func() bool {
  724. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  725. By("checking if Provider value got updated")
  726. err := k8sClient.Get(context.Background(), psKey, updatedPS)
  727. if err != nil {
  728. return false
  729. }
  730. key, ok := updatedPS.Status.SyncedPushSecrets["SecretStore/new-store"][defaultPath]
  731. if !ok {
  732. return false
  733. }
  734. syncedLen := len(updatedPS.Status.SyncedPushSecrets)
  735. if syncedLen != 1 {
  736. return false
  737. }
  738. return key.Match.SecretKey == defaultKey
  739. }, time.Second*10, time.Second).Should(BeTrue())
  740. return true
  741. }
  742. }
  743. // if conversion strategy is defined, revert the keys based on the strategy.
  744. syncSuccessfullyWithConversionStrategy := func(tc *testCase) {
  745. fakeProvider.SetSecretFn = func() error {
  746. return nil
  747. }
  748. tc.pushsecret = &v1alpha1.PushSecret{
  749. ObjectMeta: metav1.ObjectMeta{
  750. Name: PushSecretName,
  751. Namespace: PushSecretNamespace,
  752. },
  753. Spec: v1alpha1.PushSecretSpec{
  754. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  755. {
  756. Name: PushSecretStore,
  757. Kind: "SecretStore",
  758. },
  759. },
  760. Selector: v1alpha1.PushSecretSelector{
  761. Secret: &v1alpha1.PushSecretSecret{
  762. Name: SecretName,
  763. },
  764. },
  765. Data: []v1alpha1.PushSecretData{
  766. {
  767. ConversionStrategy: v1alpha1.PushSecretConversionReverseUnicode,
  768. Match: v1alpha1.PushSecretMatch{
  769. SecretKey: "some-array[0].entity",
  770. RemoteRef: v1alpha1.PushSecretRemoteRef{
  771. RemoteKey: defaultPath,
  772. },
  773. },
  774. },
  775. },
  776. },
  777. }
  778. tc.secret = &v1.Secret{
  779. ObjectMeta: metav1.ObjectMeta{
  780. Name: SecretName,
  781. Namespace: PushSecretNamespace,
  782. },
  783. Data: map[string][]byte{
  784. "some-array_U005b_0_U005d_.entity": []byte("value"),
  785. },
  786. }
  787. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  788. Eventually(func() bool {
  789. By("checking if Provider value got updated")
  790. secretValue := secret.Data["some-array_U005b_0_U005d_.entity"]
  791. providerValue, ok := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  792. if !ok {
  793. return false
  794. }
  795. got := providerValue.Value
  796. return bytes.Equal(got, secretValue)
  797. }, time.Second*10, time.Second).Should(BeTrue())
  798. return true
  799. }
  800. }
  801. // if target Secret name is not specified it should use the ExternalSecret name.
  802. syncMatchingLabels := func(tc *testCase) {
  803. fakeProvider.SetSecretFn = func() error {
  804. return nil
  805. }
  806. fakeProvider.DeleteSecretFn = func() error {
  807. return nil
  808. }
  809. tc.pushsecret = &v1alpha1.PushSecret{
  810. ObjectMeta: metav1.ObjectMeta{
  811. Name: PushSecretName,
  812. Namespace: PushSecretNamespace,
  813. },
  814. Spec: v1alpha1.PushSecretSpec{
  815. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  816. {
  817. LabelSelector: &metav1.LabelSelector{
  818. MatchLabels: map[string]string{
  819. "foo": "bar",
  820. },
  821. },
  822. Kind: "SecretStore",
  823. Name: PushSecretStore,
  824. },
  825. },
  826. Selector: v1alpha1.PushSecretSelector{
  827. Secret: &v1alpha1.PushSecretSecret{
  828. Name: SecretName,
  829. },
  830. },
  831. Data: []v1alpha1.PushSecretData{
  832. {
  833. Match: v1alpha1.PushSecretMatch{
  834. SecretKey: defaultKey,
  835. RemoteRef: v1alpha1.PushSecretRemoteRef{
  836. RemoteKey: defaultPath,
  837. },
  838. },
  839. },
  840. },
  841. },
  842. }
  843. tc.store = &esv1.SecretStore{
  844. TypeMeta: metav1.TypeMeta{
  845. Kind: "SecretStore",
  846. },
  847. ObjectMeta: metav1.ObjectMeta{
  848. Name: PushSecretStore,
  849. Namespace: PushSecretNamespace,
  850. Labels: map[string]string{
  851. "foo": "bar",
  852. },
  853. },
  854. Spec: esv1.SecretStoreSpec{
  855. Provider: &esv1.SecretStoreProvider{
  856. Fake: &esv1.FakeProvider{
  857. Data: []esv1.FakeProviderData{},
  858. },
  859. },
  860. },
  861. }
  862. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  863. secretValue := secret.Data[defaultKey]
  864. providerValue := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  865. expected := v1alpha1.PushSecretStatusCondition{
  866. Type: v1alpha1.PushSecretReady,
  867. Status: v1.ConditionTrue,
  868. Reason: v1alpha1.ReasonSynced,
  869. Message: "PushSecret synced successfully",
  870. }
  871. return bytes.Equal(secretValue, providerValue) && checkCondition(ps.Status, expected)
  872. }
  873. }
  874. syncWithClusterStore := func(tc *testCase) {
  875. fakeProvider.SetSecretFn = func() error {
  876. return nil
  877. }
  878. tc.store = &esv1.ClusterSecretStore{
  879. TypeMeta: metav1.TypeMeta{
  880. Kind: "ClusterSecretStore",
  881. },
  882. ObjectMeta: metav1.ObjectMeta{
  883. Name: PushSecretStore,
  884. },
  885. Spec: esv1.SecretStoreSpec{
  886. Provider: &esv1.SecretStoreProvider{
  887. Fake: &esv1.FakeProvider{
  888. Data: []esv1.FakeProviderData{},
  889. },
  890. },
  891. },
  892. }
  893. tc.pushsecret.Spec.SecretStoreRefs[0].Kind = "ClusterSecretStore"
  894. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  895. secretValue := secret.Data[defaultKey]
  896. providerValue := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  897. expected := v1alpha1.PushSecretStatusCondition{
  898. Type: v1alpha1.PushSecretReady,
  899. Status: v1.ConditionTrue,
  900. Reason: v1alpha1.ReasonSynced,
  901. Message: "PushSecret synced successfully",
  902. }
  903. return bytes.Equal(secretValue, providerValue) && checkCondition(ps.Status, expected)
  904. }
  905. }
  906. syncWithGenerator := func(tc *testCase) {
  907. fakeProvider.SetSecretFn = func() error {
  908. return nil
  909. }
  910. tc.pushsecret.Spec.Selector.Secret = nil
  911. tc.pushsecret.Spec.Selector.GeneratorRef = &esv1.GeneratorRef{
  912. APIVersion: "generators.external-secrets.io/v1alpha1",
  913. Kind: "Fake",
  914. Name: "test",
  915. }
  916. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  917. providerValue := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  918. expected := v1alpha1.PushSecretStatusCondition{
  919. Type: v1alpha1.PushSecretReady,
  920. Status: v1.ConditionTrue,
  921. Reason: v1alpha1.ReasonSynced,
  922. Message: "PushSecret synced successfully",
  923. }
  924. return bytes.Equal([]byte("foo-bar-from-generator"), providerValue) && checkCondition(ps.Status, expected)
  925. }
  926. }
  927. // if target Secret name is not specified it should use the ExternalSecret name.
  928. syncWithClusterStoreMatchingLabels := func(tc *testCase) {
  929. fakeProvider.SetSecretFn = func() error {
  930. return nil
  931. }
  932. tc.pushsecret = &v1alpha1.PushSecret{
  933. ObjectMeta: metav1.ObjectMeta{
  934. Name: PushSecretName,
  935. Namespace: PushSecretNamespace,
  936. },
  937. Spec: v1alpha1.PushSecretSpec{
  938. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  939. {
  940. LabelSelector: &metav1.LabelSelector{
  941. MatchLabels: map[string]string{
  942. "foo": "bar",
  943. },
  944. },
  945. Kind: "ClusterSecretStore",
  946. Name: PushSecretStore,
  947. },
  948. },
  949. Selector: v1alpha1.PushSecretSelector{
  950. Secret: &v1alpha1.PushSecretSecret{
  951. Name: SecretName,
  952. },
  953. },
  954. Data: []v1alpha1.PushSecretData{
  955. {
  956. Match: v1alpha1.PushSecretMatch{
  957. SecretKey: defaultKey,
  958. RemoteRef: v1alpha1.PushSecretRemoteRef{
  959. RemoteKey: defaultPath,
  960. },
  961. },
  962. },
  963. },
  964. },
  965. }
  966. tc.store = &esv1.ClusterSecretStore{
  967. ObjectMeta: metav1.ObjectMeta{
  968. Name: PushSecretStore,
  969. Labels: map[string]string{
  970. "foo": "bar",
  971. },
  972. },
  973. Spec: esv1.SecretStoreSpec{
  974. Provider: &esv1.SecretStoreProvider{
  975. Fake: &esv1.FakeProvider{
  976. Data: []esv1.FakeProviderData{},
  977. },
  978. },
  979. },
  980. }
  981. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  982. secretValue := secret.Data[defaultKey]
  983. providerValue := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey].Value
  984. expected := v1alpha1.PushSecretStatusCondition{
  985. Type: v1alpha1.PushSecretReady,
  986. Status: v1.ConditionTrue,
  987. Reason: v1alpha1.ReasonSynced,
  988. Message: "PushSecret synced successfully",
  989. }
  990. return bytes.Equal(secretValue, providerValue) && checkCondition(ps.Status, expected)
  991. }
  992. }
  993. // if target Secret name is not specified it should use the ExternalSecret name.
  994. failNoSecret := func(tc *testCase) {
  995. fakeProvider.SetSecretFn = func() error {
  996. return nil
  997. }
  998. tc.secret = nil
  999. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1000. expected := v1alpha1.PushSecretStatusCondition{
  1001. Type: v1alpha1.PushSecretReady,
  1002. Status: v1.ConditionFalse,
  1003. Reason: v1alpha1.ReasonErrored,
  1004. Message: "could not get source secret",
  1005. }
  1006. return checkCondition(ps.Status, expected)
  1007. }
  1008. }
  1009. // if target Secret name is not specified it should use the ExternalSecret name.
  1010. failNoSecretKey := func(tc *testCase) {
  1011. fakeProvider.SetSecretFn = func() error {
  1012. return nil
  1013. }
  1014. tc.pushsecret.Spec.Data[0].Match.SecretKey = "unexisting"
  1015. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1016. expected := v1alpha1.PushSecretStatusCondition{
  1017. Type: v1alpha1.PushSecretReady,
  1018. Status: v1.ConditionFalse,
  1019. Reason: v1alpha1.ReasonErrored,
  1020. Message: "set secret failed: secret key unexisting does not exist",
  1021. }
  1022. return checkCondition(ps.Status, expected)
  1023. }
  1024. }
  1025. // if target Secret name is not specified it should use the ExternalSecret name.
  1026. failNoSecretStore := func(tc *testCase) {
  1027. fakeProvider.SetSecretFn = func() error {
  1028. return nil
  1029. }
  1030. tc.store = nil
  1031. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1032. expected := v1alpha1.PushSecretStatusCondition{
  1033. Type: v1alpha1.PushSecretReady,
  1034. Status: v1.ConditionFalse,
  1035. Reason: v1alpha1.ReasonErrored,
  1036. Message: "could not get SecretStore \"test-store\", secretstores.external-secrets.io \"test-store\" not found",
  1037. }
  1038. return checkCondition(ps.Status, expected)
  1039. }
  1040. }
  1041. // if target Secret name is not specified it should use the ExternalSecret name.
  1042. failNoClusterStore := func(tc *testCase) {
  1043. fakeProvider.SetSecretFn = func() error {
  1044. return nil
  1045. }
  1046. tc.store = nil
  1047. tc.pushsecret.Spec.SecretStoreRefs[0].Kind = "ClusterSecretStore"
  1048. tc.pushsecret.Spec.SecretStoreRefs[0].Name = "unexisting"
  1049. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1050. expected := v1alpha1.PushSecretStatusCondition{
  1051. Type: v1alpha1.PushSecretReady,
  1052. Status: v1.ConditionFalse,
  1053. Reason: v1alpha1.ReasonErrored,
  1054. Message: "could not get ClusterSecretStore \"unexisting\", clustersecretstores.external-secrets.io \"unexisting\" not found",
  1055. }
  1056. return checkCondition(ps.Status, expected)
  1057. }
  1058. }
  1059. // if target Secret name is not specified it should use the ExternalSecret name.
  1060. setSecretFail := func(tc *testCase) {
  1061. fakeProvider.SetSecretFn = func() error {
  1062. return errors.New("boom")
  1063. }
  1064. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1065. expected := v1alpha1.PushSecretStatusCondition{
  1066. Type: v1alpha1.PushSecretReady,
  1067. Status: v1.ConditionFalse,
  1068. Reason: v1alpha1.ReasonErrored,
  1069. Message: "set secret failed: could not write remote ref key to target secretstore test-store: boom",
  1070. }
  1071. return checkCondition(ps.Status, expected)
  1072. }
  1073. }
  1074. // if target Secret name is not specified it should use the ExternalSecret name.
  1075. newClientFail := func(tc *testCase) {
  1076. fakeProvider.NewFn = func(context.Context, esv1.GenericStore, client.Client, string) (esv1.SecretsClient, error) {
  1077. return nil, errors.New("boom")
  1078. }
  1079. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1080. expected := v1alpha1.PushSecretStatusCondition{
  1081. Type: v1alpha1.PushSecretReady,
  1082. Status: v1.ConditionFalse,
  1083. Reason: v1alpha1.ReasonErrored,
  1084. Message: "set secret failed: could not get secrets client for store test-store: boom",
  1085. }
  1086. return checkCondition(ps.Status, expected)
  1087. }
  1088. }
  1089. DescribeTable("When reconciling a PushSecret",
  1090. func(tweaks ...testTweaks) {
  1091. tc := makeDefaultTestcase()
  1092. for _, tweak := range tweaks {
  1093. tweak(tc)
  1094. }
  1095. ctx := context.Background()
  1096. By("creating a secret store, secret and pushsecret")
  1097. if tc.store != nil {
  1098. Expect(k8sClient.Create(ctx, tc.store)).To(Succeed())
  1099. }
  1100. if tc.secret != nil {
  1101. Expect(k8sClient.Create(ctx, tc.secret)).To(Succeed())
  1102. }
  1103. if tc.pushsecret != nil {
  1104. Expect(k8sClient.Create(ctx, tc.pushsecret)).Should(Succeed())
  1105. }
  1106. time.Sleep(2 * time.Second) // prevents race conditions during tests causing failures
  1107. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  1108. createdPS := &v1alpha1.PushSecret{}
  1109. By("checking the pushSecret condition")
  1110. Eventually(func() bool {
  1111. err := k8sClient.Get(ctx, psKey, createdPS)
  1112. if err != nil {
  1113. return false
  1114. }
  1115. return tc.assert(createdPS, tc.secret)
  1116. }, timeout, interval).Should(BeTrue())
  1117. // this must be optional so we can test faulty es configuration
  1118. },
  1119. Entry("should sync", syncSuccessfully),
  1120. Entry("should not update existing secret if UpdatePolicy=IfNotExists", updateIfNotExists),
  1121. Entry("should only update parts of secret that don't already exist if UpdatePolicy=IfNotExists", updateIfNotExistsPartialSecrets),
  1122. Entry("should update the PushSecret status correctly if UpdatePolicy=IfNotExists", updateIfNotExistsSyncStatus),
  1123. Entry("should fail if secret existence cannot be verified if UpdatePolicy=IfNotExists", updateIfNotExistsSyncFailed),
  1124. Entry("should sync with template", syncSuccessfullyWithTemplate),
  1125. Entry("should sync with template reusing keys", syncSuccessfullyReusingKeys),
  1126. Entry("should sync with conversion strategy", syncSuccessfullyWithConversionStrategy),
  1127. Entry("should delete if DeletionPolicy=Delete", syncAndDeleteSuccessfully),
  1128. Entry("should delete after DeletionPolicy changed from Delete to None", syncChangePolicyAndDeleteSuccessfully),
  1129. Entry("should track deletion tasks if Delete fails", failDelete),
  1130. Entry("should track deleted stores if Delete fails", failDeleteStore),
  1131. Entry("should delete all secrets if SecretStore changes", deleteWholeStore),
  1132. Entry("should sync to stores matching labels", syncMatchingLabels),
  1133. Entry("should sync with ClusterStore", syncWithClusterStore),
  1134. Entry("should sync with ClusterStore matching labels", syncWithClusterStoreMatchingLabels),
  1135. Entry("should sync with Generator", syncWithGenerator),
  1136. Entry("should fail if Secret is not created", failNoSecret),
  1137. Entry("should fail if Secret Key does not exist", failNoSecretKey),
  1138. Entry("should fail if SetSecret fails", setSecretFail),
  1139. Entry("should fail if no valid SecretStore", failNoSecretStore),
  1140. Entry("should fail if no valid ClusterSecretStore", failNoClusterStore),
  1141. Entry("should fail if NewClient fails", newClientFail),
  1142. )
  1143. })
  1144. var _ = Describe("PushSecret Controller Un/Managed Stores", func() {
  1145. const (
  1146. PushSecretName = "test-ps"
  1147. ManagedPushSecretStore1 = "test-managed-store-1"
  1148. ManagedPushSecretStore2 = "test-managed-store-2"
  1149. UnmanagedPushSecretStore1 = "test-unmanaged-store-1"
  1150. UnmanagedPushSecretStore2 = "test-unmanaged-store-2"
  1151. SecretName = "test-secret"
  1152. )
  1153. var PushSecretNamespace string
  1154. PushSecretStores := []string{ManagedPushSecretStore1, ManagedPushSecretStore2, UnmanagedPushSecretStore1, UnmanagedPushSecretStore2}
  1155. // if we are in debug and need to increase the timeout for testing, we can do so by using an env var
  1156. if customTimeout := os.Getenv("TEST_CUSTOM_TIMEOUT_SEC"); customTimeout != "" {
  1157. if t, err := strconv.Atoi(customTimeout); err == nil {
  1158. timeout = time.Second * time.Duration(t)
  1159. }
  1160. }
  1161. BeforeEach(func() {
  1162. var err error
  1163. PushSecretNamespace, err = ctest.CreateNamespace("test-ns", k8sClient)
  1164. Expect(err).ToNot(HaveOccurred())
  1165. fakeProvider.Reset()
  1166. })
  1167. AfterEach(func() {
  1168. k8sClient.Delete(context.Background(), &v1alpha1.PushSecret{
  1169. ObjectMeta: metav1.ObjectMeta{
  1170. Name: PushSecretName,
  1171. Namespace: PushSecretNamespace,
  1172. },
  1173. })
  1174. // give a time for reconciler to remove finalizers before removing SecretStores
  1175. // TODO: Secret Stores should have finalizers bound to PushSecrets if DeletionPolicy == Delete
  1176. time.Sleep(2 * time.Second)
  1177. for _, psstore := range PushSecretStores {
  1178. k8sClient.Delete(context.Background(), &esv1.SecretStore{
  1179. ObjectMeta: metav1.ObjectMeta{
  1180. Name: psstore,
  1181. Namespace: PushSecretNamespace,
  1182. },
  1183. })
  1184. k8sClient.Delete(context.Background(), &esv1.ClusterSecretStore{
  1185. ObjectMeta: metav1.ObjectMeta{
  1186. Name: psstore,
  1187. },
  1188. })
  1189. }
  1190. k8sClient.Delete(context.Background(), &v1.Secret{
  1191. ObjectMeta: metav1.ObjectMeta{
  1192. Name: SecretName,
  1193. Namespace: PushSecretNamespace,
  1194. },
  1195. })
  1196. Expect(k8sClient.Delete(context.Background(), &v1.Namespace{
  1197. ObjectMeta: metav1.ObjectMeta{
  1198. Name: PushSecretNamespace,
  1199. },
  1200. })).To(Succeed())
  1201. })
  1202. const (
  1203. defaultKey = "key"
  1204. defaultVal = "value"
  1205. defaultPath = "path/to/key"
  1206. )
  1207. makeDefaultTestcase := func() *testCase {
  1208. return &testCase{
  1209. pushsecret: &v1alpha1.PushSecret{
  1210. ObjectMeta: metav1.ObjectMeta{
  1211. Name: PushSecretName,
  1212. Namespace: PushSecretNamespace,
  1213. },
  1214. Spec: v1alpha1.PushSecretSpec{
  1215. SecretStoreRefs: []v1alpha1.PushSecretStoreRef{
  1216. {
  1217. Name: ManagedPushSecretStore1,
  1218. Kind: "SecretStore",
  1219. },
  1220. },
  1221. Selector: v1alpha1.PushSecretSelector{
  1222. Secret: &v1alpha1.PushSecretSecret{
  1223. Name: SecretName,
  1224. },
  1225. },
  1226. Data: []v1alpha1.PushSecretData{
  1227. {
  1228. Match: v1alpha1.PushSecretMatch{
  1229. SecretKey: defaultKey,
  1230. RemoteRef: v1alpha1.PushSecretRemoteRef{
  1231. RemoteKey: defaultPath,
  1232. },
  1233. },
  1234. },
  1235. },
  1236. },
  1237. },
  1238. secret: &v1.Secret{
  1239. ObjectMeta: metav1.ObjectMeta{
  1240. Name: SecretName,
  1241. Namespace: PushSecretNamespace,
  1242. },
  1243. Data: map[string][]byte{
  1244. defaultKey: []byte(defaultVal),
  1245. },
  1246. },
  1247. managedStore1: &esv1.SecretStore{
  1248. ObjectMeta: metav1.ObjectMeta{
  1249. Name: ManagedPushSecretStore1,
  1250. Namespace: PushSecretNamespace,
  1251. },
  1252. TypeMeta: metav1.TypeMeta{
  1253. Kind: "SecretStore",
  1254. },
  1255. Spec: esv1.SecretStoreSpec{
  1256. Provider: &esv1.SecretStoreProvider{
  1257. Fake: &esv1.FakeProvider{
  1258. Data: []esv1.FakeProviderData{},
  1259. },
  1260. },
  1261. },
  1262. },
  1263. managedStore2: &esv1.SecretStore{
  1264. ObjectMeta: metav1.ObjectMeta{
  1265. Name: ManagedPushSecretStore2,
  1266. Namespace: PushSecretNamespace,
  1267. },
  1268. TypeMeta: metav1.TypeMeta{
  1269. Kind: "SecretStore",
  1270. },
  1271. Spec: esv1.SecretStoreSpec{
  1272. Provider: &esv1.SecretStoreProvider{
  1273. Fake: &esv1.FakeProvider{
  1274. Data: []esv1.FakeProviderData{},
  1275. },
  1276. },
  1277. },
  1278. },
  1279. unmanagedStore1: &esv1.SecretStore{
  1280. ObjectMeta: metav1.ObjectMeta{
  1281. Name: UnmanagedPushSecretStore1,
  1282. Namespace: PushSecretNamespace,
  1283. },
  1284. TypeMeta: metav1.TypeMeta{
  1285. Kind: "SecretStore",
  1286. },
  1287. Spec: esv1.SecretStoreSpec{
  1288. Provider: &esv1.SecretStoreProvider{
  1289. Fake: &esv1.FakeProvider{
  1290. Data: []esv1.FakeProviderData{},
  1291. },
  1292. },
  1293. Controller: "not-managed",
  1294. },
  1295. },
  1296. unmanagedStore2: &esv1.SecretStore{
  1297. ObjectMeta: metav1.ObjectMeta{
  1298. Name: UnmanagedPushSecretStore2,
  1299. Namespace: PushSecretNamespace,
  1300. },
  1301. TypeMeta: metav1.TypeMeta{
  1302. Kind: "SecretStore",
  1303. },
  1304. Spec: esv1.SecretStoreSpec{
  1305. Provider: &esv1.SecretStoreProvider{
  1306. Fake: &esv1.FakeProvider{
  1307. Data: []esv1.FakeProviderData{},
  1308. },
  1309. },
  1310. Controller: "not-managed",
  1311. },
  1312. },
  1313. }
  1314. }
  1315. multipleManagedStoresSyncsSuccessfully := func(tc *testCase) {
  1316. fakeProvider.SetSecretFn = func() error {
  1317. return nil
  1318. }
  1319. tc.pushsecret.Spec.SecretStoreRefs = append(tc.pushsecret.Spec.SecretStoreRefs,
  1320. v1alpha1.PushSecretStoreRef{
  1321. Name: ManagedPushSecretStore2,
  1322. Kind: "SecretStore",
  1323. },
  1324. )
  1325. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1326. Eventually(func() bool {
  1327. By("checking if Provider value got updated")
  1328. secretValue := secret.Data[defaultKey]
  1329. providerValue, ok := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  1330. if !ok {
  1331. return false
  1332. }
  1333. got := providerValue.Value
  1334. return bytes.Equal(got, secretValue)
  1335. }, time.Second*10, time.Second).Should(BeTrue())
  1336. return true
  1337. }
  1338. }
  1339. skipUnmanagedStores := func(tc *testCase) {
  1340. tc.pushsecret.Spec.SecretStoreRefs = []v1alpha1.PushSecretStoreRef{
  1341. {
  1342. Name: UnmanagedPushSecretStore1,
  1343. Kind: "SecretStore",
  1344. },
  1345. {
  1346. Name: UnmanagedPushSecretStore2,
  1347. Kind: "SecretStore",
  1348. },
  1349. }
  1350. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1351. return len(ps.Status.Conditions) == 0
  1352. }
  1353. }
  1354. warnUnmanagedStoresAndSyncManagedStores := func(tc *testCase) {
  1355. fakeProvider.SetSecretFn = func() error {
  1356. return nil
  1357. }
  1358. tc.pushsecret.Spec.SecretStoreRefs = []v1alpha1.PushSecretStoreRef{
  1359. {
  1360. Name: ManagedPushSecretStore1,
  1361. Kind: "SecretStore",
  1362. },
  1363. {
  1364. Name: ManagedPushSecretStore2,
  1365. Kind: "SecretStore",
  1366. },
  1367. {
  1368. Name: UnmanagedPushSecretStore1,
  1369. Kind: "SecretStore",
  1370. },
  1371. {
  1372. Name: UnmanagedPushSecretStore2,
  1373. Kind: "SecretStore",
  1374. },
  1375. }
  1376. tc.assert = func(ps *v1alpha1.PushSecret, secret *v1.Secret) bool {
  1377. Eventually(func() bool {
  1378. By("checking if Provider value got updated")
  1379. secretValue := secret.Data[defaultKey]
  1380. providerValue, ok := fakeProvider.SetSecretArgs[ps.Spec.Data[0].Match.RemoteRef.RemoteKey]
  1381. if !ok {
  1382. return false
  1383. }
  1384. got := providerValue.Value
  1385. return bytes.Equal(got, secretValue)
  1386. }, time.Second*10, time.Second).Should(BeTrue())
  1387. return true
  1388. }
  1389. }
  1390. DescribeTable("When reconciling a PushSecret with multiple secret stores",
  1391. func(tweaks ...testTweaks) {
  1392. tc := makeDefaultTestcase()
  1393. for _, tweak := range tweaks {
  1394. tweak(tc)
  1395. }
  1396. ctx := context.Background()
  1397. By("creating secret stores, a secret and a pushsecret")
  1398. if tc.managedStore1 != nil {
  1399. Expect(k8sClient.Create(ctx, tc.managedStore1)).To(Succeed())
  1400. }
  1401. if tc.managedStore2 != nil {
  1402. Expect(k8sClient.Create(ctx, tc.managedStore2)).To(Succeed())
  1403. }
  1404. if tc.unmanagedStore1 != nil {
  1405. Expect(k8sClient.Create(ctx, tc.unmanagedStore1)).To(Succeed())
  1406. }
  1407. if tc.unmanagedStore2 != nil {
  1408. Expect(k8sClient.Create(ctx, tc.unmanagedStore2)).To(Succeed())
  1409. }
  1410. if tc.secret != nil {
  1411. Expect(k8sClient.Create(ctx, tc.secret)).To(Succeed())
  1412. }
  1413. if tc.pushsecret != nil {
  1414. Expect(k8sClient.Create(ctx, tc.pushsecret)).Should(Succeed())
  1415. }
  1416. time.Sleep(2 * time.Second) // prevents race conditions during tests causing failures
  1417. psKey := types.NamespacedName{Name: PushSecretName, Namespace: PushSecretNamespace}
  1418. createdPS := &v1alpha1.PushSecret{}
  1419. By("checking the pushSecret condition")
  1420. Eventually(func() bool {
  1421. err := k8sClient.Get(ctx, psKey, createdPS)
  1422. if err != nil {
  1423. return false
  1424. }
  1425. return tc.assert(createdPS, tc.secret)
  1426. }, timeout, interval).Should(BeTrue())
  1427. // this must be optional so we can test faulty es configuration
  1428. },
  1429. Entry("should sync successfully if there are multiple managed stores", multipleManagedStoresSyncsSuccessfully),
  1430. Entry("should skip unmanaged stores", skipUnmanagedStores),
  1431. Entry("should skip unmanaged stores and sync managed stores", warnUnmanagedStoresAndSyncManagedStores),
  1432. )
  1433. })