refactor(oci): maintain backward compatibility

This restores the `ClientOptResolver` function which now panics on
invocation and previous signature of the `LoginOption` function.

Signed-off-by: Zoran Regvart <zoran@regvart.com>
pull/12310/head
Zoran Regvart 11 months ago
parent 156e562f38
commit e061593d16
No known key found for this signature in database
GPG Key ID: 6D9197EFE5AB7D75

@ -11,6 +11,7 @@ require (
github.com/Masterminds/squirrel v1.5.4 github.com/Masterminds/squirrel v1.5.4
github.com/Masterminds/vcs v1.13.3 github.com/Masterminds/vcs v1.13.3
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2
github.com/containerd/containerd v1.7.23
github.com/cyphar/filepath-securejoin v0.3.4 github.com/cyphar/filepath-securejoin v0.3.4
github.com/distribution/distribution/v3 v3.0.0-rc.1 github.com/distribution/distribution/v3 v3.0.0-rc.1
github.com/evanphx/json-patch v5.9.0+incompatible github.com/evanphx/json-patch v5.9.0+incompatible
@ -58,6 +59,9 @@ require (
github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chai2010/gettext-go v1.0.2 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect
github.com/containerd/errdefs v0.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/platforms v0.2.1 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect

@ -55,6 +55,14 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/containerd/containerd v1.7.23 h1:H2CClyUkmpKAGlhQp95g2WXHfLYc7whAuvZGBNYOOwQ=
github.com/containerd/containerd v1.7.23/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw=
github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4=
github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=

@ -30,6 +30,7 @@ import (
"sync" "sync"
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
"github.com/containerd/containerd/remotes"
"github.com/opencontainers/image-spec/specs-go" "github.com/opencontainers/image-spec/specs-go"
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -54,6 +55,8 @@ storing semantic versions, Helm adopts the convention of changing plus (+) to
an underscore (_) in chart version tags when pushing to a registry and back to an underscore (_) in chart version tags when pushing to a registry and back to
a plus (+) when pulling from a registry.` a plus (+) when pulling from a registry.`
var errDeprecatedRemote = errors.New("providing github.com/containerd/containerd/remotes.Resolver via ClientOptResolver is no longer suported")
type ( type (
// Client works with OCI-compliant registries // Client works with OCI-compliant registries
Client struct { Client struct {
@ -66,6 +69,7 @@ type (
credentialsStore credentials.Store credentialsStore credentials.Store
httpClient *http.Client httpClient *http.Client
plainHTTP bool plainHTTP bool
err error // pass any errors from the ClientOption or LoginOption functions
} }
// ClientOption allows specifying various settings configurable by the user for overriding the defaults // ClientOption allows specifying various settings configurable by the user for overriding the defaults
@ -80,6 +84,9 @@ func NewClient(options ...ClientOption) (*Client, error) {
} }
for _, option := range options { for _, option := range options {
option(client) option(client)
if client.err != nil {
return nil, client.popError()
}
} }
if client.credentialsFile == "" { if client.credentialsFile == "" {
client.credentialsFile = helmpath.ConfigPath(CredentialsFileBasename) client.credentialsFile = helmpath.ConfigPath(CredentialsFileBasename)
@ -184,16 +191,29 @@ func ClientOptPlainHTTP() ClientOption {
} }
} }
func ClientOptResolver(_ remotes.Resolver) ClientOption {
return func(c *Client) {
c.err = errDeprecatedRemote
}
}
type ( type (
// LoginOption allows specifying various settings on login // LoginOption allows specifying various settings on login
LoginOption func(host string, client *Client) error LoginOption func(*loginOperation)
loginOperation struct {
host string
client *Client
}
) )
// Login logs into a registry // Login logs into a registry
func (c *Client) Login(host string, options ...LoginOption) error { func (c *Client) Login(host string, options ...LoginOption) error {
for _, option := range options { for _, option := range options {
if err := option(host, c); err != nil { o := loginOperation{host, c}
return fmt.Errorf("configuring login option: %w", err) option(&o)
if c.err != nil {
return c.popError()
} }
} }
@ -224,19 +244,23 @@ func (c *Client) Login(host string, options ...LoginOption) error {
return nil return nil
} }
func (c *Client) popError() error {
err := c.err
c.err = nil
return err
}
// LoginOptBasicAuth returns a function that sets the username/password settings on login // LoginOptBasicAuth returns a function that sets the username/password settings on login
func LoginOptBasicAuth(username string, password string) LoginOption { func LoginOptBasicAuth(username string, password string) LoginOption {
return func(host string, client *Client) error { return func(o *loginOperation) {
client.authorizer.Credential = auth.StaticCredential(host, auth.Credential{Username: username, Password: password}) o.client.authorizer.Credential = auth.StaticCredential(o.host, auth.Credential{Username: username, Password: password})
return nil
} }
} }
// LoginOptBasicAuth returns a function that allows plaintext (HTTP) login // LoginOptBasicAuth returns a function that allows plaintext (HTTP) login
func LoginOptPlainText(isPlainText bool) LoginOption { func LoginOptPlainText(isPlainText bool) LoginOption {
return func(host string, client *Client) error { return func(o *loginOperation) {
client.plainHTTP = isPlainText o.client.plainHTTP = isPlainText
return nil
} }
} }
@ -268,33 +292,35 @@ func ensureTLSConfig(client *auth.Client) (*tls.Config, error) {
// LoginOptInsecure returns a function that sets the insecure setting on login // LoginOptInsecure returns a function that sets the insecure setting on login
func LoginOptInsecure(insecure bool) LoginOption { func LoginOptInsecure(insecure bool) LoginOption {
return func(_ string, client *Client) error { return func(o *loginOperation) {
tlsConfig, err := ensureTLSConfig(client.authorizer) tlsConfig, err := ensureTLSConfig(o.client.authorizer)
if err != nil { if err != nil {
return err o.client.err = err
return
} }
tlsConfig.InsecureSkipVerify = insecure tlsConfig.InsecureSkipVerify = insecure
return nil
} }
} }
// LoginOptTLSClientConfig returns a function that sets the TLS settings on login. // LoginOptTLSClientConfig returns a function that sets the TLS settings on login.
func LoginOptTLSClientConfig(certFile, keyFile, caFile string) LoginOption { func LoginOptTLSClientConfig(certFile, keyFile, caFile string) LoginOption {
return func(_ string, client *Client) error { return func(o *loginOperation) {
if (certFile == "" || keyFile == "") && caFile == "" { if (certFile == "" || keyFile == "") && caFile == "" {
return nil return
} }
tlsConfig, err := ensureTLSConfig(client.authorizer) tlsConfig, err := ensureTLSConfig(o.client.authorizer)
if err != nil { if err != nil {
return err o.client.err = err
return
} }
if certFile != "" && keyFile != "" { if certFile != "" && keyFile != "" {
authCert, err := tls.LoadX509KeyPair(certFile, keyFile) authCert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil { if err != nil {
return err o.client.err = err
return
} }
tlsConfig.Certificates = []tls.Certificate{authCert} tlsConfig.Certificates = []tls.Certificate{authCert}
} }
@ -303,15 +329,15 @@ func LoginOptTLSClientConfig(certFile, keyFile, caFile string) LoginOption {
certPool := x509.NewCertPool() certPool := x509.NewCertPool()
ca, err := os.ReadFile(caFile) ca, err := os.ReadFile(caFile)
if err != nil { if err != nil {
return err o.client.err = err
return
} }
if !certPool.AppendCertsFromPEM(ca) { if !certPool.AppendCertsFromPEM(ca) {
return fmt.Errorf("unable to parse CA file: %q", caFile) o.client.err = fmt.Errorf("unable to parse CA file: %q", caFile)
return
} }
tlsConfig.RootCAs = certPool tlsConfig.RootCAs = certPool
} }
return nil
} }
} }

@ -0,0 +1,32 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package registry
import (
"testing"
"github.com/containerd/containerd/remotes"
)
func TestNewClientResolverNotSupported(t *testing.T) {
var r remotes.Resolver
client, err := NewClient(ClientOptResolver(r))
if client != nil || err != errDeprecatedRemote {
t.Errorf("expected nil, %v, got: %v, %v", errDeprecatedRemote, client, err)
}
}
Loading…
Cancel
Save