pushsecret_controller_test.go 48 KB

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