| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- /*
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package parameterstore
- import (
- "context"
- "fmt"
- "strings"
- "testing"
- "github.com/aws/aws-sdk-go/aws"
- "github.com/aws/aws-sdk-go/service/ssm"
- "github.com/google/go-cmp/cmp"
- "github.com/stretchr/testify/assert"
- esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1"
- fake "github.com/external-secrets/external-secrets/pkg/provider/aws/parameterstore/fake"
- sess "github.com/external-secrets/external-secrets/pkg/provider/aws/session"
- )
- func TestConstructor(t *testing.T) {
- s, err := sess.New("1111", "2222", "foo", "", nil)
- assert.Nil(t, err)
- c, err := New(s)
- assert.Nil(t, err)
- assert.NotNil(t, c.client)
- }
- type parameterstoreTestCase struct {
- fakeClient *fake.Client
- apiInput *ssm.GetParameterInput
- apiOutput *ssm.GetParameterOutput
- remoteRef *esv1alpha1.ExternalSecretDataRemoteRef
- apiErr error
- expectError string
- expectedSecret string
- expectedData map[string]string
- }
- func makeValidParameterStoreTestCase() *parameterstoreTestCase {
- return ¶meterstoreTestCase{
- fakeClient: &fake.Client{},
- apiInput: makeValidAPIInput(),
- apiOutput: makeValidAPIOutput(),
- remoteRef: makeValidRemoteRef(),
- apiErr: nil,
- expectError: "",
- expectedSecret: "",
- expectedData: make(map[string]string),
- }
- }
- func makeValidAPIInput() *ssm.GetParameterInput {
- return &ssm.GetParameterInput{
- Name: aws.String("/baz"),
- WithDecryption: aws.Bool(true),
- }
- }
- func makeValidAPIOutput() *ssm.GetParameterOutput {
- return &ssm.GetParameterOutput{
- Parameter: &ssm.Parameter{
- Value: aws.String("RRRRR"),
- },
- }
- }
- func makeValidRemoteRef() *esv1alpha1.ExternalSecretDataRemoteRef {
- return &esv1alpha1.ExternalSecretDataRemoteRef{
- Key: "/baz",
- }
- }
- func makeValidParameterStoreTestCaseCustom(tweaks ...func(pstc *parameterstoreTestCase)) *parameterstoreTestCase {
- pstc := makeValidParameterStoreTestCase()
- for _, fn := range tweaks {
- fn(pstc)
- }
- pstc.fakeClient.WithValue(pstc.apiInput, pstc.apiOutput, pstc.apiErr)
- return pstc
- }
- // test the ssm<->aws interface
- // make sure correct values are passed and errors are handled accordingly.
- func TestGetSecret(t *testing.T) {
- // good case: key is passed in, output is sent back
- setSecretString := func(pstc *parameterstoreTestCase) {
- pstc.apiOutput.Parameter.Value = aws.String("RRRRR")
- pstc.expectedSecret = "RRRRR"
- }
- // good case: extract property
- setExtractProperty := func(pstc *parameterstoreTestCase) {
- pstc.apiOutput.Parameter.Value = aws.String(`{"/shmoo": "bang"}`)
- pstc.expectedSecret = "bang"
- pstc.remoteRef.Property = "/shmoo"
- }
- // bad case: missing property
- setMissingProperty := func(pstc *parameterstoreTestCase) {
- pstc.apiOutput.Parameter.Value = aws.String(`{"/shmoo": "bang"}`)
- pstc.remoteRef.Property = "INVALPROP"
- pstc.expectError = "key INVALPROP does not exist in secret"
- }
- // bad case: extract property failure due to invalid json
- setPropertyFail := func(pstc *parameterstoreTestCase) {
- pstc.apiOutput.Parameter.Value = aws.String(`------`)
- pstc.remoteRef.Property = "INVALPROP"
- pstc.expectError = "key INVALPROP does not exist in secret"
- }
- // bad case: parameter.Value may be nil but binary is set
- setParameterValueNil := func(pstc *parameterstoreTestCase) {
- pstc.apiOutput.Parameter.Value = nil
- pstc.expectError = "parameter value is nil for key"
- }
- // base case: api output return error
- setAPIError := func(pstc *parameterstoreTestCase) {
- pstc.apiOutput = &ssm.GetParameterOutput{}
- pstc.apiErr = fmt.Errorf("oh no")
- pstc.expectError = "oh no"
- }
- successCases := []*parameterstoreTestCase{
- makeValidParameterStoreTestCaseCustom(setSecretString),
- makeValidParameterStoreTestCaseCustom(setExtractProperty),
- makeValidParameterStoreTestCaseCustom(setMissingProperty),
- makeValidParameterStoreTestCaseCustom(setPropertyFail),
- makeValidParameterStoreTestCaseCustom(setParameterValueNil),
- makeValidParameterStoreTestCaseCustom(setAPIError),
- }
- ps := ParameterStore{}
- for k, v := range successCases {
- ps.client = v.fakeClient
- out, err := ps.GetSecret(context.Background(), *v.remoteRef)
- if !ErrorContains(err, v.expectError) {
- t.Errorf("[%d] unexpected error: %s, expected: '%s'", k, err.Error(), v.expectError)
- }
- if cmp.Equal(out, v.expectedSecret) {
- t.Errorf("[%d] unexpected secret data: expected %#v, got %#v", k, v.expectedSecret, out)
- }
- }
- }
- func TestGetSecretMap(t *testing.T) {
- // good case: default version & deserialization
- setDeserialization := func(pstc *parameterstoreTestCase) {
- pstc.apiOutput.Parameter.Value = aws.String(`{"foo":"bar"}`)
- pstc.expectedData["foo"] = "bar"
- }
- // bad case: api error returned
- setAPIError := func(pstc *parameterstoreTestCase) {
- pstc.apiOutput.Parameter = &ssm.Parameter{}
- pstc.expectError = "some api err"
- pstc.apiErr = fmt.Errorf("some api err")
- }
- // bad case: invalid json
- setInvalidJSON := func(pstc *parameterstoreTestCase) {
- pstc.apiOutput.Parameter.Value = aws.String(`-----------------`)
- pstc.expectError = "unable to unmarshal secret"
- }
- successCases := []*parameterstoreTestCase{
- makeValidParameterStoreTestCaseCustom(setDeserialization),
- makeValidParameterStoreTestCaseCustom(setAPIError),
- makeValidParameterStoreTestCaseCustom(setInvalidJSON),
- }
- ps := ParameterStore{}
- for k, v := range successCases {
- ps.client = v.fakeClient
- out, err := ps.GetSecretMap(context.Background(), *v.remoteRef)
- if !ErrorContains(err, v.expectError) {
- t.Errorf("[%d] unexpected error: %s, expected: '%s'", k, err.Error(), v.expectError)
- }
- if cmp.Equal(out, v.expectedData) {
- t.Errorf("[%d] unexpected secret data: expected %#v, got %#v", k, v.expectedData, out)
- }
- }
- }
- func ErrorContains(out error, want string) bool {
- if out == nil {
- return want == ""
- }
- if want == "" {
- return false
- }
- return strings.Contains(out.Error(), want)
- }
|