Add --version cmd flag to push cmd to validate chart version

Signed-off-by: Benoit Tigeot <benoit.tigeot@lifen.fr>
pull/31347/head
Benoit Tigeot 4 months ago
parent b6c719dfec
commit 7f5bb43bef
No known key found for this signature in database
GPG Key ID: 8E6D4FC8AEBDA62C

@ -38,6 +38,7 @@ type Push struct {
insecureSkipTLSverify bool
plainHTTP bool
out io.Writer
expectedVersion string
}
// PushOpt is a type of function that sets options for a push action.
@ -80,6 +81,13 @@ func WithPushOptWriter(out io.Writer) PushOpt {
}
}
// WithExpectedVersion configures an expected chart version that must match Chart.yaml.
func WithExpectedVersion(version string) PushOpt {
return func(p *Push) {
p.expectedVersion = version
}
}
// NewPushWithOpts creates a new push, with configuration options.
func NewPushWithOpts(opts ...PushOpt) *Push {
p := &Push{}
@ -103,6 +111,10 @@ func (p *Push) Run(chartRef string, remote string) (string, error) {
},
}
if p.expectedVersion != "" {
c.Options = append(c.Options, pusher.WithExpectedVersion(p.expectedVersion))
}
if registry.IsOCI(remote) {
// Don't use the default registry client if tls options are set.
c.Options = append(c.Options, pusher.WithRegistryClient(p.cfg.RegistryClient))

@ -30,8 +30,16 @@ import (
const pushDesc = `
Upload a chart to a registry.
If the chart has an associated provenance file,
it will also be uploaded.
If the chart has an associated provenance file, it will also be uploaded.
You can optionally specify --version or oci://...:version as a safety check. When provided,
it must match the version from Chart.yaml; otherwise the command will fail.
Examples:
$ helm push mychart-0.1.0.tgz oci://my-registry.io/helm/charts
$ helm push mychart-0.1.0.tgz oci://my-registry.io/helm/charts --version 0.1.0
$ helm push mychart-0.1.0.tgz oci://my-registry.io/helm/charts:0.1.0
`
type registryPushOptions struct {
@ -42,6 +50,7 @@ type registryPushOptions struct {
plainHTTP bool
password string
username string
version string
}
func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
@ -84,6 +93,7 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
action.WithTLSClientConfig(o.certFile, o.keyFile, o.caFile),
action.WithInsecureSkipTLSVerify(o.insecureSkipTLSverify),
action.WithPlainHTTP(o.plainHTTP),
action.WithExpectedVersion(o.version),
action.WithPushOptWriter(out))
client.Settings = settings
output, err := client.Run(chartRef, remote)
@ -103,6 +113,7 @@ func newPushCmd(cfg *action.Configuration, out io.Writer) *cobra.Command {
f.BoolVar(&o.plainHTTP, "plain-http", false, "use insecure HTTP connections for the chart upload")
f.StringVar(&o.username, "username", "", "chart repository username where to locate the requested chart")
f.StringVar(&o.password, "password", "", "chart repository password where to locate the requested chart")
f.StringVar(&o.version, "version", "", "specify the exact chart version to push. If this is not specified, the version from Chart.yaml is used")
return cmd
}

@ -59,6 +59,11 @@ func (pusher *OCIPusher) push(chartRef, href string) error {
return err
}
// If an expected version is specified via --version, enforce it matches Chart.yaml
if pusher.opts.expectedVersion != "" && pusher.opts.expectedVersion != meta.Metadata.Version {
return fmt.Errorf("specified --version %q does not match chart version %q", pusher.opts.expectedVersion, meta.Metadata.Version)
}
ref, err := registry.BuildPushRef(href, meta.Metadata.Name, meta.Metadata.Version)
if err != nil {
return err

@ -455,3 +455,30 @@ func TestOCIPusher_Push_MultipleOptions(t *testing.T) {
t.Error("Expected insecureSkipTLSverify option to be applied")
}
}
func TestOCIPusher_Push_ExpectedVersionMismatch(t *testing.T) {
chartPath := "../../pkg/cmd/testdata/testcharts/compressedchart-0.1.0.tgz"
// Skip test if chart file doesn't exist
if _, err := os.Stat(chartPath); err != nil {
t.Skipf("Test chart %s not found, skipping test", chartPath)
}
p, err := NewOCIPusher()
if err != nil {
t.Fatal(err)
}
// Provide an expected version that does not match the chart's version
err = p.Push(chartPath, "oci://localhost:5000/test",
WithExpectedVersion("0.2.0"),
)
if err == nil {
t.Fatal("Expected error when --version does not match chart version")
}
if !strings.Contains(err.Error(), "specified --version") {
t.Errorf("Expected error to mention version mismatch check, got %q", err.Error())
}
}

@ -34,6 +34,7 @@ type options struct {
caFile string
insecureSkipTLSverify bool
plainHTTP bool
expectedVersion string
}
// Option allows specifying various settings configurable by the user for overriding the defaults
@ -69,6 +70,14 @@ func WithPlainHTTP(plainHTTP bool) Option {
}
}
// WithExpectedVersion sets a specific chart version to check against the chart metadata.
// If the chart's version differs, the push will fail.
func WithExpectedVersion(version string) Option {
return func(opts *options) {
opts.expectedVersion = version
}
}
// Pusher is an interface to support upload to the specified URL.
type Pusher interface {
// Push file content by url string

Loading…
Cancel
Save