Files
threshold-plugin-aws/plugin/plugin_test.go
T

386 lines
11 KiB
Go
Raw Normal View History

2021-09-22 17:00:37 -07:00
package plugin
import (
"context"
2021-10-06 12:47:05 -07:00
"errors"
2021-09-24 12:47:57 -07:00
"fmt"
2021-09-22 17:00:37 -07:00
"testing"
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/hostcatalogs"
pb "github.com/hashicorp/boundary/sdk/pbs/plugin"
2021-09-23 17:24:54 -07:00
"github.com/hashicorp/go-secure-stdlib/awsutil"
2021-09-22 17:00:37 -07:00
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/structpb"
)
2021-09-27 16:47:51 -07:00
func TestOnCreateCatalogErr(t *testing.T) {
cases := []struct {
2021-10-06 12:47:05 -07:00
name string
req *pb.OnCreateCatalogRequest
opts []awsCatalogPersistedStateOption
expectedErr string
2021-09-27 16:47:51 -07:00
}{
{
2021-10-06 12:47:05 -07:00
name: "nil catalog",
req: &pb.OnCreateCatalogRequest{},
expectedErr: "catalog is nil",
2021-09-27 16:47:51 -07:00
},
{
name: "nil secrets",
req: &pb.OnCreateCatalogRequest{
Catalog: &hostcatalogs.HostCatalog{},
},
2021-10-06 12:47:05 -07:00
expectedErr: "secrets are required",
2021-09-27 16:47:51 -07:00
},
{
name: "nil attributes",
req: &pb.OnCreateCatalogRequest{
Catalog: &hostcatalogs.HostCatalog{
Secrets: new(structpb.Struct),
},
},
2021-10-06 12:47:05 -07:00
expectedErr: "attributes are required",
2021-09-27 16:47:51 -07:00
},
{
name: "invalid region",
req: &pb.OnCreateCatalogRequest{
Catalog: &hostcatalogs.HostCatalog{
Secrets: new(structpb.Struct),
Attributes: mustStruct(map[string]interface{}{
2021-10-06 12:47:05 -07:00
constRegion: "foobar",
2021-09-27 16:47:51 -07:00
}),
},
},
2021-10-06 12:47:05 -07:00
expectedErr: "not a valid region: foobar",
2021-09-27 16:47:51 -07:00
},
{
name: "missing access key ID",
req: &pb.OnCreateCatalogRequest{
Catalog: &hostcatalogs.HostCatalog{
Secrets: new(structpb.Struct),
Attributes: mustStruct(map[string]interface{}{
2021-10-06 12:47:05 -07:00
constRegion: "us-west-2",
2021-09-27 16:47:51 -07:00
}),
},
},
2021-10-06 12:47:05 -07:00
expectedErr: "missing required value \"access_key_id\"",
2021-09-27 16:47:51 -07:00
},
{
name: "missing secret access key",
req: &pb.OnCreateCatalogRequest{
Catalog: &hostcatalogs.HostCatalog{
Secrets: mustStruct(map[string]interface{}{
2021-10-06 12:47:05 -07:00
constAccessKeyId: "foobar",
2021-09-27 16:47:51 -07:00
}),
Attributes: mustStruct(map[string]interface{}{
2021-10-06 12:47:05 -07:00
constRegion: "us-west-2",
2021-09-27 16:47:51 -07:00
}),
},
},
2021-10-06 12:47:05 -07:00
expectedErr: "missing required value \"secret_access_key\"",
2021-09-27 16:47:51 -07:00
},
{
2021-10-06 12:47:05 -07:00
name: "invalid value for skipping rotation",
2021-09-27 16:47:51 -07:00
req: &pb.OnCreateCatalogRequest{
Catalog: &hostcatalogs.HostCatalog{
Secrets: mustStruct(map[string]interface{}{
2021-10-06 12:47:05 -07:00
constAccessKeyId: "foobar",
constSecretAccessKey: "bazqux",
2021-09-27 16:47:51 -07:00
}),
Attributes: mustStruct(map[string]interface{}{
2021-10-06 12:47:05 -07:00
constRegion: "us-west-2",
constDisableCredentialRotation: "sure",
2021-09-27 16:47:51 -07:00
}),
},
},
2021-10-06 12:47:05 -07:00
expectedErr: "unexpected type for value \"disable_credential_rotation\": want bool, got string",
2021-09-27 16:47:51 -07:00
},
{
2021-10-06 12:47:05 -07:00
name: "persisted state setup error",
2021-09-27 16:47:51 -07:00
req: &pb.OnCreateCatalogRequest{
Catalog: &hostcatalogs.HostCatalog{
Secrets: mustStruct(map[string]interface{}{
2021-10-06 12:47:05 -07:00
constAccessKeyId: "foobar",
constSecretAccessKey: "bazqux",
2021-09-27 16:47:51 -07:00
}),
Attributes: mustStruct(map[string]interface{}{
2021-10-06 12:47:05 -07:00
constRegion: "us-west-2",
2021-09-27 16:47:51 -07:00
}),
},
},
2021-10-06 12:47:05 -07:00
opts: []awsCatalogPersistedStateOption{
func(s *awsCatalogPersistedState) error {
return errors.New(testOptionErr)
},
},
expectedErr: fmt.Sprintf("error setting up persisted state: %s", testOptionErr),
},
{
name: "rotation error",
req: &pb.OnCreateCatalogRequest{
Catalog: &hostcatalogs.HostCatalog{
Secrets: mustStruct(map[string]interface{}{
constAccessKeyId: "foobar",
constSecretAccessKey: "bazqux",
}),
Attributes: mustStruct(map[string]interface{}{
constRegion: "us-west-2",
}),
},
},
opts: []awsCatalogPersistedStateOption{
withStateTestOpts([]awsutil.Option{
awsutil.WithIAMAPIFunc(
awsutil.NewMockIAM(
awsutil.WithGetUserError(errors.New(testGetUserErr)),
),
),
}),
},
expectedErr: fmt.Sprintf("error during credential rotation: error rotating credentials: error calling CreateAccessKey: error calling aws.GetUser: %s", testGetUserErr),
},
{
name: "validation error",
req: &pb.OnCreateCatalogRequest{
Catalog: &hostcatalogs.HostCatalog{
Secrets: mustStruct(map[string]interface{}{
constAccessKeyId: "foobar",
constSecretAccessKey: "bazqux",
}),
Attributes: mustStruct(map[string]interface{}{
constRegion: "us-west-2",
constDisableCredentialRotation: true,
}),
},
},
opts: []awsCatalogPersistedStateOption{
withStateTestOpts([]awsutil.Option{
awsutil.WithSTSAPIFunc(
awsutil.NewMockSTS(
awsutil.WithGetCallerIdentityError(errors.New(testGetCallerIdentityErr)),
),
),
}),
},
expectedErr: fmt.Sprintf("error during credential validation: error validating credentials: %s", testGetCallerIdentityErr),
2021-09-27 16:47:51 -07:00
},
}
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
require := require.New(t)
2021-10-06 12:47:05 -07:00
p := &AwsPlugin{
testStateOpts: tc.opts,
}
2021-09-27 16:47:51 -07:00
_, err := p.OnCreateCatalog(context.Background(), tc.req)
2021-10-06 12:47:05 -07:00
require.EqualError(err, tc.expectedErr)
2021-09-27 16:47:51 -07:00
})
}
}
2021-10-06 12:47:05 -07:00
func TestOnUpdateCatalogErr(t *testing.T) {
cases := []struct {
name string
req *pb.OnUpdateCatalogRequest
opts []awsCatalogPersistedStateOption
expectedErr string
}{
{
name: "nil new catalog",
req: &pb.OnUpdateCatalogRequest{},
expectedErr: "new catalog is nil",
},
{
name: "nil new attributes",
req: &pb.OnUpdateCatalogRequest{
NewCatalog: &hostcatalogs.HostCatalog{
Secrets: new(structpb.Struct),
},
},
expectedErr: "new catalog missing attributes",
},
{
name: "invalid region",
req: &pb.OnUpdateCatalogRequest{
NewCatalog: &hostcatalogs.HostCatalog{
Attributes: mustStruct(map[string]interface{}{
constRegion: "foobar",
}),
},
},
expectedErr: "not a valid region: foobar",
},
{
name: "persisted state setup error",
req: &pb.OnUpdateCatalogRequest{
NewCatalog: &hostcatalogs.HostCatalog{
Attributes: mustStruct(map[string]interface{}{
constRegion: "us-west-2",
}),
},
Persisted: &pb.HostCatalogPersisted{
Secrets: mustStruct(map[string]interface{}{
constAccessKeyId: "foobar",
constSecretAccessKey: "bazqux",
constCredsLastRotatedTime: "2006-01-02T15:04:05+07:00",
}),
},
},
opts: []awsCatalogPersistedStateOption{
func(s *awsCatalogPersistedState) error {
return errors.New(testOptionErr)
},
},
expectedErr: fmt.Sprintf("error loading persisted state: %s", testOptionErr),
},
{
name: "invalid value for credential rotation",
req: &pb.OnUpdateCatalogRequest{
NewCatalog: &hostcatalogs.HostCatalog{
Attributes: mustStruct(map[string]interface{}{
constRegion: "us-west-2",
constDisableCredentialRotation: "sure",
}),
},
Persisted: &pb.HostCatalogPersisted{
Secrets: mustStruct(map[string]interface{}{
constAccessKeyId: "foobar",
constSecretAccessKey: "bazqux",
constCredsLastRotatedTime: "2006-01-02T15:04:05+07:00",
}),
},
},
expectedErr: "unexpected type for value \"disable_credential_rotation\": want bool, got string",
},
{
name: "cannot disable rotation for already rotated credentials",
req: &pb.OnUpdateCatalogRequest{
NewCatalog: &hostcatalogs.HostCatalog{
Attributes: mustStruct(map[string]interface{}{
constRegion: "us-west-2",
constDisableCredentialRotation: true,
}),
},
Persisted: &pb.HostCatalogPersisted{
Secrets: mustStruct(map[string]interface{}{
constAccessKeyId: "foobar",
constSecretAccessKey: "bazqux",
constCredsLastRotatedTime: "2006-01-02T15:04:05+07:00",
}),
},
},
expectedErr: "cannot disable rotation for already-rotated credentials",
},
{
name: "updating secrets, missing access key id",
req: &pb.OnUpdateCatalogRequest{
NewCatalog: &hostcatalogs.HostCatalog{
Secrets: new(structpb.Struct),
Attributes: mustStruct(map[string]interface{}{
constRegion: "us-west-2",
}),
},
Persisted: &pb.HostCatalogPersisted{
Secrets: mustStruct(map[string]interface{}{
constAccessKeyId: "foobar",
constSecretAccessKey: "bazqux",
constCredsLastRotatedTime: "2006-01-02T15:04:05+07:00",
}),
},
},
expectedErr: "missing required value \"access_key_id\"",
},
{
name: "updating secrets, missing secret access key",
req: &pb.OnUpdateCatalogRequest{
NewCatalog: &hostcatalogs.HostCatalog{
Secrets: mustStruct(map[string]interface{}{
constAccessKeyId: "foobar",
}),
Attributes: mustStruct(map[string]interface{}{
constRegion: "us-west-2",
}),
},
Persisted: &pb.HostCatalogPersisted{
Secrets: mustStruct(map[string]interface{}{
constAccessKeyId: "foobar",
constSecretAccessKey: "bazqux",
constCredsLastRotatedTime: "2006-01-02T15:04:05+07:00",
}),
},
},
expectedErr: "missing required value \"secret_access_key\"",
},
{
name: "updating secrets, replace error",
req: &pb.OnUpdateCatalogRequest{
NewCatalog: &hostcatalogs.HostCatalog{
Secrets: mustStruct(map[string]interface{}{
constAccessKeyId: "onetwo",
constSecretAccessKey: "threefour",
}),
Attributes: mustStruct(map[string]interface{}{
constRegion: "us-west-2",
constDisableCredentialRotation: true,
}),
},
Persisted: &pb.HostCatalogPersisted{
Secrets: mustStruct(map[string]interface{}{
constAccessKeyId: "foobar",
constSecretAccessKey: "bazqux",
constCredsLastRotatedTime: "2006-01-02T15:04:05+07:00",
}),
},
},
opts: []awsCatalogPersistedStateOption{
withStateTestOpts([]awsutil.Option{
awsutil.WithIAMAPIFunc(
awsutil.NewMockIAM(
awsutil.WithDeleteAccessKeyError(errors.New(testDeleteAccessKeyErr)),
),
),
}),
},
expectedErr: fmt.Sprintf("error attempting to replace credentials: error deleting old access key: %s", testDeleteAccessKeyErr),
},
{
name: "rotation error",
req: &pb.OnUpdateCatalogRequest{
NewCatalog: &hostcatalogs.HostCatalog{
Attributes: mustStruct(map[string]interface{}{
constRegion: "us-west-2",
}),
},
Persisted: &pb.HostCatalogPersisted{
Secrets: mustStruct(map[string]interface{}{
constAccessKeyId: "foobar",
constSecretAccessKey: "bazqux",
}),
},
},
opts: []awsCatalogPersistedStateOption{
withStateTestOpts([]awsutil.Option{
awsutil.WithIAMAPIFunc(
awsutil.NewMockIAM(
awsutil.WithGetUserError(errors.New(testGetUserErr)),
),
),
}),
},
expectedErr: fmt.Sprintf("error during credential rotation: error rotating credentials: error calling CreateAccessKey: error calling aws.GetUser: %s", testGetUserErr),
},
2021-09-27 16:47:51 -07:00
}
2021-10-06 12:47:05 -07:00
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
require := require.New(t)
p := &AwsPlugin{
testStateOpts: tc.opts,
}
_, err := p.OnUpdateCatalog(context.Background(), tc.req)
require.EqualError(err, tc.expectedErr)
})
}
2021-09-27 16:47:51 -07:00
}