mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 17:11:30 +00:00
refactor: move AWS Query parser to ingress
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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-")
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
@@ -1,4 +1,4 @@
|
||||
package awsec2query
|
||||
package query
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
Reference in New Issue
Block a user