From 1aba62386a0cbeb1aa9f032e13cd631aa84a8d80 Mon Sep 17 00:00:00 2001 From: Matteo Silvestri Date: Mon, 8 Jun 2026 12:49:52 +0200 Subject: [PATCH 1/3] fix: paginate ECR DescribeImages to retrieve all image tags --- pkg/client/ecr/ecr.go | 48 +++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/pkg/client/ecr/ecr.go b/pkg/client/ecr/ecr.go index 49367d50..4f5a44dc 100644 --- a/pkg/client/ecr/ecr.go +++ b/pkg/client/ecr/ecr.go @@ -57,35 +57,43 @@ func (c *Client) Tags(ctx context.Context, host, repo, image string) ([]api.Imag repoName := util.JoinRepoImage(repo, image) - images, err := client.DescribeImages(ctx, &ecr.DescribeImagesInput{ + tags := map[string]api.ImageTag{} + input := &ecr.DescribeImagesInput{ RepositoryName: &repoName, RegistryId: aws.String(id), - }) - - if err != nil { - return nil, fmt.Errorf("failed to describe images: %s", err) } - tags := map[string]api.ImageTag{} - for _, img := range images.ImageDetails { - // Base data shared across tags - base := api.ImageTag{ - SHA: *img.ImageDigest, - Timestamp: *img.ImagePushedAt, + for { + images, err := client.DescribeImages(ctx, input) + if err != nil { + return nil, fmt.Errorf("failed to describe images: %s", err) } - // Continue early if no tags available - if len(img.ImageTags) == 0 { - tags[base.SHA] = base - continue + for _, img := range images.ImageDetails { + // Base data shared across tags + base := api.ImageTag{ + SHA: *img.ImageDigest, + Timestamp: *img.ImagePushedAt, + } + + // Continue early if no tags available + if len(img.ImageTags) == 0 { + tags[base.SHA] = base + continue + } + + for _, tag := range img.ImageTags { + current := base // copy the base + current.Tag = tag // set tag value + + util.BuildTags(tags, tag, ¤t) + } } - for _, tag := range img.ImageTags { - current := base // copy the base - current.Tag = tag // set tag value - - util.BuildTags(tags, tag, ¤t) + if images.NextToken == nil { + break } + input.NextToken = images.NextToken } return util.TagMaptoList(tags), nil From a03e0472b09111fa8176aa16aff7a0dbb85a2b02 Mon Sep 17 00:00:00 2001 From: Matteo Silvestri Date: Mon, 15 Jun 2026 14:51:06 +0100 Subject: [PATCH 2/3] fix: address Copilot review suggestions on ECR pagination - Use %w for error wrapping so callers can unwrap with errors.Is/As - Also break on empty-string NextToken to guard against non-nil empty token edge case --- pkg/client/ecr/ecr.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/client/ecr/ecr.go b/pkg/client/ecr/ecr.go index 4f5a44dc..7cf63337 100644 --- a/pkg/client/ecr/ecr.go +++ b/pkg/client/ecr/ecr.go @@ -66,7 +66,7 @@ func (c *Client) Tags(ctx context.Context, host, repo, image string) ([]api.Imag for { images, err := client.DescribeImages(ctx, input) if err != nil { - return nil, fmt.Errorf("failed to describe images: %s", err) + return nil, fmt.Errorf("failed to describe images: %w", err) } for _, img := range images.ImageDetails { @@ -90,7 +90,7 @@ func (c *Client) Tags(ctx context.Context, host, repo, image string) ([]api.Imag } } - if images.NextToken == nil { + if images.NextToken == nil || aws.ToString(images.NextToken) == "" { break } input.NextToken = images.NextToken From 6a1b4490ab1b6fe322726a58176e0251eb6f5dfe Mon Sep 17 00:00:00 2001 From: Matteo Silvestri Date: Mon, 15 Jun 2026 15:04:40 +0100 Subject: [PATCH 3/3] fix: simplify NextToken check using aws.ToString --- pkg/client/ecr/ecr.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/client/ecr/ecr.go b/pkg/client/ecr/ecr.go index 7cf63337..54c60327 100644 --- a/pkg/client/ecr/ecr.go +++ b/pkg/client/ecr/ecr.go @@ -90,7 +90,7 @@ func (c *Client) Tags(ctx context.Context, host, repo, image string) ([]api.Imag } } - if images.NextToken == nil || aws.ToString(images.NextToken) == "" { + if aws.ToString(images.NextToken) == "" { break } input.NextToken = images.NextToken