mirror of
https://github.com/external-secrets/external-secrets.git
synced 2024-12-15 17:51:01 +00:00
chore: add tests for AWS/SM (#3057)
Signed-off-by: Moritz Johner <beller.moritz@googlemail.com>
This commit is contained in:
parent
c45eaca651
commit
58cb47cc06
2 changed files with 291 additions and 2 deletions
|
@ -34,6 +34,7 @@ type Client struct {
|
|||
PutSecretValueWithContextFn PutSecretValueWithContextFn
|
||||
DescribeSecretWithContextFn DescribeSecretWithContextFn
|
||||
DeleteSecretWithContextFn DeleteSecretWithContextFn
|
||||
ListSecretsFn ListSecretsFn
|
||||
}
|
||||
|
||||
type CreateSecretWithContextFn func(aws.Context, *awssm.CreateSecretInput, ...request.Option) (*awssm.CreateSecretOutput, error)
|
||||
|
@ -41,6 +42,7 @@ type GetSecretValueWithContextFn func(aws.Context, *awssm.GetSecretValueInput, .
|
|||
type PutSecretValueWithContextFn func(aws.Context, *awssm.PutSecretValueInput, ...request.Option) (*awssm.PutSecretValueOutput, error)
|
||||
type DescribeSecretWithContextFn func(aws.Context, *awssm.DescribeSecretInput, ...request.Option) (*awssm.DescribeSecretOutput, error)
|
||||
type DeleteSecretWithContextFn func(ctx aws.Context, input *awssm.DeleteSecretInput, opts ...request.Option) (*awssm.DeleteSecretOutput, error)
|
||||
type ListSecretsFn func(ctx aws.Context, input *awssm.ListSecretsInput, opts ...request.Option) (*awssm.ListSecretsOutput, error)
|
||||
|
||||
func (sm Client) CreateSecretWithContext(ctx aws.Context, input *awssm.CreateSecretInput, options ...request.Option) (*awssm.CreateSecretOutput, error) {
|
||||
return sm.CreateSecretWithContextFn(ctx, input, options...)
|
||||
|
@ -60,6 +62,7 @@ func NewCreateSecretWithContextFn(output *awssm.CreateSecretOutput, err error, e
|
|||
return output, err
|
||||
}
|
||||
}
|
||||
|
||||
func (sm Client) DeleteSecretWithContext(ctx aws.Context, input *awssm.DeleteSecretInput, opts ...request.Option) (*awssm.DeleteSecretOutput, error) {
|
||||
return sm.DeleteSecretWithContextFn(ctx, input, opts...)
|
||||
}
|
||||
|
@ -156,8 +159,8 @@ func (sm *Client) GetSecretValue(in *awssm.GetSecretValueInput) (*awssm.GetSecre
|
|||
return nil, fmt.Errorf("test case not found")
|
||||
}
|
||||
|
||||
func (sm *Client) ListSecrets(*awssm.ListSecretsInput) (*awssm.ListSecretsOutput, error) {
|
||||
return nil, nil
|
||||
func (sm *Client) ListSecrets(input *awssm.ListSecretsInput) (*awssm.ListSecretsOutput, error) {
|
||||
return sm.ListSecretsFn(nil, input)
|
||||
}
|
||||
|
||||
func (sm *Client) cacheKeyForInput(in *awssm.GetSecretValueInput) string {
|
||||
|
|
|
@ -18,16 +18,22 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||
"github.com/aws/aws-sdk-go/aws/request"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
awssm "github.com/aws/aws-sdk-go/service/secretsmanager"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/utils/ptr"
|
||||
|
||||
esv1beta1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
|
||||
fakesm "github.com/external-secrets/external-secrets/pkg/provider/aws/secretsmanager/fake"
|
||||
|
@ -1025,3 +1031,283 @@ func getTagSlice() []*awssm.Tag {
|
|||
},
|
||||
}
|
||||
}
|
||||
func TestSecretsManagerGetAllSecrets(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
errBoom := errors.New("boom")
|
||||
secretName := "my-secret"
|
||||
secretVersion := "AWSCURRENT"
|
||||
secretPath := "/path/to/secret"
|
||||
secretValue := "secret value"
|
||||
secretTags := map[string]string{
|
||||
"foo": "bar",
|
||||
}
|
||||
// Test cases
|
||||
testCases := []struct {
|
||||
name string
|
||||
ref esv1beta1.ExternalSecretFind
|
||||
|
||||
secretName string
|
||||
secretVersion string
|
||||
secretValue string
|
||||
fetchError error
|
||||
listSecretsFn func(ctx context.Context, input *awssm.ListSecretsInput, opts ...request.Option) (*awssm.ListSecretsOutput, error)
|
||||
|
||||
expectedData map[string][]byte
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
name: "Matching secrets found",
|
||||
ref: esv1beta1.ExternalSecretFind{
|
||||
Name: &esv1beta1.FindName{
|
||||
RegExp: secretName,
|
||||
},
|
||||
Path: ptr.To(secretPath),
|
||||
},
|
||||
secretName: secretName,
|
||||
secretVersion: secretVersion,
|
||||
secretValue: secretValue,
|
||||
listSecretsFn: func(ctx context.Context, input *awssm.ListSecretsInput, opts ...request.Option) (*awssm.ListSecretsOutput, error) {
|
||||
assert.Len(t, input.Filters, 1)
|
||||
assert.Equal(t, "name", *input.Filters[0].Key)
|
||||
assert.Equal(t, secretPath, *input.Filters[0].Values[0])
|
||||
return &awssm.ListSecretsOutput{
|
||||
SecretList: []*awssm.SecretListEntry{
|
||||
{
|
||||
Name: ptr.To(secretName),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
expectedData: map[string][]byte{
|
||||
secretName: []byte(secretValue),
|
||||
},
|
||||
expectedError: "",
|
||||
},
|
||||
{
|
||||
name: "Error occurred while fetching secret value",
|
||||
ref: esv1beta1.ExternalSecretFind{
|
||||
Name: &esv1beta1.FindName{
|
||||
RegExp: secretName,
|
||||
},
|
||||
Path: ptr.To(secretPath),
|
||||
},
|
||||
secretName: secretName,
|
||||
secretVersion: secretVersion,
|
||||
secretValue: secretValue,
|
||||
fetchError: errBoom,
|
||||
listSecretsFn: func(ctx context.Context, input *awssm.ListSecretsInput, opts ...request.Option) (*awssm.ListSecretsOutput, error) {
|
||||
return &awssm.ListSecretsOutput{
|
||||
SecretList: []*awssm.SecretListEntry{
|
||||
{
|
||||
Name: ptr.To(secretName),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
expectedData: nil,
|
||||
expectedError: errBoom.Error(),
|
||||
},
|
||||
{
|
||||
name: "regexp: error occurred while listing secrets",
|
||||
ref: esv1beta1.ExternalSecretFind{
|
||||
Name: &esv1beta1.FindName{
|
||||
RegExp: secretName,
|
||||
},
|
||||
},
|
||||
listSecretsFn: func(ctx context.Context, input *awssm.ListSecretsInput, opts ...request.Option) (*awssm.ListSecretsOutput, error) {
|
||||
return nil, errBoom
|
||||
},
|
||||
expectedData: nil,
|
||||
expectedError: errBoom.Error(),
|
||||
},
|
||||
{
|
||||
name: "regep: no matching secrets found",
|
||||
ref: esv1beta1.ExternalSecretFind{
|
||||
Name: &esv1beta1.FindName{
|
||||
RegExp: secretName,
|
||||
},
|
||||
},
|
||||
listSecretsFn: func(ctx context.Context, input *awssm.ListSecretsInput, opts ...request.Option) (*awssm.ListSecretsOutput, error) {
|
||||
return &awssm.ListSecretsOutput{
|
||||
SecretList: []*awssm.SecretListEntry{
|
||||
{
|
||||
Name: ptr.To("other-secret"),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
expectedData: make(map[string][]byte),
|
||||
expectedError: "",
|
||||
},
|
||||
{
|
||||
name: "invalid regexp",
|
||||
ref: esv1beta1.ExternalSecretFind{
|
||||
Name: &esv1beta1.FindName{
|
||||
RegExp: "[",
|
||||
},
|
||||
},
|
||||
expectedData: nil,
|
||||
expectedError: "could not compile find.name.regexp [[]: error parsing regexp: missing closing ]: `[`",
|
||||
},
|
||||
|
||||
{
|
||||
name: "tags: Matching secrets found",
|
||||
ref: esv1beta1.ExternalSecretFind{
|
||||
Tags: secretTags,
|
||||
},
|
||||
secretName: secretName,
|
||||
secretVersion: secretVersion,
|
||||
secretValue: secretValue,
|
||||
listSecretsFn: func(ctx context.Context, input *awssm.ListSecretsInput, opts ...request.Option) (*awssm.ListSecretsOutput, error) {
|
||||
assert.Len(t, input.Filters, 2)
|
||||
assert.Equal(t, "tag-key", *input.Filters[0].Key)
|
||||
assert.Equal(t, "foo", *input.Filters[0].Values[0])
|
||||
assert.Equal(t, "tag-value", *input.Filters[1].Key)
|
||||
assert.Equal(t, "bar", *input.Filters[1].Values[0])
|
||||
return &awssm.ListSecretsOutput{
|
||||
SecretList: []*awssm.SecretListEntry{
|
||||
{
|
||||
Name: ptr.To(secretName),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
expectedData: map[string][]byte{
|
||||
secretName: []byte(secretValue),
|
||||
},
|
||||
expectedError: "",
|
||||
},
|
||||
{
|
||||
name: "tags: error occurred while fetching secret value",
|
||||
ref: esv1beta1.ExternalSecretFind{
|
||||
Tags: secretTags,
|
||||
},
|
||||
secretName: secretName,
|
||||
secretVersion: secretVersion,
|
||||
secretValue: secretValue,
|
||||
fetchError: errBoom,
|
||||
listSecretsFn: func(ctx context.Context, input *awssm.ListSecretsInput, opts ...request.Option) (*awssm.ListSecretsOutput, error) {
|
||||
return &awssm.ListSecretsOutput{
|
||||
SecretList: []*awssm.SecretListEntry{
|
||||
{
|
||||
Name: ptr.To(secretName),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
},
|
||||
expectedData: nil,
|
||||
expectedError: errBoom.Error(),
|
||||
},
|
||||
{
|
||||
name: "tags: error occurred while listing secrets",
|
||||
ref: esv1beta1.ExternalSecretFind{
|
||||
Tags: secretTags,
|
||||
},
|
||||
listSecretsFn: func(ctx context.Context, input *awssm.ListSecretsInput, opts ...request.Option) (*awssm.ListSecretsOutput, error) {
|
||||
return nil, errBoom
|
||||
},
|
||||
expectedData: nil,
|
||||
expectedError: errBoom.Error(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
fc := fakesm.NewClient()
|
||||
fc.ListSecretsFn = tc.listSecretsFn
|
||||
fc.WithValue(&awssm.GetSecretValueInput{
|
||||
SecretId: ptr.To(tc.secretName),
|
||||
VersionStage: ptr.To(tc.secretVersion),
|
||||
}, &awssm.GetSecretValueOutput{
|
||||
Name: ptr.To(tc.secretName),
|
||||
VersionStages: []*string{ptr.To(tc.secretVersion)},
|
||||
SecretBinary: []byte(tc.secretValue),
|
||||
}, tc.fetchError)
|
||||
sm := SecretsManager{
|
||||
client: fc,
|
||||
cache: make(map[string]*awssm.GetSecretValueOutput),
|
||||
}
|
||||
data, err := sm.GetAllSecrets(ctx, tc.ref)
|
||||
if err != nil && err.Error() != tc.expectedError {
|
||||
t.Errorf("unexpected error: got %v, want %v", err, tc.expectedError)
|
||||
}
|
||||
if !reflect.DeepEqual(data, tc.expectedData) {
|
||||
t.Errorf("unexpected data: got %v, want %v", data, tc.expectedData)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecretsManagerValidate(t *testing.T) {
|
||||
type fields struct {
|
||||
sess *session.Session
|
||||
referentAuth bool
|
||||
}
|
||||
validSession, _ := session.NewSession(aws.NewConfig().WithCredentials(credentials.NewStaticCredentials("fake", "fake", "fake")))
|
||||
invalidSession, _ := session.NewSession(aws.NewConfig().WithCredentials(credentials.NewCredentials(&FakeCredProvider{
|
||||
retrieveFunc: func() (credentials.Value, error) {
|
||||
return credentials.Value{}, errors.New("invalid credentials")
|
||||
},
|
||||
})))
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want esv1beta1.ValidationResult
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "ReferentAuth should always return unknown",
|
||||
fields: fields{
|
||||
referentAuth: true,
|
||||
},
|
||||
want: esv1beta1.ValidationResultUnknown,
|
||||
},
|
||||
{
|
||||
name: "Valid credentials should return ready",
|
||||
fields: fields{
|
||||
sess: validSession,
|
||||
},
|
||||
want: esv1beta1.ValidationResultReady,
|
||||
},
|
||||
{
|
||||
name: "Invalid credentials should return error",
|
||||
fields: fields{
|
||||
sess: invalidSession,
|
||||
},
|
||||
want: esv1beta1.ValidationResultError,
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
sm := &SecretsManager{
|
||||
sess: tt.fields.sess,
|
||||
referentAuth: tt.fields.referentAuth,
|
||||
}
|
||||
got, err := sm.Validate()
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("SecretsManager.Validate() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("SecretsManager.Validate() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// FakeCredProvider implements the AWS credentials.Provider interface
|
||||
// It is used to inject an error into the AWS session to cause a
|
||||
// validation error.
|
||||
type FakeCredProvider struct {
|
||||
retrieveFunc func() (credentials.Value, error)
|
||||
}
|
||||
|
||||
func (f *FakeCredProvider) Retrieve() (credentials.Value, error) {
|
||||
return f.retrieveFunc()
|
||||
}
|
||||
|
||||
func (f *FakeCredProvider) IsExpired() bool {
|
||||
return true
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue