client_push_test.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  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 vault
  13. import (
  14. "context"
  15. "errors"
  16. "fmt"
  17. "strings"
  18. "testing"
  19. corev1 "k8s.io/api/core/v1"
  20. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  21. testingfake "github.com/external-secrets/external-secrets/pkg/provider/testing/fake"
  22. "github.com/external-secrets/external-secrets/pkg/provider/vault/fake"
  23. "github.com/external-secrets/external-secrets/pkg/provider/vault/util"
  24. )
  25. const (
  26. fakeKey = "fake-key"
  27. fakeValue = "fake-value"
  28. managedBy = "managed-by"
  29. managedByESO = "external-secrets"
  30. )
  31. func TestDeleteSecret(t *testing.T) {
  32. type args struct {
  33. store *esv1.VaultProvider
  34. vLogical util.Logical
  35. }
  36. type want struct {
  37. err error
  38. }
  39. tests := map[string]struct {
  40. reason string
  41. args args
  42. ref *testingfake.PushSecretData
  43. want want
  44. value []byte
  45. }{
  46. "DeleteSecretNoOpKV1": {
  47. reason: "delete secret is a no-op if v1 secret does not exist",
  48. args: args{
  49. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV1).Spec.Provider.Vault,
  50. vLogical: &fake.Logical{
  51. ReadWithDataWithContextFn: fake.NewReadWithContextFn(nil, nil),
  52. WriteWithContextFn: fake.ExpectWriteWithContextNoCall(),
  53. DeleteWithContextFn: fake.ExpectDeleteWithContextNoCall(),
  54. },
  55. },
  56. want: want{
  57. err: nil,
  58. },
  59. },
  60. "DeleteSecretNoOpKV2": {
  61. reason: "delete secret is a no-op if v2 secret does not exist",
  62. args: args{
  63. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV2).Spec.Provider.Vault,
  64. vLogical: &fake.Logical{
  65. ReadWithDataWithContextFn: fake.NewReadWithContextFn(nil, nil),
  66. WriteWithContextFn: fake.ExpectWriteWithContextNoCall(),
  67. DeleteWithContextFn: fake.ExpectDeleteWithContextNoCall(),
  68. },
  69. },
  70. want: want{
  71. err: nil,
  72. },
  73. },
  74. "DeleteSecretFailIfErrorKV1": {
  75. reason: "delete v1 secret fails if error occurs",
  76. args: args{
  77. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV1).Spec.Provider.Vault,
  78. vLogical: &fake.Logical{
  79. ReadWithDataWithContextFn: fake.NewReadWithContextFn(nil, errors.New("failed to read")),
  80. WriteWithContextFn: fake.ExpectWriteWithContextNoCall(),
  81. DeleteWithContextFn: fake.ExpectDeleteWithContextNoCall(),
  82. },
  83. },
  84. want: want{
  85. err: errors.New("failed to read"),
  86. },
  87. },
  88. "DeleteSecretFailIfErrorKV2": {
  89. reason: "delete v2 secret fails if error occurs",
  90. args: args{
  91. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV2).Spec.Provider.Vault,
  92. vLogical: &fake.Logical{
  93. ReadWithDataWithContextFn: fake.NewReadWithContextFn(nil, errors.New("failed to read")),
  94. WriteWithContextFn: fake.ExpectWriteWithContextNoCall(),
  95. DeleteWithContextFn: fake.ExpectDeleteWithContextNoCall(),
  96. },
  97. },
  98. want: want{
  99. err: errors.New("failed to read"),
  100. },
  101. },
  102. "DeleteSecretNotManagedKV1": {
  103. reason: "delete v1 secret when not managed by ESO",
  104. args: args{
  105. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV1).Spec.Provider.Vault,
  106. vLogical: &fake.Logical{
  107. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  108. fakeKey: fakeValue,
  109. "custom_metadata": map[string]any{
  110. managedBy: "another-secret-tool",
  111. },
  112. }, nil),
  113. WriteWithContextFn: fake.ExpectWriteWithContextNoCall(),
  114. DeleteWithContextFn: fake.NewDeleteWithContextFn(nil, nil),
  115. },
  116. },
  117. want: want{
  118. err: nil,
  119. },
  120. },
  121. "DeleteSecretNotManagedKV2": {
  122. reason: "delete v2 secret when not managed by eso",
  123. args: args{
  124. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV2).Spec.Provider.Vault,
  125. vLogical: &fake.Logical{
  126. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  127. "data": map[string]any{
  128. fakeKey: fakeValue,
  129. },
  130. "custom_metadata": map[string]any{
  131. managedBy: "another-secret-tool",
  132. },
  133. }, nil),
  134. WriteWithContextFn: fake.ExpectWriteWithContextNoCall(),
  135. DeleteWithContextFn: fake.NewDeleteWithContextFn(nil, nil),
  136. },
  137. },
  138. want: want{
  139. err: nil,
  140. },
  141. },
  142. "DeleteSecretSuccessKV1": {
  143. reason: "delete secret succeeds if secret is managed by ESO and exists in vault v1",
  144. args: args{
  145. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV1).Spec.Provider.Vault,
  146. vLogical: &fake.Logical{
  147. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  148. fakeKey: fakeValue,
  149. "custom_metadata": map[string]any{
  150. managedBy: managedByESO,
  151. },
  152. }, nil),
  153. WriteWithContextFn: fake.ExpectWriteWithContextNoCall(),
  154. DeleteWithContextFn: fake.NewDeleteWithContextFn(nil, nil),
  155. },
  156. },
  157. want: want{
  158. err: nil,
  159. },
  160. },
  161. "DeleteSecretSuccessKV2": {
  162. reason: "delete secret succeeds if secret is managed by ESO and exists in vault v2",
  163. args: args{
  164. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV2).Spec.Provider.Vault,
  165. vLogical: &fake.Logical{
  166. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  167. "data": map[string]any{
  168. fakeKey: fakeValue,
  169. },
  170. "custom_metadata": map[string]any{
  171. managedBy: managedByESO,
  172. },
  173. }, nil),
  174. WriteWithContextFn: fake.ExpectWriteWithContextNoCall(),
  175. DeleteWithContextFn: fake.NewDeleteWithContextFn(nil, nil),
  176. },
  177. },
  178. want: want{
  179. err: nil,
  180. },
  181. },
  182. "DeleteSecretErrorKV1": {
  183. reason: "delete secret fails if error occurs v1",
  184. args: args{
  185. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV1).Spec.Provider.Vault,
  186. vLogical: &fake.Logical{
  187. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  188. fakeKey: fakeValue,
  189. "custom_metadata": map[string]any{
  190. managedBy: managedByESO,
  191. },
  192. }, nil),
  193. WriteWithContextFn: fake.ExpectWriteWithContextNoCall(),
  194. DeleteWithContextFn: fake.NewDeleteWithContextFn(nil, errors.New("failed to delete")),
  195. },
  196. },
  197. want: want{
  198. err: errors.New("failed to delete"),
  199. },
  200. },
  201. "DeleteSecretErrorKV2": {
  202. reason: "delete secret fails if error occurs v2",
  203. args: args{
  204. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV2).Spec.Provider.Vault,
  205. vLogical: &fake.Logical{
  206. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  207. "data": map[string]any{
  208. fakeKey: fakeValue,
  209. },
  210. "custom_metadata": map[string]any{
  211. managedBy: managedByESO,
  212. },
  213. }, nil),
  214. WriteWithContextFn: fake.ExpectWriteWithContextNoCall(),
  215. DeleteWithContextFn: fake.NewDeleteWithContextFn(nil, errors.New("failed to delete")),
  216. },
  217. },
  218. want: want{
  219. err: errors.New("failed to delete"),
  220. },
  221. },
  222. "DeleteSecretUpdatePropertyKV1": {
  223. reason: "Secret should only be updated if Property is set v1",
  224. ref: &testingfake.PushSecretData{RemoteKey: "secret", Property: fakeKey},
  225. args: args{
  226. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV1).Spec.Provider.Vault,
  227. vLogical: &fake.Logical{
  228. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  229. fakeKey: fakeValue,
  230. "foo": "bar",
  231. "custom_metadata": map[string]any{
  232. managedBy: managedByESO,
  233. },
  234. }, nil),
  235. WriteWithContextFn: fake.ExpectWriteWithContextValue(map[string]any{
  236. "foo": "bar",
  237. "custom_metadata": map[string]any{
  238. managedBy: managedByESO,
  239. }}),
  240. DeleteWithContextFn: fake.ExpectDeleteWithContextNoCall(),
  241. },
  242. },
  243. want: want{
  244. err: nil,
  245. },
  246. },
  247. "DeleteSecretUpdatePropertyKV2": {
  248. reason: "Secret should only be updated if Property is set v2",
  249. ref: &testingfake.PushSecretData{RemoteKey: "secret", Property: fakeKey},
  250. args: args{
  251. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV2).Spec.Provider.Vault,
  252. vLogical: &fake.Logical{
  253. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  254. "data": map[string]any{
  255. fakeKey: fakeValue,
  256. "foo": "bar",
  257. },
  258. "custom_metadata": map[string]any{
  259. managedBy: managedByESO,
  260. },
  261. }, nil),
  262. WriteWithContextFn: fake.ExpectWriteWithContextValue(map[string]any{"data": map[string]any{"foo": "bar"}}),
  263. DeleteWithContextFn: fake.ExpectDeleteWithContextNoCall(),
  264. },
  265. },
  266. want: want{
  267. err: nil,
  268. },
  269. },
  270. "DeleteSecretIfNoOtherPropertiesKV1": {
  271. reason: "Secret should only be deleted if no other properties are set v1",
  272. ref: &testingfake.PushSecretData{RemoteKey: "secret", Property: "foo"},
  273. args: args{
  274. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV1).Spec.Provider.Vault,
  275. vLogical: &fake.Logical{
  276. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  277. "foo": "bar",
  278. "custom_metadata": map[string]any{
  279. managedBy: managedByESO,
  280. },
  281. }, nil),
  282. WriteWithContextFn: fake.ExpectWriteWithContextNoCall(),
  283. DeleteWithContextFn: fake.NewDeleteWithContextFn(nil, nil),
  284. },
  285. },
  286. want: want{
  287. err: nil,
  288. },
  289. },
  290. "DeleteSecretIfNoOtherPropertiesKV2": {
  291. reason: "Secret should only be deleted if no other properties are set v2",
  292. ref: &testingfake.PushSecretData{RemoteKey: "secret", Property: "foo"},
  293. args: args{
  294. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV2).Spec.Provider.Vault,
  295. vLogical: &fake.Logical{
  296. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  297. "data": map[string]any{
  298. "foo": "bar",
  299. },
  300. "custom_metadata": map[string]any{
  301. managedBy: managedByESO,
  302. },
  303. }, nil),
  304. WriteWithContextFn: fake.ExpectWriteWithContextNoCall(),
  305. DeleteWithContextFn: fake.NewDeleteWithContextFn(nil, nil),
  306. },
  307. },
  308. want: want{
  309. err: nil,
  310. },
  311. },
  312. }
  313. for name, tc := range tests {
  314. t.Run(name, func(t *testing.T) {
  315. ref := testingfake.PushSecretData{RemoteKey: "secret", Property: ""}
  316. if tc.ref != nil {
  317. ref = *tc.ref
  318. }
  319. client := &client{
  320. logical: tc.args.vLogical,
  321. store: tc.args.store,
  322. }
  323. err := client.DeleteSecret(context.Background(), ref)
  324. // Error nil XOR tc.want.err nil
  325. if ((err == nil) || (tc.want.err == nil)) && !((err == nil) && (tc.want.err == nil)) {
  326. t.Errorf("\nTesting DeleteSecret:\nName: %v\nReason: %v\nWant error: %v\nGot error: %v", name, tc.reason, tc.want.err, err)
  327. }
  328. // if errors are the same type but their contents do not match
  329. if err != nil && tc.want.err != nil {
  330. if !strings.Contains(err.Error(), tc.want.err.Error()) {
  331. t.Errorf("\nTesting DeleteSecret:\nName: %v\nReason: %v\nWant error: %v\nGot error got nil", name, tc.reason, tc.want.err)
  332. }
  333. }
  334. })
  335. }
  336. }
  337. func TestPushSecret(t *testing.T) {
  338. secretKey := "secret-key"
  339. noPermission := errors.New("no permission")
  340. type args struct {
  341. store *esv1.VaultProvider
  342. vLogical util.Logical
  343. }
  344. type want struct {
  345. err error
  346. }
  347. tests := map[string]struct {
  348. reason string
  349. args args
  350. want want
  351. data *testingfake.PushSecretData
  352. value []byte
  353. secret *corev1.Secret
  354. }{
  355. "SetSecretKV1": {
  356. reason: "secret is successfully set, with no existing vault secret",
  357. args: args{
  358. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV1).Spec.Provider.Vault,
  359. vLogical: &fake.Logical{
  360. ReadWithDataWithContextFn: fake.NewReadWithContextFn(nil, nil),
  361. WriteWithContextFn: fake.NewWriteWithContextFn(nil, nil),
  362. },
  363. },
  364. want: want{
  365. err: nil,
  366. },
  367. },
  368. "SetSecretKV2": {
  369. reason: "secret is successfully set, with no existing vault secret",
  370. args: args{
  371. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV2).Spec.Provider.Vault,
  372. vLogical: &fake.Logical{
  373. ReadWithDataWithContextFn: fake.NewReadWithContextFn(nil, nil),
  374. WriteWithContextFn: fake.NewWriteWithContextFn(nil, nil),
  375. },
  376. },
  377. want: want{
  378. err: nil,
  379. },
  380. },
  381. "SetSecretWithWriteErrorKV1": {
  382. reason: "secret cannot be pushed if write fails",
  383. args: args{
  384. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV1).Spec.Provider.Vault,
  385. vLogical: &fake.Logical{
  386. ReadWithDataWithContextFn: fake.NewReadWithContextFn(nil, nil),
  387. WriteWithContextFn: fake.NewWriteWithContextFn(nil, noPermission),
  388. },
  389. },
  390. want: want{
  391. err: noPermission,
  392. },
  393. },
  394. "SetSecretWithWriteErrorKV2": {
  395. reason: "secret cannot be pushed if write fails",
  396. args: args{
  397. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV2).Spec.Provider.Vault,
  398. vLogical: &fake.Logical{
  399. ReadWithDataWithContextFn: fake.NewReadWithContextFn(nil, nil),
  400. WriteWithContextFn: fake.NewWriteWithContextFn(nil, noPermission),
  401. },
  402. },
  403. want: want{
  404. err: noPermission,
  405. },
  406. },
  407. "SetSecretEqualsPushSecretV1": {
  408. reason: "vault secret kv equals secret to push kv",
  409. args: args{
  410. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV1).Spec.Provider.Vault,
  411. vLogical: &fake.Logical{
  412. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  413. fakeKey: fakeValue,
  414. "custom_metadata": map[string]any{
  415. managedBy: managedByESO,
  416. },
  417. }, nil),
  418. },
  419. },
  420. want: want{
  421. err: nil,
  422. },
  423. },
  424. "SetSecretEqualsPushSecretV2": {
  425. reason: "vault secret kv equals secret to push kv",
  426. args: args{
  427. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV2).Spec.Provider.Vault,
  428. vLogical: &fake.Logical{
  429. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  430. "data": map[string]any{
  431. fakeKey: fakeValue,
  432. },
  433. "custom_metadata": map[string]any{
  434. managedBy: managedByESO,
  435. },
  436. }, nil),
  437. },
  438. },
  439. want: want{
  440. err: nil,
  441. },
  442. },
  443. "PushSecretPropertyKV1": {
  444. reason: "push secret with property adds the property",
  445. value: []byte(fakeValue),
  446. data: &testingfake.PushSecretData{SecretKey: secretKey, RemoteKey: "secret", Property: "foo"},
  447. args: args{
  448. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV1).Spec.Provider.Vault,
  449. vLogical: &fake.Logical{
  450. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  451. fakeKey: fakeValue,
  452. "custom_metadata": map[string]any{
  453. managedBy: managedByESO,
  454. },
  455. }, nil),
  456. WriteWithContextFn: fake.ExpectWriteWithContextValue(map[string]any{
  457. fakeKey: fakeValue,
  458. "custom_metadata": map[string]string{
  459. managedBy: managedByESO,
  460. },
  461. "foo": fakeValue,
  462. }),
  463. },
  464. },
  465. want: want{
  466. err: nil,
  467. },
  468. },
  469. "PushSecretPropertyKV2": {
  470. reason: "push secret with property adds the property",
  471. value: []byte(fakeValue),
  472. data: &testingfake.PushSecretData{SecretKey: secretKey, RemoteKey: "secret", Property: "foo"},
  473. args: args{
  474. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV2).Spec.Provider.Vault,
  475. vLogical: &fake.Logical{
  476. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  477. "data": map[string]any{
  478. fakeKey: fakeValue,
  479. },
  480. "custom_metadata": map[string]any{
  481. managedBy: managedByESO,
  482. },
  483. }, nil),
  484. WriteWithContextFn: fake.ExpectWriteWithContextValue(map[string]any{"data": map[string]any{fakeKey: fakeValue, "foo": fakeValue}}),
  485. },
  486. },
  487. want: want{
  488. err: nil,
  489. },
  490. },
  491. "PushSecretUpdatePropertyKV1": {
  492. reason: "push secret with property only updates the property",
  493. value: []byte("new-value"),
  494. data: &testingfake.PushSecretData{SecretKey: secretKey, RemoteKey: "secret", Property: "foo"},
  495. args: args{
  496. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV1).Spec.Provider.Vault,
  497. vLogical: &fake.Logical{
  498. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  499. "foo": fakeValue,
  500. "custom_metadata": map[string]any{
  501. managedBy: managedByESO,
  502. },
  503. }, nil),
  504. WriteWithContextFn: fake.ExpectWriteWithContextValue(map[string]any{
  505. "foo": "new-value",
  506. "custom_metadata": map[string]string{
  507. managedBy: managedByESO,
  508. },
  509. }),
  510. },
  511. },
  512. want: want{
  513. err: nil,
  514. },
  515. },
  516. "PushSecretUpdatePropertyKV2": {
  517. reason: "push secret with property only updates the property",
  518. value: []byte("new-value"),
  519. data: &testingfake.PushSecretData{SecretKey: secretKey, RemoteKey: "secret", Property: "foo"},
  520. args: args{
  521. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV2).Spec.Provider.Vault,
  522. vLogical: &fake.Logical{
  523. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  524. "data": map[string]any{
  525. "foo": fakeValue,
  526. },
  527. "custom_metadata": map[string]any{
  528. managedBy: managedByESO,
  529. },
  530. }, nil),
  531. WriteWithContextFn: fake.ExpectWriteWithContextValue(map[string]any{"data": map[string]any{"foo": "new-value"}}),
  532. },
  533. },
  534. want: want{
  535. err: nil,
  536. },
  537. },
  538. "PushSecretPropertyNoUpdateKV1": {
  539. reason: "push secret with property only updates the property",
  540. value: []byte(fakeValue),
  541. data: &testingfake.PushSecretData{SecretKey: secretKey, RemoteKey: "secret", Property: "foo"},
  542. args: args{
  543. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV1).Spec.Provider.Vault,
  544. vLogical: &fake.Logical{
  545. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  546. "foo": fakeValue,
  547. "custom_metadata": map[string]any{
  548. managedBy: managedByESO,
  549. },
  550. }, nil),
  551. WriteWithContextFn: fake.ExpectWriteWithContextNoCall(),
  552. },
  553. },
  554. want: want{
  555. err: nil,
  556. },
  557. },
  558. "PushSecretPropertyNoUpdateKV2": {
  559. reason: "push secret with property only updates the property",
  560. value: []byte(fakeValue),
  561. data: &testingfake.PushSecretData{SecretKey: secretKey, RemoteKey: "secret", Property: "foo"},
  562. args: args{
  563. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV2).Spec.Provider.Vault,
  564. vLogical: &fake.Logical{
  565. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  566. "data": map[string]any{
  567. "foo": fakeValue,
  568. },
  569. "custom_metadata": map[string]any{
  570. managedBy: managedByESO,
  571. },
  572. }, nil),
  573. WriteWithContextFn: fake.ExpectWriteWithContextNoCall(),
  574. },
  575. },
  576. want: want{
  577. err: nil,
  578. },
  579. },
  580. "SetSecretErrorReadingSecretKV1": {
  581. reason: "error occurs if secret cannot be read",
  582. args: args{
  583. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV1).Spec.Provider.Vault,
  584. vLogical: &fake.Logical{
  585. ReadWithDataWithContextFn: fake.NewReadWithContextFn(nil, noPermission),
  586. },
  587. },
  588. want: want{
  589. err: fmt.Errorf(errReadSecret, noPermission),
  590. },
  591. },
  592. "SetSecretErrorReadingSecretKV2": {
  593. reason: "error occurs if secret cannot be read",
  594. args: args{
  595. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV2).Spec.Provider.Vault,
  596. vLogical: &fake.Logical{
  597. ReadWithDataWithContextFn: fake.NewReadWithContextFn(nil, noPermission),
  598. },
  599. },
  600. want: want{
  601. err: fmt.Errorf(errReadSecret, noPermission),
  602. },
  603. },
  604. "SetSecretNotManagedByESOV1": {
  605. reason: "a secret not managed by ESO cannot be updated",
  606. args: args{
  607. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV1).Spec.Provider.Vault,
  608. vLogical: &fake.Logical{
  609. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  610. fakeKey: "fake-value2",
  611. "custom_metadata": map[string]any{
  612. managedBy: "not-external-secrets",
  613. },
  614. }, nil),
  615. },
  616. },
  617. want: want{
  618. err: errors.New("secret not managed by external-secrets"),
  619. },
  620. },
  621. "SetSecretNotManagedByESOV2": {
  622. reason: "a secret not managed by ESO cannot be updated",
  623. args: args{
  624. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV2).Spec.Provider.Vault,
  625. vLogical: &fake.Logical{
  626. ReadWithDataWithContextFn: fake.NewReadWithContextFn(map[string]any{
  627. "data": map[string]any{
  628. fakeKey: "fake-value2",
  629. "custom_metadata": map[string]any{
  630. managedBy: "not-external-secrets",
  631. },
  632. },
  633. }, nil),
  634. },
  635. },
  636. want: want{
  637. err: errors.New("secret not managed by external-secrets"),
  638. },
  639. },
  640. "WholeSecretKV2": {
  641. reason: "secret is successfully set, with no existing vault secret",
  642. args: args{
  643. store: makeValidSecretStoreWithVersion(esv1.VaultKVStoreV2).Spec.Provider.Vault,
  644. vLogical: &fake.Logical{
  645. ReadWithDataWithContextFn: fake.NewReadWithContextFn(nil, nil),
  646. WriteWithContextFn: fake.ExpectWriteWithContextValue(map[string]any{"data": map[string]any{"key1": "value1", "key2": "value2"}}),
  647. },
  648. },
  649. data: &testingfake.PushSecretData{SecretKey: "", RemoteKey: "secret", Property: ""},
  650. secret: &corev1.Secret{Data: map[string][]byte{"key1": []byte(`value1`), "key2": []byte(`value2`)}},
  651. want: want{
  652. err: nil,
  653. },
  654. },
  655. }
  656. for name, tc := range tests {
  657. t.Run(name, func(t *testing.T) {
  658. data := testingfake.PushSecretData{SecretKey: secretKey, RemoteKey: "secret", Property: ""}
  659. if tc.data != nil {
  660. data = *tc.data
  661. }
  662. client := &client{
  663. logical: tc.args.vLogical,
  664. store: tc.args.store,
  665. }
  666. s := tc.secret
  667. if s == nil {
  668. val := tc.value
  669. if val == nil {
  670. val = []byte(`{"fake-key":"fake-value"}`)
  671. }
  672. s = &corev1.Secret{Data: map[string][]byte{secretKey: val}}
  673. }
  674. err := client.PushSecret(context.Background(), s, data)
  675. // Error nil XOR tc.want.err nil
  676. if ((err == nil) || (tc.want.err == nil)) && !((err == nil) && (tc.want.err == nil)) {
  677. t.Errorf("\nTesting SetSecret:\nName: %v\nReason: %v\nWant error: %v\nGot error: %v", name, tc.reason, tc.want.err, err)
  678. }
  679. // if errors are the same type but their contents do not match
  680. if err != nil && tc.want.err != nil {
  681. if !strings.Contains(err.Error(), tc.want.err.Error()) {
  682. t.Errorf("\nTesting SetSecret:\nName: %v\nReason: %v\nWant error: %v\nGot error got nil", name, tc.reason, tc.want.err)
  683. }
  684. }
  685. })
  686. }
  687. }