iclient/registry.go
Rama develop · réplica de lectura del repositorio original.
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
}