Ctrl K
ComunidadGuías…

iclient/registry.go

Rama develop · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package iclient

import (
	"fmt"
	"net/http"
	"net/url"
	"time"

	incusTLS "github.com/lxc/incus/v7/shared/tls"
	"oras.land/oras-go/v2/registry"
	"oras.land/oras-go/v2/registry/remote"
	"oras.land/oras-go/v2/registry/remote/auth"
	"oras.land/oras-go/v2/registry/remote/retry"
)

// A registry answers metadata promptly, where an Incus operation long-polls.
const registryResponseHeaderTimeout = 30 * time.Second

// NewRepository returns an OCI Distribution client for one image on the
// registry an "oci" remote points at. image carries the tag or digest,
// e.g. "library/redis:alpine".
//
// The registry is the remote's own address, so a mirror stands in for what it
// mirrors, and the proxy environment applies as it does to a Connection.
// Credentials are info's Username and Password, which RemoteInfos fills from
// the remote's credentials helper; an address still carrying its own is
// refused rather than silently reached anonymously.
func NewRepository(info *ConfigRemoteInfo, image string) (*remote.Repository, error) {
	if info.Protocol != "oci" {
		return nil, fmt.Errorf("%q: %w", info.Name, ErrRegistryProtocol)
	}

	if len(info.Addrs) == 0 {
		return nil, fmt.Errorf("%q: %w", info.Name, ErrConnectionNoAddress)
	}

	// The address is never echoed back: a hand-built info may still hold a
	// password in it, which is what the next check is about.
	addr, err := url.Parse(info.Addrs[0])
	if err != nil {
		return nil, fmt.Errorf("%q: parsing the registry address: %w", info.Name, err)
	}

	if addr.User != nil {
		return nil, fmt.Errorf("%q: %w", info.Name, ErrRegistryAddrCredentials)
	}

	ref, err := registry.ParseReference(addr.Host + "/" + image)
	if err != nil {
		return nil, fmt.Errorf("%q: %w", info.Name, err)
	}

	// A registry is handed no client certificate; only its own may be pinned.
	tlsConfig, err := incusTLS.GetTLSConfigMem("", "", info.ClientCA, info.ServerCert, info.InsecureSkipVerify)
	if err != nil {
		return nil, fmt.Errorf("%q: building the TLS config: %w", info.Name, err)
	}

	transport := incusTransport()
	transport.TLSClientConfig = tlsConfig
	transport.Proxy = http.ProxyFromEnvironment
	transport.ResponseHeaderTimeout = registryResponseHeaderTimeout

	client := &auth.Client{
		Client: &http.Client{Transport: retry.NewTransport(transport)},
		Cache:  auth.NewCache(),
	}

	if info.UserAgent != "" {
		client.SetUserAgent(info.UserAgent)
	}

	if info.Username != "" || info.Password != "" {
		// Keyed on Host: auth.Client maps docker.io to registry-1.docker.io first.
		client.Credential = auth.StaticCredential(ref.Host(), auth.Credential{
			Username: info.Username,
			Password: info.Password,
		})
	}

	return &remote.Repository{
		Client:    client,
		Reference: ref,
		PlainHTTP: addr.Scheme == "http",
	}, nil
}