From 06ea7ecfd16dfd7960bc900b319bd45d3db0aacc Mon Sep 17 00:00:00 2001 From: Josh Siviour Date: Fri, 26 Jun 2026 09:23:03 +1000 Subject: [PATCH] fix: ECS ListTaskDefinitions honors Status filter (default ACTIVE) (#426) ListTaskDefinitions appended every revision regardless of the requested status, so deregistered (INACTIVE) task definitions never dropped off the default listing and the console could not clear them. Filter by status, defaulting to ACTIVE to match AWS. --- spinifex/handlers/ecs/service.go | 10 +++++++-- spinifex/handlers/ecs/service_test.go | 32 +++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/spinifex/handlers/ecs/service.go b/spinifex/handlers/ecs/service.go index fefa64d98..1b0b6b981 100644 --- a/spinifex/handlers/ecs/service.go +++ b/spinifex/handlers/ecs/service.go @@ -352,12 +352,18 @@ func (s *Service) DescribeTaskDefinition(input *ecs.DescribeTaskDefinitionInput, return &ecs.DescribeTaskDefinitionOutput{TaskDefinition: rec.toAWS()}, nil } -// ListTaskDefinitions returns all revision ARNs, optionally filtered by family. +// ListTaskDefinitions returns revision ARNs, optionally filtered by family and +// by status. Matching AWS, the status defaults to ACTIVE when unset, so +// deregistered (INACTIVE) revisions drop off the default listing. func (s *Service) ListTaskDefinitions(input *ecs.ListTaskDefinitionsInput, accountID string) (*ecs.ListTaskDefinitionsOutput, error) { kv, err := s.bucket(accountID) if err != nil { return nil, err } + wantStatus := aws.StringValue(input.Status) + if wantStatus == "" { + wantStatus = TaskDefStatusActive + } prefix := TaskDefFamiliesPrefix() if fam := aws.StringValue(input.FamilyPrefix); fam != "" { prefix = TaskDefRevsPrefix(fam) @@ -376,7 +382,7 @@ func (s *Service) ListTaskDefinitions(input *ecs.ListTaskDefinitionsInput, accou if err != nil { return nil, err } - if found { + if found && rec.Status == wantStatus { out.TaskDefinitionArns = append(out.TaskDefinitionArns, aws.String(rec.ARN)) } } diff --git a/spinifex/handlers/ecs/service_test.go b/spinifex/handlers/ecs/service_test.go index 334bac00f..e6f39d7bc 100644 --- a/spinifex/handlers/ecs/service_test.go +++ b/spinifex/handlers/ecs/service_test.go @@ -90,6 +90,38 @@ func TestService_RegisterTaskDefinition_RevisionBump(t *testing.T) { assert.Len(t, list.TaskDefinitionArns, 2) } +func TestService_ListTaskDefinitions_StatusFilter(t *testing.T) { + svc, _ := newTestService(t) + registerTaskDef(t, svc, "keep", 128, 256) + registerTaskDef(t, svc, "gone", 128, 256) + + _, err := svc.DeregisterTaskDefinition(&ecs.DeregisterTaskDefinitionInput{ + TaskDefinition: aws.String("gone:1"), + }, testAccountID) + require.NoError(t, err) + + // Default (unset) status lists ACTIVE only; the deregistered revision drops. + active, err := svc.ListTaskDefinitions(&ecs.ListTaskDefinitionsInput{}, testAccountID) + require.NoError(t, err) + require.Len(t, active.TaskDefinitionArns, 1) + assert.Contains(t, aws.StringValue(active.TaskDefinitionArns[0]), "keep:1") + + // Explicit ACTIVE matches the default. + activeExplicit, err := svc.ListTaskDefinitions(&ecs.ListTaskDefinitionsInput{ + Status: aws.String(TaskDefStatusActive), + }, testAccountID) + require.NoError(t, err) + assert.Len(t, activeExplicit.TaskDefinitionArns, 1) + + // INACTIVE returns only the deregistered revision. + inactive, err := svc.ListTaskDefinitions(&ecs.ListTaskDefinitionsInput{ + Status: aws.String(TaskDefStatusInactive), + }, testAccountID) + require.NoError(t, err) + require.Len(t, inactive.TaskDefinitionArns, 1) + assert.Contains(t, aws.StringValue(inactive.TaskDefinitionArns[0]), "gone:1") +} + func TestService_RegisterTaskDefinition_NoFamily(t *testing.T) { svc, _ := newTestService(t) _, err := svc.RegisterTaskDefinition(&ecs.RegisterTaskDefinitionInput{}, testAccountID)