Skip to content

Commit 7a55789

Browse files
authored
Merge pull request #8 from oreillymedia/CL-1152-cloudformation-stack-fix
fix(cloudformation-stack): fix nil pointer dereference when stack does not have a RoleARN defined
2 parents f601c15 + 8eb54cb commit 7a55789

File tree

2 files changed

+58
-1
lines changed

2 files changed

+58
-1
lines changed

resources/cloudformation-stack.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,8 @@ func (r *CloudFormationStack) removeWithAttempts(ctx context.Context, attempt in
175175
var awsErr awserr.Error
176176
ok := errors.As(err, &awsErr)
177177
if ok && awsErr.Code() == "ValidationError" {
178-
if awsErr.Message() == fmt.Sprintf("Role %s is invalid or cannot be assumed", *r.roleARN) {
178+
// roleARN could be nil. It is not mandatory to have a roleARN for a stack.
179+
if r.roleARN != nil && awsErr.Message() == fmt.Sprintf("Role %s is invalid or cannot be assumed", *r.roleARN) {
179180
if r.settings.GetBool("CreateRoleToDeleteStack") {
180181
r.logger.Infof("CloudFormationStack stackName=%s attempt=%d maxAttempts=%d creating role to delete stack",
181182
*r.Name, attempt, r.maxDeleteAttempts)

resources/cloudformation-stack_test.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,3 +354,59 @@ func TestCloudformationStack_Remove_Stack_UpdateInProgress(t *testing.T) {
354354
})
355355
}
356356
}
357+
358+
func TestCloudformationStack_Remove_RoleARNIsNil(t *testing.T) {
359+
a := assert.New(t)
360+
ctrl := gomock.NewController(t)
361+
defer ctrl.Finish()
362+
363+
mockCloudformation := mock_cloudformationiface.NewMockCloudFormationAPI(ctrl)
364+
365+
stack := CloudFormationStack{
366+
svc: mockCloudformation,
367+
logger: logrus.NewEntry(logrus.StandardLogger()),
368+
Name: ptr.String("foobar"),
369+
settings: &libsettings.Setting{
370+
"DisableDeletionProtection": true,
371+
},
372+
roleARN: nil, // roleARN is nil
373+
}
374+
375+
gomock.InOrder(
376+
mockCloudformation.EXPECT().DescribeStacks(gomock.Eq(&cloudformation.DescribeStacksInput{
377+
StackName: ptr.String("foobar"),
378+
})).Return(&cloudformation.DescribeStacksOutput{
379+
Stacks: []*cloudformation.Stack{
380+
{
381+
StackStatus: ptr.String(cloudformation.StackStatusDeleteFailed),
382+
},
383+
},
384+
}, nil),
385+
mockCloudformation.EXPECT().ListStackResources(gomock.Eq(&cloudformation.ListStackResourcesInput{
386+
StackName: ptr.String("foobar"),
387+
})).Return(&cloudformation.ListStackResourcesOutput{
388+
StackResourceSummaries: []*cloudformation.StackResourceSummary{
389+
{
390+
ResourceStatus: ptr.String(cloudformation.ResourceStatusDeleteComplete),
391+
LogicalResourceId: ptr.String("fooDeleteComplete"),
392+
},
393+
{
394+
ResourceStatus: ptr.String(cloudformation.ResourceStatusDeleteFailed),
395+
LogicalResourceId: ptr.String("fooDeleteFailed"),
396+
},
397+
},
398+
}, nil),
399+
mockCloudformation.EXPECT().DeleteStack(gomock.Eq(&cloudformation.DeleteStackInput{
400+
StackName: ptr.String("foobar"),
401+
RetainResources: []*string{
402+
ptr.String("fooDeleteFailed"),
403+
},
404+
})).Return(nil, nil),
405+
mockCloudformation.EXPECT().WaitUntilStackDeleteComplete(gomock.Eq(&cloudformation.DescribeStacksInput{
406+
StackName: ptr.String("foobar"),
407+
})).Return(nil),
408+
)
409+
410+
err := stack.Remove(context.TODO())
411+
a.Nil(err)
412+
}

0 commit comments

Comments
 (0)