diff --git a/cmd/ketchup/api.go b/cmd/ketchup/api.go index 51c6ce07..003a5f66 100644 --- a/cmd/ketchup/api.go +++ b/cmd/ketchup/api.go @@ -134,7 +134,7 @@ func main() { userServiceService := userService.New(userStore.New(ketchupDb), &authServiceService) githubService := github.New(githubConfig, redisClient, telemetryService.MeterProvider(), telemetryService.TracerProvider()) - dockerService := docker.New(dockerConfig, githubConfig.Token) + dockerService := docker.New(dockerConfig) helmService := helm.New() npmService := npm.New() pypiService := pypi.New() diff --git a/cmd/notifier/notifier.go b/cmd/notifier/notifier.go index 14d6dd72..6d15db01 100644 --- a/cmd/notifier/notifier.go +++ b/cmd/notifier/notifier.go @@ -79,7 +79,7 @@ func main() { helmService := helm.New() npmService := npm.New() pypiService := pypi.New() - repositoryServiceService := repositoryService.New(repositoryStore.New(ketchupDb), github.New(githubConfig, nil, nil, telemetryService.TracerProvider()), helmService, docker.New(dockerConfig, githubConfig.Token), npmService, pypiService) + repositoryServiceService := repositoryService.New(repositoryStore.New(ketchupDb), github.New(githubConfig, nil, nil, telemetryService.TracerProvider()), helmService, docker.New(dockerConfig), npmService, pypiService) ketchupServiceService := ketchupService.New(ketchupStore.New(ketchupDb), repositoryServiceService) userServiceService := userService.New(userStore.New(ketchupDb), nil) diff --git a/pkg/provider/docker/docker.go b/pkg/provider/docker/docker.go index 6f8332c3..1565e25f 100644 --- a/pkg/provider/docker/docker.go +++ b/pkg/provider/docker/docker.go @@ -19,19 +19,20 @@ import ( ) const ( - registryURL = "https://index.docker.io" - authURL = "https://auth.docker.io/token" - nextLink = `rel="next"` + registryURL = "https://index.docker.io" + authURL = "https://auth.docker.io/token" + ghcrLoginURL = "https://ghcr.io/token" + nextLink = `rel="next"` ) type authResponse struct { AccessToken string `json:"access_token"` + Token string `json:"token"` } type Service struct { - username string - password string - githubToken string + username string + password string } type Config struct { @@ -48,11 +49,10 @@ func Flags(fs *flag.FlagSet, prefix string, overrides ...flags.Override) *Config return &config } -func New(config *Config, githubToken string) Service { +func New(config *Config) Service { return Service{ - username: config.Username, - password: config.Password, - githubToken: githubToken, + username: config.Username, + password: config.Password, } } @@ -95,12 +95,13 @@ func (s Service) getImageDetails(ctx context.Context, repository string) (string parts := strings.Split(repository, "/") if len(parts) > 2 { var token string + var err error if parts[0] == "ghcr.io" { - token = "token " + s.githubToken + token, err = s.ghcr(ctx, strings.Join(parts[1:], "/")) } - return fmt.Sprintf("https://%s", parts[0]), strings.Join(parts[1:], "/"), token, nil + return fmt.Sprintf("https://%s", parts[0]), strings.Join(parts[1:], "/"), token, err } if len(parts) == 1 { @@ -137,6 +138,23 @@ func (s Service) login(ctx context.Context, repository string) (string, error) { return authContent.AccessToken, nil } +func (s Service) ghcr(ctx context.Context, repository string) (string, error) { + values := url.Values{} + values.Add("scope", fmt.Sprintf("repository:%s:pull", repository)) + + resp, err := request.Get(fmt.Sprintf("%s?%s", ghcrLoginURL, values.Encode())).Send(ctx, nil) + if err != nil { + return "", fmt.Errorf("authenticate to `%s`: %w", ghcrLoginURL, err) + } + + var authContent authResponse + if err := httpjson.Read(resp, &authContent); err != nil { + return "", fmt.Errorf("read auth token: %w", err) + } + + return fmt.Sprintf("Bearer %s", authContent.Token), nil +} + func browseRegistryTagsList(body io.ReadCloser, versions map[string]semver.Version, patterns map[string]semver.Pattern) error { done := make(chan struct{}) versionsStream := make(chan string, runtime.NumCPU())