secretsmanager_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 secretsmanager
  13. import (
  14. "context"
  15. "errors"
  16. "fmt"
  17. "strings"
  18. "testing"
  19. "github.com/aws/aws-sdk-go/aws"
  20. "github.com/aws/aws-sdk-go/aws/awserr"
  21. awssm "github.com/aws/aws-sdk-go/service/secretsmanager"
  22. "github.com/google/go-cmp/cmp"
  23. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  24. esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
  25. fakesm "github.com/external-secrets/external-secrets/pkg/provider/aws/secretsmanager/fake"
  26. )
  27. type secretsManagerTestCase struct {
  28. fakeClient *fakesm.Client
  29. apiInput *awssm.GetSecretValueInput
  30. apiOutput *awssm.GetSecretValueOutput
  31. remoteRef *esv1beta1.ExternalSecretDataRemoteRef
  32. apiErr error
  33. expectError string
  34. expectedSecret string
  35. // for testing secretmap
  36. expectedData map[string][]byte
  37. // for testing caching
  38. expectedCounter *int
  39. }
  40. const unexpectedErrorString = "[%d] unexpected error: %s, expected: '%s'"
  41. func makeValidSecretsManagerTestCase() *secretsManagerTestCase {
  42. smtc := secretsManagerTestCase{
  43. fakeClient: fakesm.NewClient(),
  44. apiInput: makeValidAPIInput(),
  45. remoteRef: makeValidRemoteRef(),
  46. apiOutput: makeValidAPIOutput(),
  47. apiErr: nil,
  48. expectError: "",
  49. expectedSecret: "",
  50. expectedData: map[string][]byte{},
  51. }
  52. smtc.fakeClient.WithValue(smtc.apiInput, smtc.apiOutput, smtc.apiErr)
  53. return &smtc
  54. }
  55. func makeValidRemoteRef() *esv1beta1.ExternalSecretDataRemoteRef {
  56. return &esv1beta1.ExternalSecretDataRemoteRef{
  57. Key: "/baz",
  58. Version: "AWSCURRENT",
  59. }
  60. }
  61. func makeValidAPIInput() *awssm.GetSecretValueInput {
  62. return &awssm.GetSecretValueInput{
  63. SecretId: aws.String("/baz"),
  64. VersionStage: aws.String("AWSCURRENT"),
  65. }
  66. }
  67. func makeValidAPIOutput() *awssm.GetSecretValueOutput {
  68. return &awssm.GetSecretValueOutput{
  69. SecretString: aws.String(""),
  70. }
  71. }
  72. func makeValidSecretsManagerTestCaseCustom(tweaks ...func(smtc *secretsManagerTestCase)) *secretsManagerTestCase {
  73. smtc := makeValidSecretsManagerTestCase()
  74. for _, fn := range tweaks {
  75. fn(smtc)
  76. }
  77. smtc.fakeClient.WithValue(smtc.apiInput, smtc.apiOutput, smtc.apiErr)
  78. return smtc
  79. }
  80. // This case can be shared by both GetSecret and GetSecretMap tests.
  81. // bad case: set apiErr.
  82. var setAPIErr = func(smtc *secretsManagerTestCase) {
  83. smtc.apiErr = fmt.Errorf("oh no")
  84. smtc.expectError = "oh no"
  85. }
  86. // test the sm<->aws interface
  87. // make sure correct values are passed and errors are handled accordingly.
  88. func TestSecretsManagerGetSecret(t *testing.T) {
  89. // good case: default version is set
  90. // key is passed in, output is sent back
  91. setSecretString := func(smtc *secretsManagerTestCase) {
  92. smtc.apiOutput.SecretString = aws.String("testtesttest")
  93. smtc.expectedSecret = "testtesttest"
  94. }
  95. // good case: extract property
  96. // Testing that the property exists in the SecretString
  97. setRemoteRefPropertyExistsInKey := func(smtc *secretsManagerTestCase) {
  98. smtc.remoteRef.Property = "/shmoo"
  99. smtc.apiOutput.SecretString = aws.String(`{"/shmoo": "bang"}`)
  100. smtc.expectedSecret = "bang"
  101. }
  102. // bad case: missing property
  103. setRemoteRefMissingProperty := func(smtc *secretsManagerTestCase) {
  104. smtc.remoteRef.Property = "INVALPROP"
  105. smtc.expectError = "key INVALPROP does not exist in secret"
  106. }
  107. // bad case: extract property failure due to invalid json
  108. setRemoteRefMissingPropertyInvalidJSON := func(smtc *secretsManagerTestCase) {
  109. smtc.remoteRef.Property = "INVALPROP"
  110. smtc.apiOutput.SecretString = aws.String(`------`)
  111. smtc.expectError = "key INVALPROP does not exist in secret"
  112. }
  113. // good case: set .SecretString to nil but set binary with value
  114. setSecretBinaryNotSecretString := func(smtc *secretsManagerTestCase) {
  115. smtc.apiOutput.SecretBinary = []byte("yesplease")
  116. // needs to be set as nil, empty quotes ("") is considered existing
  117. smtc.apiOutput.SecretString = nil
  118. smtc.expectedSecret = "yesplease"
  119. }
  120. // bad case: both .SecretString and .SecretBinary are nil
  121. setSecretBinaryAndSecretStringToNil := func(smtc *secretsManagerTestCase) {
  122. smtc.apiOutput.SecretBinary = nil
  123. smtc.apiOutput.SecretString = nil
  124. smtc.expectError = "no secret string nor binary for key"
  125. }
  126. // good case: secretOut.SecretBinary JSON parsing
  127. setNestedSecretValueJSONParsing := func(smtc *secretsManagerTestCase) {
  128. smtc.apiOutput.SecretString = nil
  129. smtc.apiOutput.SecretBinary = []byte(`{"foobar":{"baz":"nestedval"}}`)
  130. smtc.remoteRef.Property = "foobar.baz"
  131. smtc.expectedSecret = "nestedval"
  132. }
  133. // good case: secretOut.SecretBinary no JSON parsing if name on key
  134. setSecretValueWithDot := func(smtc *secretsManagerTestCase) {
  135. smtc.apiOutput.SecretString = nil
  136. smtc.apiOutput.SecretBinary = []byte(`{"foobar.baz":"nestedval"}`)
  137. smtc.remoteRef.Property = "foobar.baz"
  138. smtc.expectedSecret = "nestedval"
  139. }
  140. // good case: custom version stage set
  141. setCustomVersionStage := func(smtc *secretsManagerTestCase) {
  142. smtc.apiInput.VersionStage = aws.String("1234")
  143. smtc.remoteRef.Version = "1234"
  144. smtc.apiOutput.SecretString = aws.String("FOOBA!")
  145. smtc.expectedSecret = "FOOBA!"
  146. }
  147. // good case: custom version id set
  148. setCustomVersionID := func(smtc *secretsManagerTestCase) {
  149. smtc.apiInput.VersionStage = nil
  150. smtc.apiInput.VersionId = aws.String("1234-5678")
  151. smtc.remoteRef.Version = "uuid/1234-5678"
  152. smtc.apiOutput.SecretString = aws.String("myvalue")
  153. smtc.expectedSecret = "myvalue"
  154. }
  155. successCases := []*secretsManagerTestCase{
  156. makeValidSecretsManagerTestCase(),
  157. makeValidSecretsManagerTestCaseCustom(setSecretString),
  158. makeValidSecretsManagerTestCaseCustom(setRemoteRefPropertyExistsInKey),
  159. makeValidSecretsManagerTestCaseCustom(setRemoteRefMissingProperty),
  160. makeValidSecretsManagerTestCaseCustom(setRemoteRefMissingPropertyInvalidJSON),
  161. makeValidSecretsManagerTestCaseCustom(setSecretBinaryNotSecretString),
  162. makeValidSecretsManagerTestCaseCustom(setSecretBinaryAndSecretStringToNil),
  163. makeValidSecretsManagerTestCaseCustom(setNestedSecretValueJSONParsing),
  164. makeValidSecretsManagerTestCaseCustom(setSecretValueWithDot),
  165. makeValidSecretsManagerTestCaseCustom(setCustomVersionStage),
  166. makeValidSecretsManagerTestCaseCustom(setCustomVersionID),
  167. makeValidSecretsManagerTestCaseCustom(setAPIErr),
  168. }
  169. for k, v := range successCases {
  170. sm := SecretsManager{
  171. cache: make(map[string]*awssm.GetSecretValueOutput),
  172. client: v.fakeClient,
  173. }
  174. out, err := sm.GetSecret(context.Background(), *v.remoteRef)
  175. if !ErrorContains(err, v.expectError) {
  176. t.Errorf(unexpectedErrorString, k, err.Error(), v.expectError)
  177. }
  178. if err == nil && string(out) != v.expectedSecret {
  179. t.Errorf("[%d] unexpected secret: expected %s, got %s", k, v.expectedSecret, string(out))
  180. }
  181. }
  182. }
  183. func TestCaching(t *testing.T) {
  184. fakeClient := fakesm.NewClient()
  185. // good case: first call, since we are using the same key, results should be cached and the counter should not go
  186. // over 1
  187. firstCall := func(smtc *secretsManagerTestCase) {
  188. smtc.apiOutput.SecretString = aws.String(`{"foo":"bar", "bar":"vodka"}`)
  189. smtc.remoteRef.Property = "foo"
  190. smtc.expectedSecret = "bar"
  191. smtc.expectedCounter = aws.Int(1)
  192. smtc.fakeClient = fakeClient
  193. }
  194. secondCall := func(smtc *secretsManagerTestCase) {
  195. smtc.apiOutput.SecretString = aws.String(`{"foo":"bar", "bar":"vodka"}`)
  196. smtc.remoteRef.Property = "bar"
  197. smtc.expectedSecret = "vodka"
  198. smtc.expectedCounter = aws.Int(1)
  199. smtc.fakeClient = fakeClient
  200. }
  201. notCachedCall := func(smtc *secretsManagerTestCase) {
  202. smtc.apiOutput.SecretString = aws.String(`{"sheldon":"bazinga", "bar":"foo"}`)
  203. smtc.remoteRef.Property = "sheldon"
  204. smtc.expectedSecret = "bazinga"
  205. smtc.expectedCounter = aws.Int(2)
  206. smtc.fakeClient = fakeClient
  207. smtc.apiInput.SecretId = aws.String("xyz")
  208. smtc.remoteRef.Key = "xyz" // it should reset the cache since the key is different
  209. }
  210. cachedCases := []*secretsManagerTestCase{
  211. makeValidSecretsManagerTestCaseCustom(firstCall),
  212. makeValidSecretsManagerTestCaseCustom(firstCall),
  213. makeValidSecretsManagerTestCaseCustom(secondCall),
  214. makeValidSecretsManagerTestCaseCustom(notCachedCall),
  215. }
  216. sm := SecretsManager{
  217. cache: make(map[string]*awssm.GetSecretValueOutput),
  218. }
  219. for k, v := range cachedCases {
  220. sm.client = v.fakeClient
  221. out, err := sm.GetSecret(context.Background(), *v.remoteRef)
  222. if !ErrorContains(err, v.expectError) {
  223. t.Errorf(unexpectedErrorString, k, err.Error(), v.expectError)
  224. }
  225. if err == nil && string(out) != v.expectedSecret {
  226. t.Errorf("[%d] unexpected secret: expected %s, got %s", k, v.expectedSecret, string(out))
  227. }
  228. if v.expectedCounter != nil && v.fakeClient.ExecutionCounter != *v.expectedCounter {
  229. t.Errorf("[%d] unexpected counter value: expected %d, got %d", k, v.expectedCounter, v.fakeClient.ExecutionCounter)
  230. }
  231. }
  232. }
  233. func TestGetSecretMap(t *testing.T) {
  234. // good case: default version & deserialization
  235. setDeserialization := func(smtc *secretsManagerTestCase) {
  236. smtc.apiOutput.SecretString = aws.String(`{"foo":"bar"}`)
  237. smtc.expectedData["foo"] = []byte("bar")
  238. }
  239. // good case: nested json
  240. setNestedJSON := func(smtc *secretsManagerTestCase) {
  241. smtc.apiOutput.SecretString = aws.String(`{"foobar":{"baz":"nestedval"}}`)
  242. smtc.expectedData["foobar"] = []byte("{\"baz\":\"nestedval\"}")
  243. }
  244. // good case: caching
  245. cachedMap := func(smtc *secretsManagerTestCase) {
  246. smtc.apiOutput.SecretString = aws.String(`{"foo":"bar", "plus": "one"}`)
  247. smtc.expectedData["foo"] = []byte("bar")
  248. smtc.expectedData["plus"] = []byte("one")
  249. smtc.expectedCounter = aws.Int(1)
  250. }
  251. // bad case: invalid json
  252. setInvalidJSON := func(smtc *secretsManagerTestCase) {
  253. smtc.apiOutput.SecretString = aws.String(`-----------------`)
  254. smtc.expectError = "unable to unmarshal secret"
  255. }
  256. successCases := []*secretsManagerTestCase{
  257. makeValidSecretsManagerTestCaseCustom(setDeserialization),
  258. makeValidSecretsManagerTestCaseCustom(setNestedJSON),
  259. makeValidSecretsManagerTestCaseCustom(setAPIErr),
  260. makeValidSecretsManagerTestCaseCustom(setInvalidJSON),
  261. makeValidSecretsManagerTestCaseCustom(cachedMap),
  262. }
  263. for k, v := range successCases {
  264. sm := SecretsManager{
  265. cache: make(map[string]*awssm.GetSecretValueOutput),
  266. client: v.fakeClient,
  267. }
  268. out, err := sm.GetSecretMap(context.Background(), *v.remoteRef)
  269. if !ErrorContains(err, v.expectError) {
  270. t.Errorf(unexpectedErrorString, k, err.Error(), v.expectError)
  271. }
  272. if err == nil && !cmp.Equal(out, v.expectedData) {
  273. t.Errorf("[%d] unexpected secret data: expected %#v, got %#v", k, v.expectedData, out)
  274. }
  275. if v.expectedCounter != nil && v.fakeClient.ExecutionCounter != *v.expectedCounter {
  276. t.Errorf("[%d] unexpected counter value: expected %d, got %d", k, v.expectedCounter, v.fakeClient.ExecutionCounter)
  277. }
  278. }
  279. }
  280. func ErrorContains(out error, want string) bool {
  281. if out == nil {
  282. return want == ""
  283. }
  284. if want == "" {
  285. return false
  286. }
  287. return strings.Contains(out.Error(), want)
  288. }
  289. type fakeRef struct {
  290. key string
  291. }
  292. func (f fakeRef) GetRemoteKey() string {
  293. return f.key
  294. }
  295. func TestSetSecret(t *testing.T) {
  296. managedBy := managedBy
  297. notManagedBy := "not-managed-by"
  298. secretValue := []byte("fake-value")
  299. externalSecrets := externalSecrets
  300. noPermission := errors.New("no permission")
  301. arn := "arn:aws:secretsmanager:us-east-1:702902267788:secret:foo-bar5-Robbgh"
  302. getSecretCorrectErr := awssm.ResourceNotFoundException{}
  303. getSecretWrongErr := awssm.InvalidRequestException{}
  304. secretOutput := &awssm.CreateSecretOutput{
  305. ARN: &arn,
  306. }
  307. externalSecretsTag := []*awssm.Tag{
  308. {
  309. Key: &managedBy,
  310. Value: &externalSecrets,
  311. },
  312. }
  313. externalSecretsTagFaulty := []*awssm.Tag{
  314. {
  315. Key: &notManagedBy,
  316. Value: &externalSecrets,
  317. },
  318. }
  319. tagSecretOutput := &awssm.DescribeSecretOutput{
  320. ARN: &arn,
  321. Tags: externalSecretsTag,
  322. }
  323. tagSecretOutputFaulty := &awssm.DescribeSecretOutput{
  324. ARN: &arn,
  325. Tags: externalSecretsTagFaulty,
  326. }
  327. secretValueOutput := &awssm.GetSecretValueOutput{
  328. ARN: &arn,
  329. }
  330. secretValueOutput2 := &awssm.GetSecretValueOutput{
  331. ARN: &arn,
  332. SecretBinary: secretValue,
  333. }
  334. blankSecretValueOutput := &awssm.GetSecretValueOutput{}
  335. putSecretOutput := &awssm.PutSecretValueOutput{
  336. ARN: &arn,
  337. }
  338. type args struct {
  339. store *esv1beta1.AWSProvider
  340. client fakesm.Client
  341. }
  342. type want struct {
  343. err error
  344. }
  345. tests := map[string]struct {
  346. reason string
  347. args args
  348. want want
  349. }{
  350. "SetSecretSucceedsWithExistingSecret": {
  351. reason: "a secret can be pushed to aws secrets manager when it already exists",
  352. args: args{
  353. store: makeValidSecretStore().Spec.Provider.AWS,
  354. client: fakesm.Client{
  355. GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(secretValueOutput, nil),
  356. CreateSecretWithContextFn: fakesm.NewCreateSecretWithContextFn(secretOutput, nil),
  357. PutSecretValueWithContextFn: fakesm.NewPutSecretValueWithContextFn(putSecretOutput, nil),
  358. DescribeSecretWithContextFn: fakesm.NewDescribeSecretWithContextFn(tagSecretOutput, nil),
  359. },
  360. },
  361. want: want{
  362. err: nil,
  363. },
  364. },
  365. "SetSecretSucceedsWithNewSecret": {
  366. reason: "a secret can be pushed to aws secrets manager if it doesn't already exist",
  367. args: args{
  368. store: makeValidSecretStore().Spec.Provider.AWS,
  369. client: fakesm.Client{
  370. GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(blankSecretValueOutput, &getSecretCorrectErr),
  371. CreateSecretWithContextFn: fakesm.NewCreateSecretWithContextFn(secretOutput, nil),
  372. },
  373. },
  374. want: want{
  375. err: nil,
  376. },
  377. },
  378. "SetSecretCreateSecretFails": {
  379. reason: "CreateSecretWithContext returns an error if it fails",
  380. args: args{
  381. store: makeValidSecretStore().Spec.Provider.AWS,
  382. client: fakesm.Client{
  383. GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(blankSecretValueOutput, &getSecretCorrectErr),
  384. CreateSecretWithContextFn: fakesm.NewCreateSecretWithContextFn(nil, noPermission),
  385. },
  386. },
  387. want: want{
  388. err: noPermission,
  389. },
  390. },
  391. "SetSecretGetSecretFails": {
  392. reason: "GetSecretValueWithContext returns an error if it fails",
  393. args: args{
  394. store: makeValidSecretStore().Spec.Provider.AWS,
  395. client: fakesm.Client{
  396. GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(blankSecretValueOutput, noPermission),
  397. },
  398. },
  399. want: want{
  400. err: noPermission,
  401. },
  402. },
  403. "SetSecretWillNotPushSameSecret": {
  404. reason: "secret with the same value will not be pushed",
  405. args: args{
  406. store: makeValidSecretStore().Spec.Provider.AWS,
  407. client: fakesm.Client{
  408. GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(secretValueOutput2, nil),
  409. DescribeSecretWithContextFn: fakesm.NewDescribeSecretWithContextFn(tagSecretOutput, nil),
  410. },
  411. },
  412. want: want{
  413. err: nil,
  414. },
  415. },
  416. "SetSecretPutSecretValueFails": {
  417. reason: "PutSecretValueWithContext returns an error if it fails",
  418. args: args{
  419. store: makeValidSecretStore().Spec.Provider.AWS,
  420. client: fakesm.Client{
  421. GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(secretValueOutput, nil),
  422. PutSecretValueWithContextFn: fakesm.NewPutSecretValueWithContextFn(nil, noPermission),
  423. DescribeSecretWithContextFn: fakesm.NewDescribeSecretWithContextFn(tagSecretOutput, nil),
  424. },
  425. },
  426. want: want{
  427. err: noPermission,
  428. },
  429. },
  430. "SetSecretWrongGetSecretErrFails": {
  431. reason: "GetSecretValueWithContext errors out when anything except awssm.ErrCodeResourceNotFoundException",
  432. args: args{
  433. store: makeValidSecretStore().Spec.Provider.AWS,
  434. client: fakesm.Client{
  435. GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(blankSecretValueOutput, &getSecretWrongErr),
  436. },
  437. },
  438. want: want{
  439. err: &getSecretWrongErr,
  440. },
  441. },
  442. "SetSecretDescribeSecretFails": {
  443. reason: "secret cannot be described",
  444. args: args{
  445. store: makeValidSecretStore().Spec.Provider.AWS,
  446. client: fakesm.Client{
  447. GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(secretValueOutput, nil),
  448. DescribeSecretWithContextFn: fakesm.NewDescribeSecretWithContextFn(nil, noPermission),
  449. },
  450. },
  451. want: want{
  452. err: noPermission,
  453. },
  454. },
  455. "SetSecretDoesNotOverwriteUntaggedSecret": {
  456. reason: "secret cannot be described",
  457. args: args{
  458. store: makeValidSecretStore().Spec.Provider.AWS,
  459. client: fakesm.Client{
  460. GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(secretValueOutput, nil),
  461. DescribeSecretWithContextFn: fakesm.NewDescribeSecretWithContextFn(tagSecretOutputFaulty, nil),
  462. },
  463. },
  464. want: want{
  465. err: fmt.Errorf("secret not managed by external-secrets"),
  466. },
  467. },
  468. }
  469. for name, tc := range tests {
  470. t.Run(name, func(t *testing.T) {
  471. ref := fakeRef{key: "fake-key"}
  472. sm := SecretsManager{
  473. client: &tc.args.client,
  474. }
  475. err := sm.PushSecret(context.Background(), []byte("fake-value"), ref)
  476. // Error nil XOR tc.want.err nil
  477. if ((err == nil) || (tc.want.err == nil)) && !((err == nil) && (tc.want.err == nil)) {
  478. t.Errorf("\nTesting SetSecret:\nName: %v\nReason: %v\nWant error: %v\nGot error: %v", name, tc.reason, tc.want.err, err)
  479. }
  480. // if errors are the same type but their contents do not match
  481. if err != nil && tc.want.err != nil {
  482. if !strings.Contains(err.Error(), tc.want.err.Error()) {
  483. t.Errorf("\nTesting SetSecret:\nName: %v\nReason: %v\nWant error: %v\nGot error got nil", name, tc.reason, tc.want.err)
  484. }
  485. }
  486. })
  487. }
  488. }
  489. func TestDeleteSecret(t *testing.T) {
  490. fakeClient := fakesm.Client{}
  491. managed := managedBy
  492. manager := externalSecrets
  493. secretTag := awssm.Tag{
  494. Key: &managed,
  495. Value: &manager,
  496. }
  497. type args struct {
  498. client fakesm.Client
  499. getSecretOutput *awssm.GetSecretValueOutput
  500. describeSecretOutput *awssm.DescribeSecretOutput
  501. deleteSecretOutput *awssm.DeleteSecretOutput
  502. getSecretErr error
  503. describeSecretErr error
  504. deleteSecretErr error
  505. }
  506. type want struct {
  507. err error
  508. }
  509. type testCase struct {
  510. args args
  511. want want
  512. reason string
  513. }
  514. tests := map[string]testCase{
  515. "Deletes Successfully": {
  516. args: args{
  517. client: fakeClient,
  518. getSecretOutput: &awssm.GetSecretValueOutput{},
  519. describeSecretOutput: &awssm.DescribeSecretOutput{
  520. Tags: []*awssm.Tag{&secretTag},
  521. },
  522. deleteSecretOutput: &awssm.DeleteSecretOutput{},
  523. getSecretErr: nil,
  524. describeSecretErr: nil,
  525. deleteSecretErr: nil,
  526. },
  527. want: want{
  528. err: nil,
  529. },
  530. reason: "",
  531. },
  532. "Not Managed by ESO": {
  533. args: args{
  534. client: fakeClient,
  535. getSecretOutput: &awssm.GetSecretValueOutput{},
  536. describeSecretOutput: &awssm.DescribeSecretOutput{
  537. Tags: []*awssm.Tag{},
  538. },
  539. deleteSecretOutput: &awssm.DeleteSecretOutput{},
  540. getSecretErr: nil,
  541. describeSecretErr: nil,
  542. deleteSecretErr: nil,
  543. },
  544. want: want{
  545. err: nil,
  546. },
  547. reason: "",
  548. },
  549. "Failed to get Tags": {
  550. args: args{
  551. client: fakeClient,
  552. getSecretOutput: &awssm.GetSecretValueOutput{},
  553. describeSecretOutput: nil,
  554. deleteSecretOutput: nil,
  555. getSecretErr: nil,
  556. describeSecretErr: errors.New("failed to get tags"),
  557. deleteSecretErr: nil,
  558. },
  559. want: want{
  560. err: errors.New("failed to get tags"),
  561. },
  562. reason: "",
  563. },
  564. "Secret Not Found": {
  565. args: args{
  566. client: fakeClient,
  567. getSecretOutput: nil,
  568. describeSecretOutput: nil,
  569. deleteSecretOutput: nil,
  570. getSecretErr: awserr.New(awssm.ErrCodeResourceNotFoundException, "not here, sorry dude", nil),
  571. describeSecretErr: nil,
  572. deleteSecretErr: nil,
  573. },
  574. want: want{
  575. err: nil,
  576. },
  577. },
  578. "Not expected AWS error": {
  579. args: args{
  580. client: fakeClient,
  581. getSecretOutput: nil,
  582. describeSecretOutput: nil,
  583. deleteSecretOutput: nil,
  584. getSecretErr: awserr.New(awssm.ErrCodeEncryptionFailure, "aws unavailable", nil),
  585. describeSecretErr: nil,
  586. deleteSecretErr: nil,
  587. },
  588. want: want{
  589. err: errors.New("aws unavailable"),
  590. },
  591. },
  592. "unexpected error": {
  593. args: args{
  594. client: fakeClient,
  595. getSecretOutput: nil,
  596. describeSecretOutput: nil,
  597. deleteSecretOutput: nil,
  598. getSecretErr: errors.New("timeout"),
  599. describeSecretErr: nil,
  600. deleteSecretErr: nil,
  601. },
  602. want: want{
  603. err: errors.New("timeout"),
  604. },
  605. },
  606. }
  607. for name, tc := range tests {
  608. t.Run(name, func(t *testing.T) {
  609. ref := fakeRef{key: "fake-key"}
  610. sm := SecretsManager{
  611. client: &tc.args.client,
  612. }
  613. tc.args.client.GetSecretValueWithContextFn = fakesm.NewGetSecretValueWithContextFn(tc.args.getSecretOutput, tc.args.getSecretErr)
  614. tc.args.client.DescribeSecretWithContextFn = fakesm.NewDescribeSecretWithContextFn(tc.args.describeSecretOutput, tc.args.describeSecretErr)
  615. tc.args.client.DeleteSecretWithContextFn = fakesm.NewDeleteSecretWithContextFn(tc.args.deleteSecretOutput, tc.args.deleteSecretErr)
  616. err := sm.DeleteSecret(context.TODO(), ref)
  617. // Error nil XOR tc.want.err nil
  618. if ((err == nil) || (tc.want.err == nil)) && !((err == nil) && (tc.want.err == nil)) {
  619. t.Errorf("\nTesting SetSecret:\nName: %v\nReason: %v\nWant error: %v\nGot error: %v", name, tc.reason, tc.want.err, err)
  620. }
  621. // if errors are the same type but their contents do not match
  622. if err != nil && tc.want.err != nil {
  623. if !strings.Contains(err.Error(), tc.want.err.Error()) {
  624. t.Errorf("\nTesting SetSecret:\nName: %v\nReason: %v\nWant error: %v\nGot error got nil", name, tc.reason, tc.want.err)
  625. }
  626. }
  627. })
  628. }
  629. }
  630. func makeValidSecretStore() *esv1beta1.SecretStore {
  631. return &esv1beta1.SecretStore{
  632. ObjectMeta: metav1.ObjectMeta{
  633. Name: "aws-secret-store",
  634. Namespace: "default",
  635. },
  636. Spec: esv1beta1.SecretStoreSpec{
  637. Provider: &esv1beta1.SecretStoreProvider{
  638. AWS: &esv1beta1.AWSProvider{
  639. Service: esv1beta1.AWSServiceSecretsManager,
  640. Region: "eu-west-2",
  641. },
  642. },
  643. },
  644. }
  645. }