diff --git a/spinifex/gateway/ec2.go b/spinifex/gateway/ec2.go index 3b7ce0c84..4c02cd6f9 100644 --- a/spinifex/gateway/ec2.go +++ b/spinifex/gateway/ec2.go @@ -13,7 +13,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/mulgadc/spinifex/spinifex/awsec2query" + "github.com/mulgadc/spinifex/spinifex/ingress/aws/query" "github.com/mulgadc/spinifex/spinifex/awserrors" gateway_ec2 "github.com/mulgadc/spinifex/spinifex/gateway/ec2" gateway_ec2_account "github.com/mulgadc/spinifex/spinifex/gateway/ec2/account" @@ -76,7 +76,7 @@ func requestContext(r *http.Request) context.Context { // ec2Action constructor so they all consume the same parse. func parseEC2Input[In any](q map[string]string) (any, error) { input := new(In) - if err := awsec2query.QueryParamsToStruct(q, input); err != nil { + if err := query.QueryParamsToStruct(q, input); err != nil { return nil, err } return input, nil @@ -655,7 +655,7 @@ func (gw *GatewayConfig) EC2_Request(w http.ResponseWriter, r *http.Request) err input, err := handler.parse(queryArgs) if err != nil { - if errors.Is(err, awsec2query.ErrSliceTooLarge) { + if errors.Is(err, query.ErrSliceTooLarge) { return errors.New(awserrors.ErrorMalformedQueryString) } return err diff --git a/spinifex/gateway/ec2/authz.go b/spinifex/gateway/ec2/authz.go index ea02b1366..ee649919e 100644 --- a/spinifex/gateway/ec2/authz.go +++ b/spinifex/gateway/ec2/authz.go @@ -9,7 +9,7 @@ import ( "slices" "github.com/mulgadc/spinifex/spinifex/foundation/aws/arn" - "github.com/mulgadc/spinifex/spinifex/awsec2query" + "github.com/mulgadc/spinifex/spinifex/ingress/aws/query" "github.com/mulgadc/spinifex/spinifex/awserrors" ) @@ -333,7 +333,7 @@ func ResourceARNs(action, region, accountID string, input any) ([]string, error) } seen[resource] = struct{}{} resources = append(resources, resource) - if len(resources) > awsec2query.MaxSliceLen { + if len(resources) > query.MaxSliceLen { return nil, errors.New(awserrors.ErrorMalformedQueryString) } } @@ -360,7 +360,7 @@ func (s *resourceScope) resolve(region, accountID string, input any) ([]string, } return []string{anyResource}, nil } - if len(ids) > awsec2query.MaxSliceLen { + if len(ids) > query.MaxSliceLen { return nil, errors.New(awserrors.ErrorMalformedQueryString) } @@ -384,7 +384,7 @@ func (s *resourceScope) resolve(region, accountID string, input any) ([]string, // precedence. Values are deduplicated before policy evaluation. func (s *resourceScope) identifiers(input any) []string { for _, path := range s.paths { - values := awsec2query.StringValuesAt(input, path) + values := query.StringValuesAt(input, path) seen := make(map[string]struct{}, len(values)) ids := make([]string, 0, len(values)) for _, value := range values { diff --git a/spinifex/gateway/ec2/authz_test.go b/spinifex/gateway/ec2/authz_test.go index bbadb0c79..5d3367b38 100644 --- a/spinifex/gateway/ec2/authz_test.go +++ b/spinifex/gateway/ec2/authz_test.go @@ -9,7 +9,7 @@ import ( "testing" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/mulgadc/spinifex/spinifex/awsec2query" + "github.com/mulgadc/spinifex/spinifex/ingress/aws/query" "github.com/mulgadc/spinifex/spinifex/awserrors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -29,7 +29,7 @@ func resolve(t *testing.T, action string, q map[string]string) []string { var input any if prototype, ok := ec2Inputs[action]; ok { input = reflect.New(reflect.TypeOf(prototype).Elem()).Interface() - require.NoError(t, awsec2query.QueryParamsToStruct(q, input)) + require.NoError(t, query.QueryParamsToStruct(q, input)) } got, err := ResourceARNs(action, testRegion, testAccountID, input) require.NoError(t, err) diff --git a/spinifex/gateway/ec2_authz_test.go b/spinifex/gateway/ec2_authz_test.go index 904329b74..094689aae 100644 --- a/spinifex/gateway/ec2_authz_test.go +++ b/spinifex/gateway/ec2_authz_test.go @@ -9,7 +9,7 @@ import ( "strings" "testing" - "github.com/mulgadc/spinifex/spinifex/awsec2query" + "github.com/mulgadc/spinifex/spinifex/ingress/aws/query" "github.com/mulgadc/spinifex/spinifex/awserrors" handlers_iam "github.com/mulgadc/spinifex/spinifex/handlers/iam" "github.com/stretchr/testify/assert" @@ -224,7 +224,7 @@ func TestEC2Request_ModifySecurityGroupRulesIsGroupScoped(t *testing.T) { func TestEC2Request_RejectsOversizedResourceList(t *testing.T) { var body strings.Builder body.WriteString("Action=TerminateInstances") - for i := 1; i <= awsec2query.MaxSliceLen+1; i++ { + for i := 1; i <= query.MaxSliceLen+1; i++ { body.WriteString("&InstanceId.") body.WriteString(strconv.Itoa(i)) body.WriteString("=i-") diff --git a/spinifex/gateway/ecrapi/authz.go b/spinifex/gateway/ecrapi/authz.go index a7848d5a2..2e4860469 100644 --- a/spinifex/gateway/ecrapi/authz.go +++ b/spinifex/gateway/ecrapi/authz.go @@ -8,7 +8,7 @@ import ( "slices" "strings" - "github.com/mulgadc/spinifex/spinifex/awsec2query" + "github.com/mulgadc/spinifex/spinifex/ingress/aws/query" "github.com/mulgadc/spinifex/spinifex/awserrors" "github.com/mulgadc/spinifex/spinifex/gateway/bodyscope" ) @@ -143,7 +143,7 @@ func ResourceARNs(action, region, accountID string, body []byte) ([]string, erro if _, duplicate := seen[resource]; duplicate { continue } - if len(resources) >= awsec2query.MaxSliceLen { + if len(resources) >= query.MaxSliceLen { return nil, errors.New(awserrors.ErrorMalformedQueryString) } seen[resource] = struct{}{} @@ -172,7 +172,7 @@ func resolve(source resourceSource, action, region, accountID string, scope body } // Capped so a body-supplied list cannot make the gate do unbounded work // ahead of the authorization decision. - if len(names) > awsec2query.MaxSliceLen { + if len(names) > query.MaxSliceLen { return nil, errors.New(awserrors.ErrorMalformedQueryString) } out := make([]string, 0, len(names)) diff --git a/spinifex/gateway/ecrapi/authz_test.go b/spinifex/gateway/ecrapi/authz_test.go index d6e9b3a70..6a5fddd0d 100644 --- a/spinifex/gateway/ecrapi/authz_test.go +++ b/spinifex/gateway/ecrapi/authz_test.go @@ -5,7 +5,7 @@ import ( "strconv" "testing" - "github.com/mulgadc/spinifex/spinifex/awsec2query" + "github.com/mulgadc/spinifex/spinifex/ingress/aws/query" "github.com/mulgadc/spinifex/spinifex/awserrors" gateway_ecrapi "github.com/mulgadc/spinifex/spinifex/gateway/ecrapi" "github.com/stretchr/testify/assert" @@ -113,13 +113,13 @@ func TestResourceARNs_OversizedListIsRejected(t *testing.T) { } _, err := gateway_ecrapi.ResourceARNs("DescribeRepositories", testRegion, testAccountID, - namesBody(awsec2query.MaxSliceLen+1)) + namesBody(query.MaxSliceLen+1)) require.EqualError(t, err, awserrors.ErrorMalformedQueryString) resources, err := gateway_ecrapi.ResourceARNs("DescribeRepositories", testRegion, testAccountID, - namesBody(awsec2query.MaxSliceLen)) + namesBody(query.MaxSliceLen)) require.NoError(t, err) - assert.Len(t, resources, awsec2query.MaxSliceLen) + assert.Len(t, resources, query.MaxSliceLen) } // encoding/json resolves two spellings of one field in document order when the diff --git a/spinifex/gateway/ecs/authz.go b/spinifex/gateway/ecs/authz.go index fdfc60886..069944458 100644 --- a/spinifex/gateway/ecs/authz.go +++ b/spinifex/gateway/ecs/authz.go @@ -6,7 +6,7 @@ import ( "maps" "slices" - "github.com/mulgadc/spinifex/spinifex/awsec2query" + "github.com/mulgadc/spinifex/spinifex/ingress/aws/query" "github.com/mulgadc/spinifex/spinifex/awserrors" "github.com/mulgadc/spinifex/spinifex/gateway/bodyscope" handlers_ecs "github.com/mulgadc/spinifex/spinifex/handlers/ecs" @@ -164,7 +164,7 @@ func ResourceARNs(action, region, accountID string, body []byte) ([]string, erro if _, duplicate := seen[resource]; duplicate { continue } - if len(resources) >= awsec2query.MaxSliceLen { + if len(resources) >= query.MaxSliceLen { return nil, errors.New(awserrors.ErrorMalformedQueryString) } seen[resource] = struct{}{} @@ -266,7 +266,7 @@ func one(resource string) []string { // each builds one ARN per reference, capped so a body-supplied list cannot make // the gate do unbounded work ahead of the authorization decision. func each(refs []string, build func(string) string) ([]string, error) { - if len(refs) > awsec2query.MaxSliceLen { + if len(refs) > query.MaxSliceLen { return nil, errors.New(awserrors.ErrorMalformedQueryString) } out := make([]string, 0, len(refs)) diff --git a/spinifex/gateway/ecs/authz_test.go b/spinifex/gateway/ecs/authz_test.go index 3a30a24e3..92add055b 100644 --- a/spinifex/gateway/ecs/authz_test.go +++ b/spinifex/gateway/ecs/authz_test.go @@ -5,7 +5,7 @@ import ( "strconv" "testing" - "github.com/mulgadc/spinifex/spinifex/awsec2query" + "github.com/mulgadc/spinifex/spinifex/ingress/aws/query" "github.com/mulgadc/spinifex/spinifex/awserrors" gateway_ecs "github.com/mulgadc/spinifex/spinifex/gateway/ecs" "github.com/stretchr/testify/assert" @@ -172,13 +172,13 @@ func TestResourceARNs_OversizedListIsRejected(t *testing.T) { } _, err := gateway_ecs.ResourceARNs("DescribeClusters", testRegion, testAccountID, - clustersBody(awsec2query.MaxSliceLen+1)) + clustersBody(query.MaxSliceLen+1)) require.EqualError(t, err, awserrors.ErrorMalformedQueryString) resources, err := gateway_ecs.ResourceARNs("DescribeClusters", testRegion, testAccountID, - clustersBody(awsec2query.MaxSliceLen)) + clustersBody(query.MaxSliceLen)) require.NoError(t, err) - assert.Len(t, resources, awsec2query.MaxSliceLen) + assert.Len(t, resources, query.MaxSliceLen) } // encoding/json resolves two spellings of one field in document order when the diff --git a/spinifex/gateway/elbv2.go b/spinifex/gateway/elbv2.go index cd3e15410..7b82ee01e 100644 --- a/spinifex/gateway/elbv2.go +++ b/spinifex/gateway/elbv2.go @@ -7,7 +7,7 @@ import ( "net/http" "github.com/aws/aws-sdk-go/service/elbv2" - "github.com/mulgadc/spinifex/spinifex/awsec2query" + "github.com/mulgadc/spinifex/spinifex/ingress/aws/query" "github.com/mulgadc/spinifex/spinifex/awserrors" gateway_elbv2 "github.com/mulgadc/spinifex/spinifex/gateway/elbv2" handlers_elbv2 "github.com/mulgadc/spinifex/spinifex/handlers/elbv2" @@ -27,7 +27,7 @@ func elbv2Handler[In any](handler func(context.Context, *In, *GatewayConfig, str return elbv2Action{ parse: func(q map[string]string) (any, error) { input := new(In) - if err := awsec2query.QueryParamsToStruct(q, input); err != nil { + if err := query.QueryParamsToStruct(q, input); err != nil { return nil, err } return input, nil @@ -222,7 +222,7 @@ func (gw *GatewayConfig) ELBv2_Request(w http.ResponseWriter, r *http.Request) e input, err := handler.parse(queryArgs) if err != nil { - if errors.Is(err, awsec2query.ErrSliceTooLarge) { + if errors.Is(err, query.ErrSliceTooLarge) { return errors.New(awserrors.ErrorMalformedQueryString) } return err diff --git a/spinifex/gateway/elbv2/authz.go b/spinifex/gateway/elbv2/authz.go index f883a44a2..055e149af 100644 --- a/spinifex/gateway/elbv2/authz.go +++ b/spinifex/gateway/elbv2/authz.go @@ -8,7 +8,7 @@ import ( "strings" "github.com/mulgadc/spinifex/spinifex/foundation/aws/arn" - "github.com/mulgadc/spinifex/spinifex/awsec2query" + "github.com/mulgadc/spinifex/spinifex/ingress/aws/query" "github.com/mulgadc/spinifex/spinifex/awserrors" ) @@ -147,7 +147,7 @@ func ResourceARNs(action, region, accountID string, input any) ([]string, error) if _, duplicate := seen[resource]; duplicate { continue } - if len(resources) >= awsec2query.MaxSliceLen { + if len(resources) >= query.MaxSliceLen { return nil, errors.New(awserrors.ErrorMalformedQueryString) } seen[resource] = struct{}{} @@ -223,13 +223,13 @@ func resolve(source resourceSource, action, region, accountID string, input any) func suppliedARNs(region, accountID string, input any, paths ...string) ([]string, error) { var resources []string for _, path := range paths { - for _, value := range awsec2query.StringValuesAt(input, path) { + for _, value := range query.StringValuesAt(input, path) { if value == "" { continue } // A nested list can fan out past what any single list may hold, so the // bound is asserted here rather than inherited from the parser. - if len(resources) >= awsec2query.MaxSliceLen { + if len(resources) >= query.MaxSliceLen { return nil, errors.New(awserrors.ErrorMalformedQueryString) } if err := checkARN(value, region, accountID); err != nil { @@ -287,7 +287,7 @@ func arnError(value, why string) error { } func firstValue(input any, path string) string { - for _, value := range awsec2query.StringValuesAt(input, path) { + for _, value := range query.StringValuesAt(input, path) { if value != "" { return value } diff --git a/spinifex/gateway/iam.go b/spinifex/gateway/iam.go index 6a708a110..e038332ec 100644 --- a/spinifex/gateway/iam.go +++ b/spinifex/gateway/iam.go @@ -7,7 +7,7 @@ import ( "net/http" "github.com/aws/aws-sdk-go/service/iam" - "github.com/mulgadc/spinifex/spinifex/awsec2query" + "github.com/mulgadc/spinifex/spinifex/ingress/aws/query" "github.com/mulgadc/spinifex/spinifex/awserrors" gateway_ec2_instance "github.com/mulgadc/spinifex/spinifex/gateway/ec2/instance" gateway_iam "github.com/mulgadc/spinifex/spinifex/gateway/iam" @@ -26,8 +26,8 @@ func iamHandler[In any](handler func(string, *In, *GatewayConfig) (any, error)) return iamAction{ parse: func(q map[string]string) (any, error) { input := new(In) - if err := awsec2query.QueryParamsToStruct(q, input); err != nil { - if errors.Is(err, awsec2query.ErrSliceTooLarge) { + if err := query.QueryParamsToStruct(q, input); err != nil { + if errors.Is(err, query.ErrSliceTooLarge) { return nil, errors.New(awserrors.ErrorMalformedQueryString) } return nil, awserrors.Errorf(awserrors.ErrorIAMInvalidInput, "The request parameters are invalid: %v", err) diff --git a/spinifex/gateway/rds/handler.go b/spinifex/gateway/rds/handler.go index 6974ce15e..2b51bbf3e 100644 --- a/spinifex/gateway/rds/handler.go +++ b/spinifex/gateway/rds/handler.go @@ -9,7 +9,7 @@ import ( "log/slog" "sort" - "github.com/mulgadc/spinifex/spinifex/awsec2query" + "github.com/mulgadc/spinifex/spinifex/ingress/aws/query" "github.com/mulgadc/spinifex/spinifex/awserrors" "github.com/mulgadc/spinifex/spinifex/utils" "github.com/nats-io/nats.go" @@ -50,10 +50,10 @@ type Handler func(ctx context.Context, action string, q map[string]string, nc *n func typedEnv[In any](handler func(context.Context, *In, *nats.Conn, Caller, Env) (any, error)) Handler { return func(ctx context.Context, action string, q map[string]string, nc *nats.Conn, caller Caller, env Env) ([]byte, error) { input := new(In) - if err := awsec2query.QueryParamsToStruct(q, input); err != nil { + if err := query.QueryParamsToStruct(q, input); err != nil { // An over-long indexed list is a client-side malformation, not an // internal failure, so it keeps its own error code. - if errors.Is(err, awsec2query.ErrSliceTooLarge) { + if errors.Is(err, query.ErrSliceTooLarge) { return nil, errors.New(awserrors.ErrorMalformedQueryString) } return nil, errors.New(awserrors.ErrorInvalidParameterValue) diff --git a/spinifex/gateway/sts.go b/spinifex/gateway/sts.go index a9111304f..7d1980480 100644 --- a/spinifex/gateway/sts.go +++ b/spinifex/gateway/sts.go @@ -8,7 +8,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/sts" spxarn "github.com/mulgadc/spinifex/spinifex/foundation/aws/arn" - "github.com/mulgadc/spinifex/spinifex/awsec2query" + "github.com/mulgadc/spinifex/spinifex/ingress/aws/query" "github.com/mulgadc/spinifex/spinifex/awserrors" gateway_sts "github.com/mulgadc/spinifex/spinifex/gateway/sts" handlers_sts "github.com/mulgadc/spinifex/spinifex/handlers/sts" @@ -36,8 +36,8 @@ type STSHandler func(action string, q map[string]string, gw *GatewayConfig, c st func stsHandler[In any](handler func(c stsCaller, input *In, gw *GatewayConfig) (any, error)) STSHandler { return func(action string, q map[string]string, gw *GatewayConfig, c stsCaller) ([]byte, error) { input := new(In) - if err := awsec2query.QueryParamsToStruct(q, input); err != nil { - if errors.Is(err, awsec2query.ErrSliceTooLarge) { + if err := query.QueryParamsToStruct(q, input); err != nil { + if errors.Is(err, query.ErrSliceTooLarge) { return nil, errors.New(awserrors.ErrorMalformedQueryString) } return nil, errors.New(awserrors.ErrorValidationError) diff --git a/spinifex/awsec2query/parser.go b/spinifex/ingress/aws/query/parser.go similarity index 98% rename from spinifex/awsec2query/parser.go rename to spinifex/ingress/aws/query/parser.go index 25dfd852c..cb46925f1 100644 --- a/spinifex/awsec2query/parser.go +++ b/spinifex/ingress/aws/query/parser.go @@ -1,4 +1,6 @@ -package awsec2query +// Package query decodes AWS Query protocol parameters into SDK request shapes. +// It is protocol plumbing and owns no service action or resource semantics. +package query import ( "encoding/base64" diff --git a/spinifex/awsec2query/parser_test.go b/spinifex/ingress/aws/query/parser_test.go similarity index 99% rename from spinifex/awsec2query/parser_test.go rename to spinifex/ingress/aws/query/parser_test.go index a4f4d74bc..026ac58b4 100644 --- a/spinifex/awsec2query/parser_test.go +++ b/spinifex/ingress/aws/query/parser_test.go @@ -1,4 +1,4 @@ -package awsec2query +package query import ( "fmt"