From c395722344ecbf61853998b69ef8c7c6a3a804b7 Mon Sep 17 00:00:00 2001 From: Julian Sommer <115516918+juliansommer@users.noreply.github.com> Date: Tue, 6 Oct 2026 11:05:43 +1000 Subject: [PATCH] fix: answer ModifyInstanceAttribute with no or several attributes with InvalidParameterCombination --- .../ec2/instance/ModifyInstanceAttribute.go | 10 +++++-- .../instance/ModifyInstanceAttribute_test.go | 30 ++++++++++++++----- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/spinifex/gateway/ec2/instance/ModifyInstanceAttribute.go b/spinifex/gateway/ec2/instance/ModifyInstanceAttribute.go index bfe7fdf98..a20a62f96 100644 --- a/spinifex/gateway/ec2/instance/ModifyInstanceAttribute.go +++ b/spinifex/gateway/ec2/instance/ModifyInstanceAttribute.go @@ -16,7 +16,8 @@ import ( ) // ValidateModifyInstanceAttributeInput validates the input constraints for ModifyInstanceAttribute. -// AWS rejects calls with multiple attributes set in a single request. +// AWS answers InvalidParameterCombination when no attribute, or more than one, +// is set in a single request. func ValidateModifyInstanceAttributeInput(input *ec2.ModifyInstanceAttributeInput) error { if input == nil { return errors.New(awserrors.ErrorInvalidParameterValue) @@ -41,8 +42,11 @@ func ValidateModifyInstanceAttributeInput(input *ec2.ModifyInstanceAttributeInpu if input.DisableApiTermination != nil { count++ } - if count != 1 { - return errors.New(awserrors.ErrorInvalidParameterValue) + switch { + case count == 0: + return awserrors.Errorf(awserrors.ErrorInvalidParameterCombination, "No attributes specified.") + case count > 1: + return awserrors.Errorf(awserrors.ErrorInvalidParameterCombination, "The request must contain a single attribute") } if input.InstanceType != nil && (input.InstanceType.Value == nil || *input.InstanceType.Value == "") { diff --git a/spinifex/gateway/ec2/instance/ModifyInstanceAttribute_test.go b/spinifex/gateway/ec2/instance/ModifyInstanceAttribute_test.go index 843049b65..3cbebc395 100644 --- a/spinifex/gateway/ec2/instance/ModifyInstanceAttribute_test.go +++ b/spinifex/gateway/ec2/instance/ModifyInstanceAttribute_test.go @@ -48,13 +48,20 @@ func TestValidateModifyInstanceAttributeInput_BadPrefix(t *testing.T) { assert.Equal(t, awserrors.ErrorInvalidInstanceIDMalformed, err.Error()) } +func assertSingleAttributeError(t *testing.T, err error, wantMessage string) { + t.Helper() + code, message, ok := awserrors.ResolveErrorDetail(err) + require.True(t, ok) + assert.Equal(t, awserrors.ErrorInvalidParameterCombination, code) + assert.Equal(t, wantMessage, message) +} + func TestValidateModifyInstanceAttributeInput_NoAttributeSet(t *testing.T) { t.Parallel() err := ValidateModifyInstanceAttributeInput(&ec2.ModifyInstanceAttributeInput{ InstanceId: aws.String("i-abc123"), }) - require.Error(t, err) - assert.Equal(t, awserrors.ErrorInvalidParameterValue, err.Error()) + assertSingleAttributeError(t, err, "No attributes specified.") } func TestValidateModifyInstanceAttributeInput_MultipleAttributes(t *testing.T) { @@ -64,8 +71,7 @@ func TestValidateModifyInstanceAttributeInput_MultipleAttributes(t *testing.T) { InstanceType: &ec2.AttributeValue{Value: aws.String("t3.micro")}, UserData: &ec2.BlobAttributeValue{Value: []byte("data")}, }) - require.Error(t, err) - assert.Equal(t, awserrors.ErrorInvalidParameterValue, err.Error()) + assertSingleAttributeError(t, err, "The request must contain a single attribute") } func TestValidateModifyInstanceAttributeInput_EmptyInstanceType(t *testing.T) { @@ -122,8 +128,7 @@ func TestValidateModifyInstanceAttributeInput_DisableApiTerminationWithOther(t * DisableApiTermination: &ec2.AttributeBooleanValue{Value: aws.Bool(true)}, InstanceType: &ec2.AttributeValue{Value: aws.String("t3.micro")}, }) - require.Error(t, err) - assert.Equal(t, awserrors.ErrorInvalidParameterValue, err.Error()) + assertSingleAttributeError(t, err, "The request must contain a single attribute") } func TestValidateModifyInstanceAttributeInput_ValidSourceDestCheck(t *testing.T) { @@ -142,8 +147,17 @@ func TestValidateModifyInstanceAttributeInput_SourceDestCheckWithOtherAttribute( SourceDestCheck: &ec2.AttributeBooleanValue{Value: aws.Bool(false)}, InstanceType: &ec2.AttributeValue{Value: aws.String("t3.micro")}, }) - require.Error(t, err) - assert.Equal(t, awserrors.ErrorInvalidParameterValue, err.Error()) + assertSingleAttributeError(t, err, "The request must contain a single attribute") +} + +func TestValidateModifyInstanceAttributeInput_SourceDestCheckWithDisableApiTermination(t *testing.T) { + t.Parallel() + err := ValidateModifyInstanceAttributeInput(&ec2.ModifyInstanceAttributeInput{ + InstanceId: aws.String("i-abc123"), + SourceDestCheck: &ec2.AttributeBooleanValue{Value: aws.Bool(false)}, + DisableApiTermination: &ec2.AttributeBooleanValue{Value: aws.Bool(true)}, + }) + assertSingleAttributeError(t, err, "The request must contain a single attribute") } // --- Gateway function tests ---