/* * Copyright 2026 Oleg Borodin * * This work is published and licensed under a Creative Commons * Attribution-NonCommercial-NoDerivatives 4.0 International License. * * Distribution of this work is permitted, but commercial use and * modifications are strictly prohibited. */ package client import ( "context" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/crane" "github.com/google/go-containerregistry/pkg/name" pkg "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/remote/transport" ) type ImageDescr struct { ConfigFile *pkg.ConfigFile `json:"configFile,omitempty"` Manifest *pkg.Manifest `json:"manifest,omitempty"` Tags []string `json:"avilableTags,omitempty"` } func (cli *Client) ImageInfo(ctx context.Context, imagepath string) (*ImageDescr, error) { var err error res := &ImageDescr{} imagepath, username, password, err := repackReference(imagepath) if err != nil { return res, err } options := make([]crane.Option, 0) options = append(options, crane.WithContext(ctx)) ref, err := name.ParseReference(imagepath) if err != nil { return res, err } repo := ref.Context() if err != nil { return res, err } if username != "" && password != "" { defaultTransport := &roundTripper{} scopes := []string{repo.Scope(transport.PullScope)} regName := repo.RegistryStr() reg, err := name.NewRegistry(regName) if err != nil { return res, err } basicAuth := &authn.Basic{ Username: username, Password: password, } authTransport, err := transport.NewWithContext(ctx, reg, basicAuth, defaultTransport, scopes) if err != nil { return res, err } options = append(options, crane.WithTransport(authTransport)) } else { transport := &roundTripper{} options = append(options, crane.WithTransport(transport)) } image, err := crane.Pull(imagepath, options...) if err != nil { return res, err } config, err := image.ConfigFile() if err != nil { return res, err } res.ConfigFile = config manifest, err := image.Manifest() if err != nil { return res, err } res.Manifest = manifest return res, err remoteOptions := make([]remote.Option, 0) remoteOptions = append(remoteOptions, remote.WithContext(ctx)) if username != "" && password != "" { defaultTransport := &roundTripper{} scopes := []string{repo.Scope(transport.PullScope)} regName := repo.RegistryStr() reg, err := name.NewRegistry(regName) if err != nil { return res, err } basicAuth := &authn.Basic{ Username: username, Password: password, } authTransport, err := transport.NewWithContext(ctx, reg, basicAuth, defaultTransport, scopes) if err != nil { return res, err } remoteOptions = append(remoteOptions, remote.WithTransport(authTransport)) } else { transport := &roundTripper{} options = append(options, crane.WithTransport(transport)) } tags, err := remote.List(repo, remoteOptions...) if err != nil { return res, err } res.Tags = tags return res, err }