From 39759e1ed22bd8bea5c50f2728bc21746d01786a Mon Sep 17 00:00:00 2001 From: Julian Sommer <115516918+juliansommer@users.noreply.github.com> Date: Tue, 29 Sep 2026 09:35:11 +1000 Subject: [PATCH] fix: report SupportedNetworkTypes and SubnetOutpost on RDS subnet groups (#1132) --- spinifex/handlers/rds/subnetgroup.go | 4 +++ spinifex/handlers/rds/subnetgroup_test.go | 32 +++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/spinifex/handlers/rds/subnetgroup.go b/spinifex/handlers/rds/subnetgroup.go index a4e059cbc..f05d6df63 100644 --- a/spinifex/handlers/rds/subnetgroup.go +++ b/spinifex/handlers/rds/subnetgroup.go @@ -285,11 +285,15 @@ func (s *Service) projectSubnetGroup(rec *DBSubnetGroupRecord) *rds.DBSubnetGrou DBSubnetGroupArn: aws.String(FormatARN(ResourceKindDBSubnetGroup, s.region, rec.AccountID, rec.Name)), SubnetGroupStatus: aws.String(subnetGroupStatusComplete), VpcId: aws.String(rec.VpcID), + SupportedNetworkTypes: aws.StringSlice([]string{networkTypeIPv4}), } for _, subnet := range rec.Subnets { + // Empty rather than nil: AWS reports SubnetOutpost as {} on every subnet, + // and the XML marshaller omits a nil pointer entirely. member := &rds.Subnet{ SubnetIdentifier: aws.String(subnet.SubnetID), SubnetStatus: aws.String("Active"), + SubnetOutpost: &rds.Outpost{}, } if subnet.AvailabilityZone != "" { member.SubnetAvailabilityZone = &rds.AvailabilityZone{Name: aws.String(subnet.AvailabilityZone)} diff --git a/spinifex/handlers/rds/subnetgroup_test.go b/spinifex/handlers/rds/subnetgroup_test.go index da3b9afb1..a86486154 100644 --- a/spinifex/handlers/rds/subnetgroup_test.go +++ b/spinifex/handlers/rds/subnetgroup_test.go @@ -1,12 +1,17 @@ package handlers_rds import ( + "bytes" + "encoding/json" + "encoding/xml" "testing" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil" "github.com/aws/aws-sdk-go/service/ec2" "github.com/aws/aws-sdk-go/service/rds" "github.com/mulgadc/spinifex/spinifex/awserrors" + "github.com/mulgadc/spinifex/spinifex/utils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -180,6 +185,33 @@ func TestDescribeDBSubnetGroups_ListsAndNames(t *testing.T) { assert.Equal(t, "zeta", aws.StringValue(named.DBSubnetGroups[0].DBSubnetGroupName)) } +// AWS reports SupportedNetworkTypes on the group and SubnetOutpost as {} on each +// subnet. Read back through the NATS JSON hop and the gateway's XML, as a client +// sees it, since an empty Outpost that either hop drops reads as absent. +func TestDescribeDBSubnetGroups_ReportsNetworkTypesAndAnEmptyOutpost(t *testing.T) { + t.Parallel() + h := newCreateHarness(t, testBaseDomain) + _, err := h.svc.CreateDBSubnetGroup(t.Context(), subnetGroupInput(testSubnetGroup, "subnet-alpha"), testAccountID) + require.NoError(t, err) + described, err := h.svc.DescribeDBSubnetGroups(t.Context(), &rds.DescribeDBSubnetGroupsInput{}, testAccountID) + require.NoError(t, err) + + wire, err := json.Marshal(described) + require.NoError(t, err) + var relayed rds.DescribeDBSubnetGroupsOutput + require.NoError(t, json.Unmarshal(wire, &relayed)) + body, err := utils.MarshalToXML(utils.GenerateIAMXMLPayload("DescribeDBSubnetGroups", &relayed)) + require.NoError(t, err) + var parsed rds.DescribeDBSubnetGroupsOutput + require.NoError(t, xmlutil.UnmarshalXML(&parsed, xml.NewDecoder(bytes.NewReader(body)), "DescribeDBSubnetGroupsResult")) + + require.Len(t, parsed.DBSubnetGroups, 1) + group := parsed.DBSubnetGroups[0] + assert.Equal(t, []string{"IPV4"}, aws.StringValueSlice(group.SupportedNetworkTypes)) + require.Len(t, group.Subnets, 1) + assert.Equal(t, &rds.Outpost{}, group.Subnets[0].SubnetOutpost) +} + // A client polling a create would read an empty list as "gone" rather than // "not there", so a named group that does not exist is an error. func TestDescribeDBSubnetGroups_RejectsAnUnknownName(t *testing.T) {