webhook_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  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 webhook
  13. import (
  14. "bytes"
  15. "context"
  16. "errors"
  17. "io"
  18. "net/http"
  19. "net/http/httptest"
  20. "strings"
  21. "testing"
  22. "time"
  23. "gopkg.in/yaml.v3"
  24. corev1 "k8s.io/api/core/v1"
  25. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  26. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  27. "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
  28. )
  29. type testCase struct {
  30. Case string `json:"case,omitempty"`
  31. Args args `json:"args"`
  32. Want want `json:"want"`
  33. }
  34. type secret struct {
  35. Name string `json:"name"`
  36. Data map[string]string `json:"data"`
  37. }
  38. type args struct {
  39. URL string `json:"url,omitempty"`
  40. Body string `json:"body,omitempty"`
  41. Timeout string `json:"timeout,omitempty"`
  42. Key string `json:"key,omitempty"`
  43. SecretKey string `json:"secretkey,omitempty"`
  44. Property string `json:"property,omitempty"`
  45. Version string `json:"version,omitempty"`
  46. JSONPath string `json:"jsonpath,omitempty"`
  47. Response string `json:"response,omitempty"`
  48. StatusCode int `json:"statuscode,omitempty"`
  49. PushSecret bool `json:"pushsecret,omitempty"`
  50. Secret secret `json:"secret,omitempty"`
  51. }
  52. type want struct {
  53. Path string `json:"path,omitempty"`
  54. Body *string `json:"body,omitempty"`
  55. Err string `json:"err,omitempty"`
  56. Result string `json:"result,omitempty"`
  57. ResultMap map[string]string `json:"resultmap,omitempty"`
  58. }
  59. var testCases = `
  60. case: error url
  61. args:
  62. url: /api/getsecret?id={{ .unclosed.template
  63. want:
  64. err: failed to parse url
  65. ---
  66. case: error body
  67. args:
  68. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  69. body: Body error {{ .unclosed.template
  70. want:
  71. err: failed to parse body
  72. ---
  73. case: error connection
  74. args:
  75. url: 1/api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  76. want:
  77. err: failed to call endpoint
  78. ---
  79. case: error no secret err
  80. args:
  81. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  82. key: testkey
  83. version: 1
  84. statuscode: 404
  85. response: not found
  86. want:
  87. path: /api/getsecret?id=testkey&version=1
  88. err: ` + esv1.NoSecretErr.Error() + `
  89. ---
  90. case: error server error
  91. args:
  92. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  93. key: testkey
  94. version: 1
  95. statuscode: 500
  96. response: server error
  97. want:
  98. path: /api/getsecret?id=testkey&version=1
  99. err: endpoint gave error 500
  100. ---
  101. case: error bad json
  102. args:
  103. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  104. key: testkey
  105. version: 1
  106. jsonpath: $.result.thesecret
  107. response: '{"result":{"thesecret":"secret-value"}'
  108. want:
  109. path: /api/getsecret?id=testkey&version=1
  110. err: failed to parse response json
  111. ---
  112. case: error bad jsonpath
  113. args:
  114. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  115. key: testkey
  116. version: 1
  117. jsonpath: $.result.thesecret
  118. response: '{"result":{"nosecret":"secret-value"}}'
  119. want:
  120. path: /api/getsecret?id=testkey&version=1
  121. err: failed to get response path
  122. ---
  123. case: pull data out of map
  124. args:
  125. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  126. key: testkey
  127. version: 1
  128. jsonpath: $.result.thesecret
  129. response: '{"result":{"thesecret":{"one":"secret-value"}}}'
  130. want:
  131. path: /api/getsecret?id=testkey&version=1
  132. err: ''
  133. result: '{"one":"secret-value"}'
  134. ---
  135. case: error timeout
  136. args:
  137. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  138. key: testkey
  139. version: 1
  140. response: secret-value
  141. timeout: 0.01ms
  142. want:
  143. path: /api/getsecret?id=testkey&version=1
  144. err: context deadline exceeded
  145. ---
  146. case: good plaintext
  147. args:
  148. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  149. key: testkey
  150. version: 1
  151. response: secret-value
  152. want:
  153. path: /api/getsecret?id=testkey&version=1
  154. err: ''
  155. result: secret-value
  156. ---
  157. case: good json
  158. args:
  159. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  160. key: testkey
  161. version: 1
  162. jsonpath: $.result.thesecret
  163. response: '{"result":{"thesecret":"secret-value"}}'
  164. want:
  165. path: /api/getsecret?id=testkey&version=1
  166. err: ''
  167. result: secret-value
  168. ---
  169. case: good json map
  170. args:
  171. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  172. key: testkey
  173. version: 1
  174. jsonpath: $.result
  175. response: '{"result":{"thesecret":"secret-value","alsosecret":"another-value"}}'
  176. want:
  177. path: /api/getsecret?id=testkey&version=1
  178. err: ''
  179. resultmap:
  180. thesecret: secret-value
  181. alsosecret: another-value
  182. ---
  183. case: templated jsonpath good json map
  184. args:
  185. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  186. key: testkey
  187. version: 1
  188. jsonpath: $.{{printf "result" }}
  189. response: '{"result":{"thesecret":"secret-value","alsosecret":"another-value"}}'
  190. want:
  191. path: /api/getsecret?id=testkey&version=1
  192. err: ''
  193. resultmap:
  194. thesecret: secret-value
  195. alsosecret: another-value
  196. ---
  197. case: templated jsonpath invalid template
  198. args:
  199. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  200. key: testkey
  201. version: 1
  202. jsonpath: $.{{printf 'result' }}
  203. response: '{"result":{"thesecret":"secret-value","alsosecret":"another-value"}}'
  204. want:
  205. path: /api/getsecret?id=testkey&version=1
  206. err: "cannot get templated json path"
  207. resultmap:
  208. thesecret: secret-value
  209. alsosecret: another-value
  210. ---
  211. case: good json map string
  212. args:
  213. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  214. key: testkey
  215. version: 1
  216. response: '{"thesecret":"secret-value","alsosecret":"another-value"}'
  217. want:
  218. path: /api/getsecret?id=testkey&version=1
  219. err: ''
  220. resultmap:
  221. thesecret: secret-value
  222. alsosecret: another-value
  223. ---
  224. case: error json map string
  225. args:
  226. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  227. key: testkey
  228. version: 1
  229. response: 'some simple string'
  230. want:
  231. path: /api/getsecret?id=testkey&version=1
  232. err: "failed to parse response json: invalid character"
  233. resultmap: {}
  234. ---
  235. case: error json map
  236. args:
  237. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  238. key: testkey
  239. version: 1
  240. jsonpath: $.result.thesecret
  241. response: '{"result":{"thesecret":"secret-value","alsosecret":"another-value"}}'
  242. want:
  243. path: /api/getsecret?id=testkey&version=1
  244. err: "failed to parse response json from jsonpath"
  245. resultmap: {}
  246. ---
  247. case: good json with good templated jsonpath
  248. args:
  249. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  250. key: testkey
  251. property: thesecret
  252. version: 1
  253. jsonpath: $.result.{{ .remoteRef.property }}
  254. response: '{"result":{"thesecret":"secret-value"}}'
  255. want:
  256. path: /api/getsecret?id=testkey&version=1
  257. err: ''
  258. result: secret-value
  259. ---
  260. case: good json with jsonpath filter
  261. args:
  262. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  263. key: testkey
  264. version: 1
  265. jsonpath: $.secrets[?@.name=="thesecret"].value
  266. response: '{"secrets": [{"name": "thesecret", "value": "secret-value"}, {"name": "alsosecret", "value": "another-value"}]}'
  267. want:
  268. path: /api/getsecret?id=testkey&version=1
  269. err: ''
  270. result: secret-value
  271. ---
  272. case: good json with bad templated jsonpath
  273. args:
  274. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  275. key: testkey
  276. property: thesecret
  277. version: 1
  278. jsonpath: $.result.{{ .remoteRef.property }
  279. response: '{"result":{"thesecret":"secret-value"}}'
  280. want:
  281. path: /api/getsecret?id=testkey&version=1
  282. err: 'template: webhooktemplate:1: unexpected "}" in operand'
  283. ---
  284. case: error with jsonpath filter empty results
  285. args:
  286. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  287. key: testkey
  288. version: 1
  289. jsonpath: $.secrets[?@.name=="thebadsecret"].value
  290. response: '{"secrets": [{"name": "thesecret", "value": "secret-value"}, {"name": "alsosecret", "value": "another-value"}]}'
  291. want:
  292. path: /api/getsecret?id=testkey&version=1
  293. err: "filter worked but didn't get any result"
  294. ---
  295. case: success with jsonpath filter and result array
  296. args:
  297. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  298. key: testkey
  299. version: 1
  300. jsonpath: $..name
  301. response: '{"secrets": [{"name": "thesecret", "value": "secret-value"}, {"name": "alsosecret", "value": "another-value"}]}'
  302. want:
  303. path: /api/getsecret?id=testkey&version=1
  304. err: ''
  305. result: 'thesecret'
  306. ---
  307. case: success with jsonpath filter and result array of ints
  308. args:
  309. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  310. key: testkey
  311. version: 1
  312. jsonpath: $..name
  313. response: '{"secrets": [{"name": 123, "value": "secret-value"}, {"name": 456, "value": "another-value"}]}'
  314. want:
  315. path: /api/getsecret?id=testkey&version=1
  316. err: ''
  317. result: 123
  318. ---
  319. case: support backslash
  320. args:
  321. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  322. key: testkey
  323. version: 1
  324. jsonpath: $.refresh_token
  325. response: '{"access_token":"REDACTED","refresh_token":"RE\/DACTED=="}'
  326. want:
  327. path: /api/getsecret?id=testkey&version=1
  328. err: ''
  329. result: "RE/DACTED=="
  330. ---
  331. case: good json with mixed fields and jsonpath filter
  332. args:
  333. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  334. key: testkey
  335. version: 1
  336. jsonpath: $.result.thesecret
  337. response: '{"result":{"thesecret":"secret-value","alsosecret":"another-value", "id": 1234, "weight": 1.5}}'
  338. want:
  339. path: /api/getsecret?id=testkey&version=1
  340. err: ''
  341. result: secret-value
  342. ---
  343. case: good json with mixed fields to map
  344. args:
  345. url: /api/getsecret?id={{ .remoteRef.key }}&version={{ .remoteRef.version }}
  346. key: testkey
  347. version: 1
  348. jsonpath: $.result
  349. response: '{"result":{"thesecret":"secret-value","alsosecret":"another-value", "id": 1234, "weight": 1.5}}'
  350. want:
  351. path: /api/getsecret?id=testkey&version=1
  352. err: ''
  353. resultmap:
  354. thesecret: secret-value
  355. alsosecret: another-value
  356. id: 1234
  357. weight: 1.5
  358. ---
  359. case: only url encoding for url templates
  360. args:
  361. url: /api/getsecrets?folder={{ .remoteRef.key }}
  362. body: '{"folder": "{{ .remoteRef.key }}"}'
  363. key: /myapp/secrets
  364. want:
  365. path: /api/getsecrets?folder=%2Fmyapp%2Fsecrets
  366. body: '{"folder": "/myapp/secrets"}'
  367. `
  368. func TestWebhookGetSecret(t *testing.T) {
  369. ydec := yaml.NewDecoder(bytes.NewReader([]byte(testCases)))
  370. for {
  371. var tc testCase
  372. if err := ydec.Decode(&tc); err != nil {
  373. if !errors.Is(err, io.EOF) {
  374. t.Errorf("testcase decode error %v", err)
  375. }
  376. break
  377. }
  378. runTestCase(tc, t)
  379. }
  380. }
  381. var testCasesPushSecret = `
  382. ---
  383. case: secret key not found
  384. args:
  385. url: /api/pushsecret?id={{ .remoteRef.remoteKey }}&secret={{ .remoteRef.secretKey }}
  386. key: testkey
  387. secretkey: not-found
  388. pushsecret: true
  389. secret:
  390. name: test-secret
  391. data:
  392. secretkey: value
  393. want:
  394. path: /api/pushsecret?id=testkey&secret=not-found
  395. err: 'failed to find secret key in secret with key: not-found'
  396. ---
  397. case: default body good json
  398. args:
  399. url: /api/pushsecret?id={{ .remoteRef.remoteKey }}&secret={{ .remoteRef.secretKey }}
  400. key: testkey
  401. secretkey: secretkey
  402. pushsecret: true
  403. secret:
  404. name: test-secret
  405. data:
  406. secretkey: value
  407. want:
  408. path: /api/pushsecret?id=testkey&secret=secretkey
  409. body: 'value'
  410. err: ''
  411. ---
  412. case: good json
  413. args:
  414. url: /api/pushsecret?id={{ .remoteRef.remoteKey }}&secret={{ .remoteRef.secretKey }}
  415. key: testkey
  416. body: 'pre {{ .remoteRef.remoteKey }} {{ .remoteRef.testkey }} post'
  417. secretkey: secretkey
  418. pushsecret: true
  419. secret:
  420. name: test-secret
  421. data:
  422. secretkey: value
  423. want:
  424. path: /api/pushsecret?id=testkey&secret=secretkey
  425. body: 'pre testkey value post'
  426. err: ''
  427. ---
  428. case: empty body
  429. args:
  430. url: /api/pushsecret?id={{ .remoteRef.remoteKey }}
  431. key: testkey
  432. body: '{{ "" }}'
  433. pushsecret: true
  434. secret:
  435. name: test-secret
  436. data:
  437. secretkey: value
  438. want:
  439. path: /api/pushsecret?id=testkey
  440. body: ''
  441. err: ''
  442. ---
  443. case: default body pushing without secret key
  444. args:
  445. url: /api/pushsecret?id={{ .remoteRef.remoteKey }}
  446. key: testkey
  447. pushsecret: true
  448. secret:
  449. name: test-secret
  450. data:
  451. secretkey: value
  452. want:
  453. path: /api/pushsecret?id=testkey
  454. body: '{"secretkey":"value"}'
  455. err: ''
  456. ---
  457. case: pushing without secret key
  458. args:
  459. url: /api/pushsecret?id={{ .remoteRef.remoteKey }}
  460. key: testkey
  461. body: 'pre {{ .remoteRef.remoteKey }} {{ index (.remoteRef.testkey | fromJson) "secretkey" }} post'
  462. pushsecret: true
  463. secret:
  464. name: test-secret
  465. data:
  466. secretkey: value
  467. want:
  468. path: /api/pushsecret?id=testkey
  469. body: 'pre testkey value post'
  470. err: ''
  471. ---
  472. case: pushing without secret key with dynamic resolution
  473. args:
  474. url: /api/pushsecret?id={{ .remoteRef.remoteKey }}
  475. key: testkey
  476. body: 'pre {{ .remoteRef.remoteKey }} {{ index (index .remoteRef .remoteRef.remoteKey | fromJson) "secretkey" }} post'
  477. pushsecret: true
  478. secret:
  479. name: test-secret
  480. data:
  481. secretkey: value
  482. want:
  483. path: /api/pushsecret?id=testkey
  484. body: 'pre testkey value post'
  485. err: ''
  486. `
  487. func TestWebhookPushSecret(t *testing.T) {
  488. ydec := yaml.NewDecoder(bytes.NewReader([]byte(testCasesPushSecret)))
  489. for {
  490. var tc testCase
  491. if err := ydec.Decode(&tc); err != nil {
  492. if !errors.Is(err, io.EOF) {
  493. t.Errorf("testcase decode error %v", err)
  494. }
  495. break
  496. }
  497. runTestCase(tc, t)
  498. }
  499. }
  500. func testCaseServer(tc testCase, t *testing.T) *httptest.Server {
  501. // Start a new server for every test case because the server wants to check the expected api path
  502. return httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
  503. if tc.Want.Path != "" && req.URL.String() != tc.Want.Path {
  504. t.Errorf("%s: unexpected api path: %s, expected %s", tc.Case, req.URL.String(), tc.Want.Path)
  505. }
  506. if tc.Want.Body != nil {
  507. b, _ := io.ReadAll(req.Body)
  508. if tc.Want.Body != nil && string(b) != *tc.Want.Body {
  509. t.Errorf("%s: unexpected body: %s, expected %s", tc.Case, string(b), *tc.Want.Body)
  510. }
  511. }
  512. if tc.Args.StatusCode != 0 {
  513. rw.WriteHeader(tc.Args.StatusCode)
  514. }
  515. rw.Write([]byte(tc.Args.Response))
  516. }))
  517. }
  518. func parseTimeout(timeout string) (*metav1.Duration, error) {
  519. if timeout == "" {
  520. return nil, nil
  521. }
  522. dur, err := time.ParseDuration(timeout)
  523. if err != nil {
  524. return nil, err
  525. }
  526. return &metav1.Duration{Duration: dur}, nil
  527. }
  528. func runTestCase(tc testCase, t *testing.T) {
  529. t.Run(tc.Case, func(t *testing.T) {
  530. ts := testCaseServer(tc, t)
  531. defer ts.Close()
  532. testStore := makeClusterSecretStore(ts.URL, tc.Args)
  533. var err error
  534. timeout, err := parseTimeout(tc.Args.Timeout)
  535. if err != nil {
  536. t.Errorf("%s: error parsing timeout '%s': %s", tc.Case, tc.Args.Timeout, err.Error())
  537. return
  538. }
  539. testStore.Spec.Provider.Webhook.Timeout = timeout
  540. testProv := &Provider{}
  541. client, err := testProv.NewClient(context.Background(), testStore, nil, "testnamespace")
  542. if err != nil {
  543. t.Errorf("%s: error creating client: %s", tc.Case, err.Error())
  544. return
  545. }
  546. if tc.Want.ResultMap != nil && !tc.Args.PushSecret {
  547. testGetSecretMap(tc, t, client)
  548. } else if !tc.Args.PushSecret {
  549. testGetSecret(tc, t, client)
  550. } else {
  551. testPushSecret(tc, t, client)
  552. }
  553. })
  554. }
  555. func testGetSecretMap(tc testCase, t *testing.T, client esv1.SecretsClient) {
  556. testRef := esv1.ExternalSecretDataRemoteRef{
  557. Key: tc.Args.Key,
  558. Version: tc.Args.Version,
  559. }
  560. secretmap, err := client.GetSecretMap(context.Background(), testRef)
  561. errStr := ""
  562. if err != nil {
  563. errStr = err.Error()
  564. }
  565. if (tc.Want.Err == "") != (errStr == "") || !strings.Contains(errStr, tc.Want.Err) {
  566. t.Errorf("%s: unexpected error: '%s' (expected '%s')", tc.Case, errStr, tc.Want.Err)
  567. }
  568. if err == nil {
  569. for wantkey, wantval := range tc.Want.ResultMap {
  570. gotval, ok := secretmap[wantkey]
  571. if !ok {
  572. t.Errorf("%s: unexpected response: wanted key '%s' not found", tc.Case, wantkey)
  573. } else if string(gotval) != wantval {
  574. t.Errorf("%s: unexpected response: key '%s' = '%s' (expected '%s')", tc.Case, wantkey, wantval, gotval)
  575. }
  576. }
  577. }
  578. }
  579. func testGetSecret(tc testCase, t *testing.T, client esv1.SecretsClient) {
  580. testRef := esv1.ExternalSecretDataRemoteRef{
  581. Key: tc.Args.Key,
  582. Property: tc.Args.Property,
  583. Version: tc.Args.Version,
  584. }
  585. ctx, cancel := context.WithTimeout(context.Background(), time.Second)
  586. defer cancel()
  587. secret, err := client.GetSecret(ctx, testRef)
  588. errStr := ""
  589. if err != nil {
  590. errStr = err.Error()
  591. }
  592. if !strings.Contains(errStr, tc.Want.Err) {
  593. t.Errorf("%s: unexpected error: '%s' (expected '%s')", tc.Case, errStr, tc.Want.Err)
  594. }
  595. if err == nil && string(secret) != tc.Want.Result {
  596. t.Errorf("%s: unexpected response: '%s' (expected '%s')", tc.Case, secret, tc.Want.Result)
  597. }
  598. }
  599. func testPushSecret(tc testCase, t *testing.T, client esv1.SecretsClient) {
  600. testRef := v1alpha1.PushSecretData{
  601. Match: v1alpha1.PushSecretMatch{
  602. SecretKey: tc.Args.SecretKey,
  603. RemoteRef: v1alpha1.PushSecretRemoteRef{
  604. RemoteKey: tc.Args.Key,
  605. },
  606. },
  607. }
  608. data := map[string][]byte{}
  609. for k, v := range tc.Args.Secret.Data {
  610. data[k] = []byte(v)
  611. }
  612. sec := &corev1.Secret{
  613. ObjectMeta: metav1.ObjectMeta{
  614. Name: tc.Args.Secret.Name,
  615. },
  616. Data: data,
  617. }
  618. ctx, cancel := context.WithTimeout(context.Background(), time.Second)
  619. defer cancel()
  620. err := client.PushSecret(ctx, sec, testRef)
  621. errStr := ""
  622. if err != nil {
  623. errStr = err.Error()
  624. }
  625. if tc.Want.Err == "" && errStr != "" {
  626. t.Errorf("%s: unexpected error: '%s' (expected '%s')", tc.Case, errStr, tc.Want.Err)
  627. }
  628. if !strings.Contains(errStr, tc.Want.Err) {
  629. t.Errorf("%s: unexpected error: '%s' (expected '%s')", tc.Case, errStr, tc.Want.Err)
  630. }
  631. }
  632. func makeClusterSecretStore(url string, args args) *esv1.ClusterSecretStore {
  633. store := &esv1.ClusterSecretStore{
  634. TypeMeta: metav1.TypeMeta{
  635. Kind: "ClusterSecretStore",
  636. },
  637. ObjectMeta: metav1.ObjectMeta{
  638. Name: "wehbook-store",
  639. Namespace: "default",
  640. },
  641. Spec: esv1.SecretStoreSpec{
  642. Provider: &esv1.SecretStoreProvider{
  643. Webhook: &esv1.WebhookProvider{
  644. URL: url + args.URL,
  645. Body: args.Body,
  646. Headers: map[string]string{
  647. "Content-Type": "application.json",
  648. "X-SecretKey": "{{ .remoteRef.key }}",
  649. },
  650. Result: esv1.WebhookResult{
  651. JSONPath: args.JSONPath,
  652. },
  653. },
  654. },
  655. },
  656. }
  657. return store
  658. }