Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ require (
github.com/aws/aws-sdk-go-v2/config v1.29.17
github.com/aws/aws-sdk-go-v2/credentials v1.17.70
github.com/aws/aws-sdk-go-v2/service/ecr v1.45.1
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.33.2
github.com/bombsimon/logrusr/v4 v4.1.0
github.com/go-chi/transport v0.5.0
github.com/gofri/go-github-ratelimit v1.1.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo=
github.com/aws/aws-sdk-go-v2/service/ecr v1.45.1 h1:Bwzh202Aq7/MYnAjXA9VawCf6u+hjwMdoYmZ4HYsdf8=
github.com/aws/aws-sdk-go-v2/service/ecr v1.45.1/go.mod h1:xZzWl9AXYa6zsLLH41HBFW8KRKJRIzlGmvSM0mVMIX4=
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.33.2 h1:XJ/AEFYj9VFPJdF+VFi4SUPEDfz1akHwxxm07JfZJcs=
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.33.2/go.mod h1:JUBHdhvKbbKmhaHjLsKJAWnQL80T6nURmhB/LEprV+4=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4 h1:CXV68E2dNqhuynZJPB80bhPQwAKqBWVer887figW6Jc=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.4/go.mod h1:/xFi9KtvBXP97ppCz1TAEvU1Uf66qvid89rbem3wCzQ=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.17 h1:t0E6FzREdtCsiLIoLCWsYliNsRBgyGD/MCK571qk4MI=
Expand Down
4 changes: 4 additions & 0 deletions pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/jetstack/version-checker/pkg/client/acr"
"github.com/jetstack/version-checker/pkg/client/docker"
"github.com/jetstack/version-checker/pkg/client/ecr"
"github.com/jetstack/version-checker/pkg/client/ecrpublic"
"github.com/jetstack/version-checker/pkg/client/fallback"
"github.com/jetstack/version-checker/pkg/client/gcr"
"github.com/jetstack/version-checker/pkg/client/ghcr"
Expand All @@ -38,6 +39,7 @@ type Client struct {
type Options struct {
ACR acr.Options
ECR ecr.Options
ECRPublic ecrpublic.Options // Add ECRPublic options
GCR gcr.Options
GHCR ghcr.Options
Docker docker.Options
Expand All @@ -54,6 +56,7 @@ func New(ctx context.Context, log *logrus.Entry, opts Options) (*Client, error)
if opts.Transport != nil {
opts.Quay.Transporter = opts.Transport
opts.ECR.Transporter = opts.Transport
opts.ECRPublic.Transporter = opts.Transport // Add ECR public transporter
opts.GHCR.Transporter = opts.Transport
opts.GCR.Transporter = opts.Transport
}
Expand Down Expand Up @@ -106,6 +109,7 @@ func New(ctx context.Context, log *logrus.Entry, opts Options) (*Client, error)
selfhostedClients,
acrClient,
ecr.New(opts.ECR),
ecrpublic.New(opts.ECRPublic),
dockerClient,
gcr.New(opts.GCR),
ghcr.New(opts.GHCR),
Expand Down
89 changes: 89 additions & 0 deletions pkg/client/ecrpublic/ecr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package ecrpublic

import (
"context"
"fmt"
"net/http"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"

"github.com/aws/aws-sdk-go-v2/service/ecrpublic"
"github.com/jetstack/version-checker/pkg/api"
"github.com/jetstack/version-checker/pkg/client/util"
)

type Client struct {
Config aws.Config

Options
}

type Options struct {
IamRoleArn string
AccessKeyID string
SecretAccessKey string
SessionToken string
Transporter http.RoundTripper
}

func New(opts Options) *Client {
return &Client{
Options: opts,
}
}

func (c *Client) Name() string {
return "ecrpublic"
}

func (c *Client) Tags(ctx context.Context, host, repo, image string) ([]api.ImageTag, error) {
client, err := c.createClient(ctx, "us-east-1")
if err != nil {
return nil, err
}
repoName := util.JoinRepoImage(repo, image)
images, err := client.DescribeImages(ctx, &ecrpublic.DescribeImagesInput{
RepositoryName: &repoName,
})

if err != nil {
return nil, fmt.Errorf("failed to describe images: %s", err)
}

var tags []api.ImageTag
for _, img := range images.ImageDetails {
// Continue early if no tags available
if len(img.ImageTags) == 0 {
tags = append(tags, api.ImageTag{
SHA: *img.ImageDigest,
Timestamp: *img.ImagePushedAt,
})

continue
}

for _, tag := range img.ImageTags {
tags = append(tags, api.ImageTag{
SHA: *img.ImageDigest,
Timestamp: *img.ImagePushedAt,
Tag: tag,
})
}
}
// For public ECR, RegistryId is not required, so id can be left empty

return tags, nil
}

func (c *Client) createClient(ctx context.Context, region string) (*ecrpublic.Client, error) {
cfg, err := config.LoadDefaultConfig(ctx,
config.WithRegion(region),
)
if err != nil {
return nil, err
}

client := ecrpublic.NewFromConfig(cfg)
return client, nil
}
25 changes: 25 additions & 0 deletions pkg/client/ecrpublic/path.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package ecrpublic

import (
"regexp"
"strings"
)

var (
// For public ECR, we only need to match the exact hostname "public.ecr.aws"
ecrPublicPattern = regexp.MustCompile(`^public\.ecr\.aws$`)
)

func (c *Client) IsHost(host string) bool {
return ecrPublicPattern.MatchString(host)
}

func (c *Client) RepoImageFromPath(path string) (string, string) {
lastIndex := strings.LastIndex(path, "/")

if lastIndex == -1 {
return "", path
}

return path[:lastIndex], path[lastIndex+1:]
}
106 changes: 106 additions & 0 deletions pkg/client/ecrpublic/path_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package ecrpublic

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestIsHost(t *testing.T) {
tests := map[string]struct {
host string
expIs bool
}{
"an empty host should be false": {
host: "",
expIs: false,
},
"random string should be false": {
host: "foobar",
expIs: false,
},
"random string with dots should be false": {
host: "foobar.foo",
expIs: false,
},
"just amazonawsaws.com should be false": {
host: "amazonaws.com",
expIs: false,
},
"ecr.foo.amazonaws.com with random sub domains should be false": {
host: "bar.ecr.foo.amazonaws.com",
expIs: false,
},
"dkr.ecr.foo.amazonaws.com with random sub domains should be false": {
host: "dkr.ecr.foo.amazonaws.com",
expIs: false,
},
"hello123.dkr.ecr.foo.amazonaws.com false": {
host: "hello123.dkr.ecr.foo.amazonaws.com",
expIs: false,
},
"123hello.hello.dkr.ecr.foo.amazonaws.com false": {
host: "123hello.hello.dkr.ecr.foo.amazonaws.com",
expIs: false,
},
"123hello.dkr.ecr.foo.amazonaws.comfoo false": {
host: "123hello.dkr.ecr.foo.amazonaws.comfoo",
expIs: false,
},
"public.ecr.aws should be true": {
host: "public.ecr.aws",
expIs: true,
},
"public.ecr.aws with random subdomains should be false": {
host: "foo.public.ecr.aws",
expIs: false,
},
}

handler := new(Client)
for name, test := range tests {
t.Run(name, func(t *testing.T) {
if isHost := handler.IsHost(test.host); isHost != test.expIs {
t.Errorf("%s: unexpected IsHost, exp=%t got=%t",
test.host, test.expIs, isHost)
}
})
}
}

func TestRepoImage(t *testing.T) {
tests := map[string]struct {
path string
expRepo, expImage string
}{
"single image should return as image": {
path: "kube-scheduler",
expRepo: "",
expImage: "kube-scheduler",
},
"two segments to path should return both": {
path: "jetstack-cre/version-checker",
expRepo: "jetstack-cre",
expImage: "version-checker",
},
"multiple segments to path should return all in repo, last segment image": {
path: "k8s-artifacts-prod/ingress-nginx/nginx",
expRepo: "k8s-artifacts-prod/ingress-nginx",
expImage: "nginx",
},
"region": {
path: "000000000000.dkr.ecr.eu-west-2.amazonaws.com/version-checker",
expRepo: "000000000000.dkr.ecr.eu-west-2.amazonaws.com",
expImage: "version-checker",
},
}

handler := new(Client)
for name, test := range tests {
t.Run(name, func(t *testing.T) {
repo, image := handler.RepoImageFromPath(test.path)
assert.Equal(t, repo, test.expRepo)
assert.Equal(t, image, test.expImage)
})
}
}
Loading