utils_test.go 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527
  1. /*
  2. Copyright © The ESO Authors
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. https://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package esutils
  14. import (
  15. "context"
  16. "encoding/json"
  17. "errors"
  18. "reflect"
  19. "testing"
  20. "time"
  21. "github.com/aws/aws-sdk-go-v2/aws"
  22. "github.com/oracle/oci-go-sdk/v65/vault"
  23. "github.com/stretchr/testify/assert"
  24. v1 "k8s.io/api/core/v1"
  25. apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
  26. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  27. clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
  28. esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
  29. esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
  30. esmetav1 "github.com/external-secrets/external-secrets/apis/meta/v1"
  31. )
  32. const (
  33. keyWithEmojis string = "😀foo😁bar😂baz😈bing"
  34. keyWithInvalidChars string = "some-array[0].entity"
  35. keyWithEncodedInvalidChars string = "some-array_U005b_0_U005d_.entity"
  36. )
  37. func TestObjectHash(t *testing.T) {
  38. tests := []struct {
  39. name string
  40. input any
  41. want string
  42. }{
  43. {
  44. name: "A nil should be still working",
  45. input: nil,
  46. want: "c461202a18e99215f121936fb2452e03843828e448a00a53f285a6fc",
  47. },
  48. {
  49. name: "We accept a simple scalar value, i.e. string",
  50. input: "hello there",
  51. want: "f78681ec611ebaeea0689bff6c7812a83ff98a7faba986d9af76c999",
  52. },
  53. {
  54. name: "A complex object like a secret is not an issue",
  55. input: v1.Secret{Data: map[string][]byte{
  56. "xx": []byte("yyy"),
  57. }},
  58. want: "9c717e13e4281db3cdad3f56c6e7faab1d7029c4b4fbbf12fbec9b1e",
  59. },
  60. {
  61. name: "map also works",
  62. input: map[string][]byte{
  63. "foo": []byte("value1"),
  64. "bar": []byte("value2"),
  65. },
  66. want: "1bed8bcbcb4547ffe19a19cd47d9078e84aa6598266d86b99f992d64",
  67. },
  68. }
  69. for _, tt := range tests {
  70. t.Run(tt.name, func(t *testing.T) {
  71. if got := ObjectHash(tt.input); got != tt.want {
  72. t.Errorf("ObjectHash() = %v, want %v", got, tt.want)
  73. }
  74. })
  75. }
  76. }
  77. func TestIsNil(t *testing.T) {
  78. tbl := []struct {
  79. name string
  80. val any
  81. exp bool
  82. }{
  83. {
  84. name: "simple nil val",
  85. val: nil,
  86. exp: true,
  87. },
  88. {
  89. name: "nil slice",
  90. val: (*[]struct{})(nil),
  91. exp: true,
  92. },
  93. {
  94. name: "struct pointer",
  95. val: &testing.T{},
  96. exp: false,
  97. },
  98. {
  99. name: "struct",
  100. val: testing.T{},
  101. exp: false,
  102. },
  103. {
  104. name: "slice of struct",
  105. val: []struct{}{{}},
  106. exp: false,
  107. },
  108. {
  109. name: "slice of ptr",
  110. val: []*testing.T{nil},
  111. exp: false,
  112. },
  113. {
  114. name: "slice",
  115. val: []struct{}(nil),
  116. exp: false,
  117. },
  118. {
  119. name: "int default value",
  120. val: 0,
  121. exp: false,
  122. },
  123. {
  124. name: "empty str",
  125. val: "",
  126. exp: false,
  127. },
  128. {
  129. name: "oracle vault",
  130. val: vault.VaultsClient{},
  131. exp: false,
  132. },
  133. {
  134. name: "func",
  135. val: func() {
  136. // noop for testing and to make linter happy
  137. },
  138. exp: false,
  139. },
  140. {
  141. name: "channel",
  142. val: make(chan struct{}),
  143. exp: false,
  144. },
  145. {
  146. name: "map",
  147. val: map[string]string{},
  148. exp: false,
  149. },
  150. }
  151. for _, row := range tbl {
  152. t.Run(row.name, func(t *testing.T) {
  153. res := IsNil(row.val)
  154. if res != row.exp {
  155. t.Errorf("IsNil(%#v)=%t, expected %t", row.val, res, row.exp)
  156. }
  157. })
  158. }
  159. }
  160. func TestConvertKeys(t *testing.T) {
  161. type args struct {
  162. strategy esv1.ExternalSecretConversionStrategy
  163. in map[string][]byte
  164. }
  165. tests := []struct {
  166. name string
  167. args args
  168. want map[string][]byte
  169. wantErr bool
  170. }{
  171. {
  172. name: "convert with special chars",
  173. args: args{
  174. strategy: esv1.ExternalSecretConversionDefault,
  175. in: map[string][]byte{
  176. "foo$bar%baz*bing": []byte(`noop`),
  177. },
  178. },
  179. want: map[string][]byte{
  180. "foo_bar_baz_bing": []byte(`noop`),
  181. },
  182. },
  183. {
  184. name: "error on collision",
  185. args: args{
  186. strategy: esv1.ExternalSecretConversionDefault,
  187. in: map[string][]byte{
  188. "foo$bar%baz*bing": []byte(`noop`),
  189. "foo_bar_baz$bing": []byte(`noop`),
  190. },
  191. },
  192. wantErr: true,
  193. },
  194. {
  195. name: "convert path",
  196. args: args{
  197. strategy: esv1.ExternalSecretConversionDefault,
  198. in: map[string][]byte{
  199. "/foo/bar/baz/bing": []byte(`noop`),
  200. "foo/bar/baz/bing/": []byte(`noop`),
  201. },
  202. },
  203. want: map[string][]byte{
  204. "_foo_bar_baz_bing": []byte(`noop`),
  205. "foo_bar_baz_bing_": []byte(`noop`),
  206. },
  207. },
  208. {
  209. name: "convert unicode",
  210. args: args{
  211. strategy: esv1.ExternalSecretConversionUnicode,
  212. in: map[string][]byte{
  213. keyWithEmojis: []byte(`noop`),
  214. },
  215. },
  216. want: map[string][]byte{
  217. "_U1f600_foo_U1f601_bar_U1f602_baz_U1f608_bing": []byte(`noop`),
  218. },
  219. },
  220. }
  221. for _, tt := range tests {
  222. t.Run(tt.name, func(t *testing.T) {
  223. got, err := ConvertKeys(tt.args.strategy, tt.args.in)
  224. if (err != nil) != tt.wantErr {
  225. t.Errorf("ConvertKeys() error = %v, wantErr %v", err, tt.wantErr)
  226. return
  227. }
  228. if !reflect.DeepEqual(got, tt.want) {
  229. t.Errorf("ConvertKeys() = %v, want %v", got, tt.want)
  230. }
  231. })
  232. }
  233. }
  234. func TestTransformKeys(t *testing.T) {
  235. tests := []struct {
  236. name string
  237. in map[string][]byte
  238. transform func(string) string
  239. want map[string][]byte
  240. wantErr bool
  241. }{
  242. {
  243. name: "transforms keys and preserves values",
  244. in: map[string][]byte{
  245. "foo": []byte("bar"),
  246. "baz": []byte("qux"),
  247. },
  248. transform: func(key string) string {
  249. return key + "-transformed"
  250. },
  251. want: map[string][]byte{
  252. "foo-transformed": []byte("bar"),
  253. "baz-transformed": []byte("qux"),
  254. },
  255. },
  256. {
  257. name: "errors on transformed key collision",
  258. in: map[string][]byte{
  259. "foo": []byte("bar"),
  260. "baz": []byte("qux"),
  261. },
  262. transform: func(string) string {
  263. return "collision"
  264. },
  265. wantErr: true,
  266. },
  267. }
  268. for _, tt := range tests {
  269. t.Run(tt.name, func(t *testing.T) {
  270. got, err := transformKeys(tt.in, tt.transform)
  271. if (err != nil) != tt.wantErr {
  272. t.Errorf("transformKeys() error = %v, wantErr %v", err, tt.wantErr)
  273. return
  274. }
  275. if !reflect.DeepEqual(got, tt.want) {
  276. t.Errorf("transformKeys() = %v, want %v", got, tt.want)
  277. }
  278. })
  279. }
  280. }
  281. func TestReverseKeys(t *testing.T) {
  282. type args struct {
  283. encodingStrategy esv1.ExternalSecretConversionStrategy
  284. decodingStrategy esv1alpha1.PushSecretConversionStrategy
  285. in map[string][]byte
  286. }
  287. tests := []struct {
  288. name string
  289. args args
  290. want map[string][]byte
  291. wantErr bool
  292. }{
  293. {
  294. name: "encoding and decoding strategy are selecting Unicode conversion and reverse unicode, so the in and want should match, this test covers Unicode characters beyond the Basic Multilingual Plane (BMP)",
  295. args: args{
  296. encodingStrategy: esv1.ExternalSecretConversionUnicode,
  297. decodingStrategy: esv1alpha1.PushSecretConversionReverseUnicode,
  298. in: map[string][]byte{
  299. keyWithEmojis: []byte(`noop`),
  300. },
  301. },
  302. want: map[string][]byte{
  303. keyWithEmojis: []byte(`noop`),
  304. },
  305. },
  306. {
  307. name: "encoding and decoding strategy are selecting Unicode conversion and reverse unicode, so the in and want should match, this test covers Unicode characters in the Basic Multilingual Plane (BMP)",
  308. args: args{
  309. encodingStrategy: esv1.ExternalSecretConversionUnicode,
  310. decodingStrategy: esv1alpha1.PushSecretConversionReverseUnicode,
  311. in: map[string][]byte{
  312. keyWithInvalidChars: []byte(`noop`),
  313. },
  314. },
  315. want: map[string][]byte{
  316. keyWithInvalidChars: []byte(`noop`),
  317. },
  318. },
  319. {
  320. name: "the encoding strategy is selecting Unicode conversion, but the decoding strategy is none, so we want an encoded representation of the content",
  321. args: args{
  322. encodingStrategy: esv1.ExternalSecretConversionUnicode,
  323. decodingStrategy: esv1alpha1.PushSecretConversionNone,
  324. in: map[string][]byte{
  325. keyWithInvalidChars: []byte(`noop`),
  326. },
  327. },
  328. want: map[string][]byte{
  329. keyWithEncodedInvalidChars: []byte(`noop`),
  330. },
  331. },
  332. }
  333. for _, tt := range tests {
  334. t.Run(tt.name, func(t *testing.T) {
  335. got, err := ConvertKeys(tt.args.encodingStrategy, tt.args.in)
  336. if (err != nil) != tt.wantErr {
  337. t.Errorf("ConvertKeys() error = %v, wantErr %v", err, tt.wantErr)
  338. return
  339. }
  340. got, err = ReverseKeys(tt.args.decodingStrategy, got)
  341. if (err != nil) != tt.wantErr {
  342. t.Errorf("ReverseKeys() error = %v, wantErr %v", err, tt.wantErr)
  343. return
  344. }
  345. if !reflect.DeepEqual(got, tt.want) {
  346. t.Errorf("ReverseKeys() = %v, want %v", got, tt.want)
  347. }
  348. })
  349. }
  350. }
  351. func TestValidate(t *testing.T) {
  352. err := NetworkValidate("http://google.com", 10*time.Second)
  353. if err != nil {
  354. t.Errorf("Connection problem: %v", err)
  355. }
  356. }
  357. func TestRewrite(t *testing.T) {
  358. type args struct {
  359. operations []esv1.ExternalSecretRewrite
  360. in map[string][]byte
  361. }
  362. tests := []struct {
  363. name string
  364. args args
  365. want map[string][]byte
  366. wantErr bool
  367. }{
  368. {
  369. name: "using double merge",
  370. args: args{
  371. operations: []esv1.ExternalSecretRewrite{
  372. {
  373. Merge: &esv1.ExternalSecretRewriteMerge{
  374. Strategy: esv1.ExternalSecretRewriteMergeStrategyJSON,
  375. ConflictPolicy: esv1.ExternalSecretRewriteMergeConflictPolicyIgnore,
  376. Into: "merged",
  377. Priority: []string{"a"},
  378. },
  379. },
  380. {
  381. Merge: &esv1.ExternalSecretRewriteMerge{
  382. Strategy: esv1.ExternalSecretRewriteMergeStrategyExtract,
  383. ConflictPolicy: esv1.ExternalSecretRewriteMergeConflictPolicyIgnore,
  384. Priority: []string{"b"},
  385. },
  386. },
  387. },
  388. in: map[string][]byte{
  389. "a": []byte(`{"host": "dba", "pass": "yola", "port": 123}`),
  390. "b": []byte(`{"host": "dbb", "pass": "yolb"}`),
  391. },
  392. },
  393. want: map[string][]byte{
  394. "host": []byte("dbb"),
  395. "pass": []byte("yolb"),
  396. "port": []byte("123"),
  397. },
  398. },
  399. {
  400. name: "using regexp and merge",
  401. args: args{
  402. operations: []esv1.ExternalSecretRewrite{
  403. {
  404. Regexp: &esv1.ExternalSecretRewriteRegexp{
  405. Source: "db/(.*)",
  406. Target: "$1",
  407. },
  408. },
  409. {
  410. Merge: &esv1.ExternalSecretRewriteMerge{
  411. Strategy: esv1.ExternalSecretRewriteMergeStrategyJSON,
  412. ConflictPolicy: esv1.ExternalSecretRewriteMergeConflictPolicyIgnore,
  413. Into: "merged",
  414. Priority: []string{"a"},
  415. },
  416. },
  417. },
  418. in: map[string][]byte{
  419. "db/a": []byte(`{"host": "dba.example.com"}`),
  420. "db/b": []byte(`{"host": "dbb.example.com", "pass": "yolo"}`),
  421. },
  422. },
  423. want: map[string][]byte{
  424. "a": []byte(`{"host": "dba.example.com"}`),
  425. "b": []byte(`{"host": "dbb.example.com", "pass": "yolo"}`),
  426. "merged": []byte(`{"host":"dba.example.com","pass":"yolo"}`),
  427. },
  428. },
  429. {
  430. name: "replace of a single key",
  431. args: args{
  432. operations: []esv1.ExternalSecretRewrite{
  433. {
  434. Regexp: &esv1.ExternalSecretRewriteRegexp{
  435. Source: "-",
  436. Target: "_",
  437. },
  438. },
  439. },
  440. in: map[string][]byte{
  441. "foo-bar": []byte("bar"),
  442. },
  443. },
  444. want: map[string][]byte{
  445. "foo_bar": []byte("bar"),
  446. },
  447. },
  448. {
  449. name: "no operation",
  450. args: args{
  451. operations: []esv1.ExternalSecretRewrite{
  452. {
  453. Regexp: &esv1.ExternalSecretRewriteRegexp{
  454. Source: "hello",
  455. Target: "world",
  456. },
  457. },
  458. },
  459. in: map[string][]byte{
  460. "foo": []byte("bar"),
  461. },
  462. },
  463. want: map[string][]byte{
  464. "foo": []byte("bar"),
  465. },
  466. },
  467. {
  468. name: "removing prefix from keys",
  469. args: args{
  470. operations: []esv1.ExternalSecretRewrite{
  471. {
  472. Regexp: &esv1.ExternalSecretRewriteRegexp{
  473. Source: "^my/initial/path/",
  474. Target: "",
  475. },
  476. },
  477. },
  478. in: map[string][]byte{
  479. "my/initial/path/foo": []byte("bar"),
  480. },
  481. },
  482. want: map[string][]byte{
  483. "foo": []byte("bar"),
  484. },
  485. },
  486. {
  487. name: "using un-named capture groups",
  488. args: args{
  489. operations: []esv1.ExternalSecretRewrite{
  490. {
  491. Regexp: &esv1.ExternalSecretRewriteRegexp{
  492. Source: "f(.*)o",
  493. Target: "a_new_path_$1",
  494. },
  495. },
  496. },
  497. in: map[string][]byte{
  498. "foo": []byte("bar"),
  499. "foodaloo": []byte("barr"),
  500. },
  501. },
  502. want: map[string][]byte{
  503. "a_new_path_o": []byte("bar"),
  504. "a_new_path_oodalo": []byte("barr"),
  505. },
  506. },
  507. {
  508. name: "using named and numbered capture groups",
  509. args: args{
  510. operations: []esv1.ExternalSecretRewrite{
  511. {
  512. Regexp: &esv1.ExternalSecretRewriteRegexp{
  513. Source: "f(?P<content>.*)o",
  514. Target: "a_new_path_${content}_${1}",
  515. },
  516. },
  517. },
  518. in: map[string][]byte{
  519. "foo": []byte("bar"),
  520. "floo": []byte("barr"),
  521. },
  522. },
  523. want: map[string][]byte{
  524. "a_new_path_o_o": []byte("bar"),
  525. "a_new_path_lo_lo": []byte("barr"),
  526. },
  527. },
  528. {
  529. name: "using sequenced rewrite operations",
  530. args: args{
  531. operations: []esv1.ExternalSecretRewrite{
  532. {
  533. Regexp: &esv1.ExternalSecretRewriteRegexp{
  534. Source: "my/(.*?)/bar/(.*)",
  535. Target: "$1-$2",
  536. },
  537. },
  538. {
  539. Regexp: &esv1.ExternalSecretRewriteRegexp{
  540. Source: "-",
  541. Target: "_",
  542. },
  543. },
  544. {
  545. Regexp: &esv1.ExternalSecretRewriteRegexp{
  546. Source: "ass",
  547. Target: "***",
  548. },
  549. },
  550. },
  551. in: map[string][]byte{
  552. "my/app/bar/key": []byte("bar"),
  553. "my/app/bar/password": []byte("barr"),
  554. },
  555. },
  556. want: map[string][]byte{
  557. "app_key": []byte("bar"),
  558. "app_p***word": []byte("barr"),
  559. },
  560. },
  561. {
  562. name: "using transform rewrite operation to create env var format keys",
  563. args: args{
  564. operations: []esv1.ExternalSecretRewrite{
  565. {
  566. Regexp: &esv1.ExternalSecretRewriteRegexp{
  567. Source: "my/(.*?)/bar/(.*)",
  568. Target: "$1-$2",
  569. },
  570. },
  571. {
  572. Transform: &esv1.ExternalSecretRewriteTransform{
  573. Template: `{{ .value | upper | replace "-" "_" }}`,
  574. },
  575. },
  576. },
  577. in: map[string][]byte{
  578. "my/app/bar/key": []byte("bar"),
  579. },
  580. },
  581. want: map[string][]byte{
  582. "APP_KEY": []byte("bar"),
  583. },
  584. },
  585. }
  586. for _, tt := range tests {
  587. t.Run(tt.name, func(t *testing.T) {
  588. got, err := RewriteMap(tt.args.operations, tt.args.in)
  589. if (err != nil) != tt.wantErr {
  590. t.Errorf("RewriteMap() error = %v, wantErr %v", err, tt.wantErr)
  591. return
  592. }
  593. if !reflect.DeepEqual(got, tt.want) {
  594. t.Errorf("RewriteMap() = %v, want %v", got, tt.want)
  595. }
  596. })
  597. }
  598. }
  599. func TestRewriteMerge(t *testing.T) {
  600. type args struct {
  601. operation esv1.ExternalSecretRewriteMerge
  602. in map[string][]byte
  603. }
  604. tests := []struct {
  605. name string
  606. args args
  607. want map[string][]byte
  608. wantErr bool
  609. }{
  610. {
  611. name: "using empty merge",
  612. args: args{
  613. operation: esv1.ExternalSecretRewriteMerge{},
  614. in: map[string][]byte{
  615. "mongo-credentials": []byte(`{"username": "foz", "password": "baz"}`),
  616. "redis-credentials": []byte(`{"host": "redis.example.com", "port": "6379"}`),
  617. },
  618. },
  619. want: map[string][]byte{
  620. "username": []byte("foz"),
  621. "password": []byte("baz"),
  622. "host": []byte("redis.example.com"),
  623. "port": []byte("6379"),
  624. },
  625. wantErr: false,
  626. },
  627. {
  628. name: "using priority",
  629. args: args{
  630. operation: esv1.ExternalSecretRewriteMerge{
  631. ConflictPolicy: esv1.ExternalSecretRewriteMergeConflictPolicyIgnore,
  632. Priority: []string{"mongo-credentials", "redis-credentials"},
  633. },
  634. in: map[string][]byte{
  635. "redis-credentials": []byte(`{"host": "redis.example.com", "port": "6379"}`),
  636. "mongo-credentials": []byte(`{"username": "foz", "password": "baz"}`),
  637. "other-credentials": []byte(`{"key": "value", "host": "other.example.com"}`),
  638. },
  639. },
  640. want: map[string][]byte{
  641. "username": []byte("foz"),
  642. "password": []byte("baz"),
  643. "host": []byte("redis.example.com"),
  644. "port": []byte("6379"),
  645. "key": []byte("value"),
  646. },
  647. wantErr: false,
  648. },
  649. {
  650. name: "using priority with keys not in input (default strict)",
  651. args: args{
  652. operation: esv1.ExternalSecretRewriteMerge{
  653. ConflictPolicy: esv1.ExternalSecretRewriteMergeConflictPolicyIgnore,
  654. Priority: []string{"non-existent-key", "another-missing-key", "mongo-credentials"},
  655. },
  656. in: map[string][]byte{
  657. "mongo-credentials": []byte(`{"username": "foz", "password": "baz"}`),
  658. "redis-credentials": []byte(`{"host": "redis.example.com", "port": "6379"}`),
  659. },
  660. },
  661. want: nil,
  662. wantErr: true,
  663. },
  664. {
  665. name: "using priority with keys not in input and ignore policy",
  666. args: args{
  667. operation: esv1.ExternalSecretRewriteMerge{
  668. ConflictPolicy: esv1.ExternalSecretRewriteMergeConflictPolicyIgnore,
  669. Priority: []string{"non-existent-key", "mongo-credentials"},
  670. PriorityPolicy: esv1.ExternalSecretRewriteMergePriorityPolicyIgnoreNotFound,
  671. },
  672. in: map[string][]byte{
  673. "mongo-credentials": []byte(`{"username": "foz", "password": "baz"}`),
  674. "redis-credentials": []byte(`{"host": "redis.example.com", "port": "6379"}`),
  675. },
  676. },
  677. want: map[string][]byte{
  678. "username": []byte("foz"),
  679. "password": []byte("baz"),
  680. "host": []byte("redis.example.com"),
  681. "port": []byte("6379"),
  682. },
  683. wantErr: false,
  684. },
  685. {
  686. name: "using conflict policy error",
  687. args: args{
  688. operation: esv1.ExternalSecretRewriteMerge{
  689. ConflictPolicy: esv1.ExternalSecretRewriteMergeConflictPolicyError,
  690. },
  691. in: map[string][]byte{
  692. "mongo-credentials": []byte(`{"username": "foz", "password": "baz"}`),
  693. "redis-credentials": []byte(`{"username": "redis", "port": "6379"}`),
  694. },
  695. },
  696. want: nil,
  697. wantErr: true,
  698. },
  699. {
  700. name: "using JSON strategy",
  701. args: args{
  702. operation: esv1.ExternalSecretRewriteMerge{
  703. Strategy: esv1.ExternalSecretRewriteMergeStrategyJSON,
  704. Into: "credentials",
  705. },
  706. in: map[string][]byte{
  707. "mongo-credentials": []byte(`{"username": "foz", "password": "baz"}`),
  708. "redis-credentials": []byte(`{"host": "redis.example.com", "port": "6379"}`),
  709. },
  710. },
  711. want: map[string][]byte{
  712. "mongo-credentials": []byte(`{"username": "foz", "password": "baz"}`),
  713. "redis-credentials": []byte(`{"host": "redis.example.com", "port": "6379"}`),
  714. "credentials": func() []byte {
  715. expected := map[string]any{
  716. "username": "foz",
  717. "password": "baz",
  718. "host": "redis.example.com",
  719. "port": "6379",
  720. }
  721. b, _ := json.Marshal(expected)
  722. return b
  723. }(),
  724. },
  725. wantErr: false,
  726. },
  727. {
  728. name: "using JSON strategy without into",
  729. args: args{
  730. operation: esv1.ExternalSecretRewriteMerge{
  731. Strategy: esv1.ExternalSecretRewriteMergeStrategyJSON,
  732. },
  733. in: map[string][]byte{
  734. "mongo-credentials": []byte(`{"username": "foz", "password": "baz"}`),
  735. "redis-credentials": []byte(`{"host": "redis.example.com", "port": "6379"}`),
  736. },
  737. },
  738. want: nil,
  739. wantErr: true,
  740. },
  741. {
  742. name: "with invalid JSON",
  743. args: args{
  744. operation: esv1.ExternalSecretRewriteMerge{},
  745. in: map[string][]byte{
  746. "invalid-json": []byte(`{"username": "foz", "password": "baz"`),
  747. },
  748. },
  749. want: nil,
  750. wantErr: true,
  751. },
  752. }
  753. for _, tt := range tests {
  754. t.Run(tt.name, func(t *testing.T) {
  755. got, err := RewriteMerge(tt.args.operation, tt.args.in)
  756. if (err != nil) != tt.wantErr {
  757. t.Errorf("RewriteMerge() error = %v, wantErr %v", err, tt.wantErr)
  758. return
  759. }
  760. if !reflect.DeepEqual(got, tt.want) {
  761. t.Errorf("RewriteMerge() = %v, want %v", got, tt.want)
  762. }
  763. })
  764. }
  765. }
  766. func TestReverse(t *testing.T) {
  767. type args struct {
  768. strategy esv1alpha1.PushSecretConversionStrategy
  769. in string
  770. }
  771. tests := []struct {
  772. name string
  773. args args
  774. want string
  775. }{
  776. {
  777. name: "do not change the key when using the None strategy",
  778. args: args{
  779. strategy: esv1alpha1.PushSecretConversionNone,
  780. in: keyWithEncodedInvalidChars,
  781. },
  782. want: keyWithEncodedInvalidChars,
  783. },
  784. {
  785. name: "reverse an unicode encoded key",
  786. args: args{
  787. strategy: esv1alpha1.PushSecretConversionReverseUnicode,
  788. in: keyWithEncodedInvalidChars,
  789. },
  790. want: keyWithInvalidChars,
  791. },
  792. {
  793. name: "do not attempt to decode an invalid unicode representation",
  794. args: args{
  795. strategy: esv1alpha1.PushSecretConversionReverseUnicode,
  796. in: "_U0xxx_x_U005b_",
  797. },
  798. want: "_U0xxx_x[",
  799. },
  800. }
  801. for _, tt := range tests {
  802. t.Run(tt.name, func(t *testing.T) {
  803. if got := reverse(tt.args.strategy, tt.args.in); got != tt.want {
  804. t.Errorf("reverse() = %v, want %v", got, tt.want)
  805. }
  806. })
  807. }
  808. }
  809. func TestFetchValueFromMetadata(t *testing.T) {
  810. type args struct {
  811. key string
  812. data *apiextensionsv1.JSON
  813. def any
  814. }
  815. type testCase struct {
  816. name string
  817. args args
  818. wantT any
  819. wantErr bool
  820. }
  821. tests := []testCase{
  822. {
  823. name: "plain dig for an existing key",
  824. args: args{
  825. key: "key",
  826. data: &apiextensionsv1.JSON{
  827. Raw: []byte(
  828. `{"key": "value"}`,
  829. ),
  830. },
  831. def: "def",
  832. },
  833. wantT: "value",
  834. wantErr: false,
  835. },
  836. {
  837. name: "return default if key not found",
  838. args: args{
  839. key: "key2",
  840. data: &apiextensionsv1.JSON{
  841. Raw: []byte(
  842. `{"key": "value"}`,
  843. ),
  844. },
  845. def: "def",
  846. },
  847. wantT: "def",
  848. wantErr: false,
  849. },
  850. {
  851. name: "use a different type",
  852. args: args{
  853. key: "key",
  854. data: &apiextensionsv1.JSON{
  855. Raw: []byte(
  856. `{"key": 123}`,
  857. ),
  858. },
  859. def: 1234,
  860. },
  861. wantT: float64(123), // unmarshal is always float64
  862. wantErr: false,
  863. },
  864. {
  865. name: "digging deeper",
  866. args: args{
  867. key: "key2",
  868. data: &apiextensionsv1.JSON{
  869. Raw: []byte(
  870. `{"key": {"key2": "value"}}`,
  871. ),
  872. },
  873. def: "",
  874. },
  875. wantT: "value",
  876. wantErr: false,
  877. },
  878. {
  879. name: "digging for a slice",
  880. args: args{
  881. key: "topics",
  882. data: &apiextensionsv1.JSON{
  883. Raw: []byte(
  884. `{"topics": ["topic1", "topic2"]}`,
  885. ),
  886. },
  887. def: []string{},
  888. },
  889. wantT: []any{"topic1", "topic2"}, // we don't have deep type matching so it's not an []string{} but []any.
  890. wantErr: false,
  891. },
  892. }
  893. for _, tt := range tests {
  894. t.Run(tt.name, func(t *testing.T) {
  895. gotT, err := FetchValueFromMetadata(tt.args.key, tt.args.data, tt.args.def)
  896. if (err != nil) != tt.wantErr {
  897. t.Errorf("FetchValueFromMetadata() error = %v, wantErr %v", err, tt.wantErr)
  898. return
  899. }
  900. assert.Equal(t, tt.wantT, gotT)
  901. })
  902. }
  903. }
  904. func TestJSONToSecretDataMap(t *testing.T) {
  905. t.Run("string values", func(t *testing.T) {
  906. got, err := JSONToSecretDataMap([]byte(`{"foo":"bar"}`))
  907. assert.NoError(t, err)
  908. assert.Equal(t, map[string][]byte{"foo": []byte("bar")}, got)
  909. })
  910. t.Run("nested and non-string values", func(t *testing.T) {
  911. got, err := JSONToSecretDataMap([]byte(`{"username":"my_user","port":5432,"nested":{"baz":"nestedval"}}`))
  912. assert.NoError(t, err)
  913. assert.Equal(t, map[string][]byte{
  914. "username": []byte("my_user"),
  915. "port": []byte("5432"),
  916. "nested": []byte(`{"baz":"nestedval"}`),
  917. }, got)
  918. })
  919. t.Run("null value", func(t *testing.T) {
  920. got, err := JSONToSecretDataMap([]byte(`{"key":null}`))
  921. assert.NoError(t, err)
  922. assert.Equal(t, map[string][]byte{"key": []byte("")}, got)
  923. })
  924. t.Run("invalid json", func(t *testing.T) {
  925. _, err := JSONToSecretDataMap([]byte(`not-json`))
  926. assert.Error(t, err)
  927. })
  928. }
  929. func TestGetByteValue(t *testing.T) {
  930. type args struct {
  931. data any
  932. }
  933. type testCase struct {
  934. name string
  935. args args
  936. want []byte
  937. wantErr bool
  938. }
  939. tests := []testCase{
  940. {
  941. name: "string",
  942. args: args{
  943. data: "value",
  944. },
  945. want: []byte("value"),
  946. wantErr: false,
  947. },
  948. {
  949. name: "map of any",
  950. args: args{
  951. data: map[string]any{
  952. "key": "value",
  953. },
  954. },
  955. want: []byte(`{"key":"value"}`),
  956. wantErr: false,
  957. },
  958. {
  959. name: "slice of string",
  960. args: args{
  961. data: []string{"value1", "value2"},
  962. },
  963. want: []byte("value1\nvalue2"),
  964. wantErr: false,
  965. },
  966. {
  967. name: "json.RawMessage",
  968. args: args{
  969. data: json.RawMessage(`{"key":"value"}`),
  970. },
  971. want: []byte(`{"key":"value"}`),
  972. wantErr: false,
  973. },
  974. {
  975. name: "float64",
  976. args: args{
  977. data: 123.45,
  978. },
  979. want: []byte("123.45"),
  980. wantErr: false,
  981. },
  982. {
  983. name: "json.Number",
  984. args: args{
  985. data: json.Number("123.45"),
  986. },
  987. want: []byte("123.45"),
  988. wantErr: false,
  989. },
  990. {
  991. name: "slice of any",
  992. args: args{
  993. data: []any{"value1", "value2"},
  994. },
  995. want: []byte(`["value1","value2"]`),
  996. wantErr: false,
  997. },
  998. {
  999. name: "boolean",
  1000. args: args{
  1001. data: true,
  1002. },
  1003. want: []byte("true"),
  1004. wantErr: false,
  1005. },
  1006. {
  1007. name: "nil",
  1008. args: args{
  1009. data: nil,
  1010. },
  1011. want: []byte(nil),
  1012. wantErr: false,
  1013. },
  1014. }
  1015. for _, tt := range tests {
  1016. t.Run(tt.name, func(t *testing.T) {
  1017. got, err := GetByteValue(tt.args.data)
  1018. if (err != nil) != tt.wantErr {
  1019. t.Errorf("GetByteValue() error = %v, wantErr %v", err, tt.wantErr)
  1020. return
  1021. }
  1022. if !reflect.DeepEqual(got, tt.want) {
  1023. t.Errorf("GetByteValue() = %v, want %v", got, tt.want)
  1024. }
  1025. })
  1026. }
  1027. }
  1028. func TestCompareStringAndByteSlices(t *testing.T) {
  1029. type args struct {
  1030. stringValue *string
  1031. byteValueSlice []byte
  1032. }
  1033. type testCase struct {
  1034. name string
  1035. args args
  1036. want bool
  1037. wantErr bool
  1038. }
  1039. tests := []testCase{
  1040. {
  1041. name: "same contents",
  1042. args: args{
  1043. stringValue: aws.String("value"),
  1044. byteValueSlice: []byte("value"),
  1045. },
  1046. want: true,
  1047. wantErr: true,
  1048. }, {
  1049. name: "different contents",
  1050. args: args{
  1051. stringValue: aws.String("value89"),
  1052. byteValueSlice: []byte("value"),
  1053. },
  1054. want: true,
  1055. wantErr: false,
  1056. }, {
  1057. name: "same contents with random",
  1058. args: args{
  1059. stringValue: aws.String("value89!3#@212"),
  1060. byteValueSlice: []byte("value89!3#@212"),
  1061. },
  1062. want: true,
  1063. wantErr: true,
  1064. }, {
  1065. name: "check Nil",
  1066. args: args{
  1067. stringValue: nil,
  1068. byteValueSlice: []byte("value89!3#@212"),
  1069. },
  1070. want: false,
  1071. wantErr: false,
  1072. },
  1073. }
  1074. for _, tt := range tests {
  1075. t.Run(tt.name, func(t *testing.T) {
  1076. got := CompareStringAndByteSlices(tt.args.stringValue, tt.args.byteValueSlice)
  1077. if got != tt.wantErr {
  1078. t.Errorf("CompareStringAndByteSlices() got = %v, want = %v", got, tt.wantErr)
  1079. return
  1080. }
  1081. })
  1082. }
  1083. }
  1084. func TestValidateSecretSelector(t *testing.T) {
  1085. tests := []struct {
  1086. desc string
  1087. store esv1.GenericStore
  1088. ref esmetav1.SecretKeySelector
  1089. expected error
  1090. }{
  1091. {
  1092. desc: "cluster secret store with namespace reference",
  1093. store: &esv1.ClusterSecretStore{
  1094. TypeMeta: metav1.TypeMeta{
  1095. Kind: esv1.ClusterSecretStoreKind,
  1096. },
  1097. },
  1098. ref: esmetav1.SecretKeySelector{
  1099. Namespace: new("test"),
  1100. },
  1101. expected: nil,
  1102. },
  1103. {
  1104. desc: "secret store without namespace reference",
  1105. store: &esv1.SecretStore{
  1106. TypeMeta: metav1.TypeMeta{
  1107. Kind: esv1.SecretStoreKind,
  1108. },
  1109. },
  1110. ref: esmetav1.SecretKeySelector{},
  1111. expected: nil,
  1112. },
  1113. {
  1114. desc: "secret store with the same namespace reference",
  1115. store: &esv1.SecretStore{
  1116. TypeMeta: metav1.TypeMeta{
  1117. Kind: esv1.SecretStoreKind,
  1118. },
  1119. ObjectMeta: metav1.ObjectMeta{
  1120. Namespace: "test",
  1121. },
  1122. },
  1123. ref: esmetav1.SecretKeySelector{
  1124. Namespace: new("test"),
  1125. },
  1126. expected: nil,
  1127. },
  1128. {
  1129. desc: "cluster secret store without namespace reference",
  1130. store: &esv1.ClusterSecretStore{
  1131. TypeMeta: metav1.TypeMeta{
  1132. Kind: esv1.ClusterSecretStoreKind,
  1133. },
  1134. },
  1135. ref: esmetav1.SecretKeySelector{},
  1136. expected: errRequireNamespace,
  1137. },
  1138. {
  1139. desc: "secret store with the different namespace reference",
  1140. store: &esv1.SecretStore{
  1141. TypeMeta: metav1.TypeMeta{
  1142. Kind: esv1.SecretStoreKind,
  1143. },
  1144. ObjectMeta: metav1.ObjectMeta{
  1145. Namespace: "test",
  1146. },
  1147. },
  1148. ref: esmetav1.SecretKeySelector{
  1149. Namespace: new("different"),
  1150. },
  1151. expected: errNamespaceNotAllowed,
  1152. },
  1153. }
  1154. for _, tt := range tests {
  1155. t.Run(tt.desc, func(t *testing.T) {
  1156. got := ValidateSecretSelector(tt.store, tt.ref)
  1157. if !errors.Is(got, tt.expected) {
  1158. t.Errorf("ValidateSecretSelector() got = %v, want = %v", got, tt.expected)
  1159. return
  1160. }
  1161. })
  1162. }
  1163. }
  1164. func TestValidateReferentSecretSelector(t *testing.T) {
  1165. tests := []struct {
  1166. desc string
  1167. store esv1.GenericStore
  1168. ref esmetav1.SecretKeySelector
  1169. expected error
  1170. }{
  1171. {
  1172. desc: "cluster secret store with namespace reference",
  1173. store: &esv1.ClusterSecretStore{
  1174. TypeMeta: metav1.TypeMeta{
  1175. Kind: esv1.ClusterSecretStoreKind,
  1176. },
  1177. },
  1178. ref: esmetav1.SecretKeySelector{
  1179. Namespace: new("test"),
  1180. },
  1181. expected: nil,
  1182. },
  1183. {
  1184. desc: "secret store without namespace reference",
  1185. store: &esv1.SecretStore{
  1186. TypeMeta: metav1.TypeMeta{
  1187. Kind: esv1.SecretStoreKind,
  1188. },
  1189. },
  1190. ref: esmetav1.SecretKeySelector{},
  1191. expected: nil,
  1192. },
  1193. {
  1194. desc: "secret store with the same namespace reference",
  1195. store: &esv1.SecretStore{
  1196. TypeMeta: metav1.TypeMeta{
  1197. Kind: esv1.SecretStoreKind,
  1198. },
  1199. ObjectMeta: metav1.ObjectMeta{
  1200. Namespace: "test",
  1201. },
  1202. },
  1203. ref: esmetav1.SecretKeySelector{
  1204. Namespace: new("test"),
  1205. },
  1206. expected: nil,
  1207. },
  1208. {
  1209. desc: "secret store with the different namespace reference",
  1210. store: &esv1.SecretStore{
  1211. TypeMeta: metav1.TypeMeta{
  1212. Kind: esv1.SecretStoreKind,
  1213. },
  1214. ObjectMeta: metav1.ObjectMeta{
  1215. Namespace: "test",
  1216. },
  1217. },
  1218. ref: esmetav1.SecretKeySelector{
  1219. Namespace: new("different"),
  1220. },
  1221. expected: errNamespaceNotAllowed,
  1222. },
  1223. }
  1224. for _, tt := range tests {
  1225. t.Run(tt.desc, func(t *testing.T) {
  1226. got := ValidateReferentSecretSelector(tt.store, tt.ref)
  1227. if !errors.Is(got, tt.expected) {
  1228. t.Errorf("ValidateReferentSecretSelector() got = %v, want = %v", got, tt.expected)
  1229. return
  1230. }
  1231. })
  1232. }
  1233. }
  1234. func TestValidateServiceAccountSelector(t *testing.T) {
  1235. tests := []struct {
  1236. desc string
  1237. store esv1.GenericStore
  1238. ref esmetav1.ServiceAccountSelector
  1239. expected error
  1240. }{
  1241. {
  1242. desc: "cluster secret store with namespace reference",
  1243. store: &esv1.ClusterSecretStore{
  1244. TypeMeta: metav1.TypeMeta{
  1245. Kind: esv1.ClusterSecretStoreKind,
  1246. },
  1247. },
  1248. ref: esmetav1.ServiceAccountSelector{
  1249. Namespace: new("test"),
  1250. },
  1251. expected: nil,
  1252. },
  1253. {
  1254. desc: "secret store without namespace reference",
  1255. store: &esv1.SecretStore{
  1256. TypeMeta: metav1.TypeMeta{
  1257. Kind: esv1.SecretStoreKind,
  1258. },
  1259. },
  1260. ref: esmetav1.ServiceAccountSelector{},
  1261. expected: nil,
  1262. },
  1263. {
  1264. desc: "secret store with the same namespace reference",
  1265. store: &esv1.SecretStore{
  1266. TypeMeta: metav1.TypeMeta{
  1267. Kind: esv1.SecretStoreKind,
  1268. },
  1269. ObjectMeta: metav1.ObjectMeta{
  1270. Namespace: "test",
  1271. },
  1272. },
  1273. ref: esmetav1.ServiceAccountSelector{
  1274. Namespace: new("test"),
  1275. },
  1276. expected: nil,
  1277. },
  1278. {
  1279. desc: "cluster secret store without namespace reference",
  1280. store: &esv1.ClusterSecretStore{
  1281. TypeMeta: metav1.TypeMeta{
  1282. Kind: esv1.ClusterSecretStoreKind,
  1283. },
  1284. },
  1285. ref: esmetav1.ServiceAccountSelector{},
  1286. expected: errRequireNamespace,
  1287. },
  1288. {
  1289. desc: "secret store with the different namespace reference",
  1290. store: &esv1.SecretStore{
  1291. TypeMeta: metav1.TypeMeta{
  1292. Kind: esv1.SecretStoreKind,
  1293. },
  1294. ObjectMeta: metav1.ObjectMeta{
  1295. Namespace: "test",
  1296. },
  1297. },
  1298. ref: esmetav1.ServiceAccountSelector{
  1299. Namespace: new("different"),
  1300. },
  1301. expected: errNamespaceNotAllowed,
  1302. },
  1303. }
  1304. for _, tt := range tests {
  1305. t.Run(tt.desc, func(t *testing.T) {
  1306. got := ValidateServiceAccountSelector(tt.store, tt.ref)
  1307. if !errors.Is(got, tt.expected) {
  1308. t.Errorf("ValidateServiceAccountSelector() got = %v, want = %v", got, tt.expected)
  1309. return
  1310. }
  1311. })
  1312. }
  1313. }
  1314. func TestValidateReferentServiceAccountSelector(t *testing.T) {
  1315. tests := []struct {
  1316. desc string
  1317. store esv1.GenericStore
  1318. ref esmetav1.ServiceAccountSelector
  1319. expected error
  1320. }{
  1321. {
  1322. desc: "cluster secret store with namespace reference",
  1323. store: &esv1.ClusterSecretStore{
  1324. TypeMeta: metav1.TypeMeta{
  1325. Kind: esv1.ClusterSecretStoreKind,
  1326. },
  1327. },
  1328. ref: esmetav1.ServiceAccountSelector{
  1329. Namespace: new("test"),
  1330. },
  1331. expected: nil,
  1332. },
  1333. {
  1334. desc: "secret store without namespace reference",
  1335. store: &esv1.SecretStore{
  1336. TypeMeta: metav1.TypeMeta{
  1337. Kind: esv1.SecretStoreKind,
  1338. },
  1339. },
  1340. ref: esmetav1.ServiceAccountSelector{},
  1341. expected: nil,
  1342. },
  1343. {
  1344. desc: "secret store with the same namespace reference",
  1345. store: &esv1.SecretStore{
  1346. TypeMeta: metav1.TypeMeta{
  1347. Kind: esv1.SecretStoreKind,
  1348. },
  1349. ObjectMeta: metav1.ObjectMeta{
  1350. Namespace: "test",
  1351. },
  1352. },
  1353. ref: esmetav1.ServiceAccountSelector{
  1354. Namespace: new("test"),
  1355. },
  1356. expected: nil,
  1357. },
  1358. {
  1359. desc: "secret store with the different namespace reference",
  1360. store: &esv1.SecretStore{
  1361. TypeMeta: metav1.TypeMeta{
  1362. Kind: esv1.SecretStoreKind,
  1363. },
  1364. ObjectMeta: metav1.ObjectMeta{
  1365. Namespace: "test",
  1366. },
  1367. },
  1368. ref: esmetav1.ServiceAccountSelector{
  1369. Namespace: new("different"),
  1370. },
  1371. expected: errNamespaceNotAllowed,
  1372. },
  1373. }
  1374. for _, tt := range tests {
  1375. t.Run(tt.desc, func(t *testing.T) {
  1376. got := ValidateReferentServiceAccountSelector(tt.store, tt.ref)
  1377. if !errors.Is(got, tt.expected) {
  1378. t.Errorf("ValidateReferentServiceAccountSelector() got = %v, want = %v", got, tt.expected)
  1379. return
  1380. }
  1381. })
  1382. }
  1383. }
  1384. func TestFetchCACertFromSourceRejectsCrossNamespaceCAProviderConfigMapForSecretStore(t *testing.T) {
  1385. fakeClient := clientfake.NewClientBuilder().WithObjects(
  1386. &v1.ConfigMap{
  1387. ObjectMeta: metav1.ObjectMeta{
  1388. Name: "ca-cm",
  1389. Namespace: "default",
  1390. },
  1391. Data: map[string]string{
  1392. "ca.crt": "local-cert",
  1393. },
  1394. },
  1395. &v1.ConfigMap{
  1396. ObjectMeta: metav1.ObjectMeta{
  1397. Name: "ca-cm",
  1398. Namespace: "other",
  1399. },
  1400. Data: map[string]string{
  1401. "ca.crt": "other-cert",
  1402. },
  1403. },
  1404. ).Build()
  1405. cert, err := FetchCACertFromSource(context.Background(), CreateCertOpts{
  1406. CAProvider: &esv1.CAProvider{
  1407. Type: esv1.CAProviderTypeConfigMap,
  1408. Name: "ca-cm",
  1409. Key: "ca.crt",
  1410. Namespace: Ptr("other"),
  1411. },
  1412. StoreKind: esv1.SecretStoreKind,
  1413. Namespace: "default",
  1414. Client: fakeClient,
  1415. })
  1416. assert.ErrorIs(t, err, errNamespaceNotAllowed)
  1417. assert.Nil(t, cert)
  1418. }
  1419. func TestFetchCACertFromSourceRejectsCrossNamespaceCAProviderSecretForSecretStore(t *testing.T) {
  1420. fakeClient := clientfake.NewClientBuilder().WithObjects(
  1421. &v1.Secret{
  1422. ObjectMeta: metav1.ObjectMeta{
  1423. Name: "ca-secret",
  1424. Namespace: "default",
  1425. },
  1426. Data: map[string][]byte{
  1427. "tls.crt": []byte("local-cert"),
  1428. },
  1429. },
  1430. &v1.Secret{
  1431. ObjectMeta: metav1.ObjectMeta{
  1432. Name: "ca-secret",
  1433. Namespace: "other",
  1434. },
  1435. Data: map[string][]byte{
  1436. "tls.crt": []byte("other-cert"),
  1437. },
  1438. },
  1439. ).Build()
  1440. cert, err := FetchCACertFromSource(context.Background(), CreateCertOpts{
  1441. CAProvider: &esv1.CAProvider{
  1442. Type: esv1.CAProviderTypeSecret,
  1443. Name: "ca-secret",
  1444. Key: "tls.crt",
  1445. Namespace: Ptr("other"),
  1446. },
  1447. StoreKind: esv1.SecretStoreKind,
  1448. Namespace: "default",
  1449. Client: fakeClient,
  1450. })
  1451. assert.ErrorIs(t, err, errNamespaceNotAllowed)
  1452. assert.Nil(t, cert)
  1453. }
  1454. const mockJWTToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiZXhwIjoxNzAwMDAwMDAwfQ.signature"
  1455. func TestParseJWTClaims(t *testing.T) {
  1456. // Mock JWT token with known payload
  1457. mockToken := mockJWTToken
  1458. claims, err := ParseJWTClaims(mockToken)
  1459. if err != nil {
  1460. t.Fatalf("Failed to get claims: %v", err)
  1461. }
  1462. if claims["sub"] != "1234567890" {
  1463. t.Errorf("Expected sub claim to be '1234567890', got %v", claims["sub"])
  1464. }
  1465. if claims["name"] != "John Doe" {
  1466. t.Errorf("Expected name claim to be 'John Doe', got %v", claims["name"])
  1467. }
  1468. }
  1469. func TestExtractJWTExpiration(t *testing.T) {
  1470. // Mock JWT token with known exp claim
  1471. mockToken := mockJWTToken
  1472. exp, err := ExtractJWTExpiration(mockToken)
  1473. if err != nil {
  1474. t.Fatalf("Failed to get token expiration: %v", err)
  1475. }
  1476. if exp != "1700000000" {
  1477. t.Errorf("Expected expiration to be '1700000000', got %s", exp)
  1478. }
  1479. }