Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/release-3.14' into helm-v3.14.…
Browse files Browse the repository at this point in the history
…3-for-werf

Signed-off-by: Ilya Lesikov <[email protected]>
  • Loading branch information
ilya-lesikov committed Mar 22, 2024
2 parents 9f81f76 + f03cc04 commit 8274718
Show file tree
Hide file tree
Showing 21 changed files with 235 additions and 8 deletions.
24 changes: 22 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,22 @@ jobs:

- name: Build Helm Binaries
run: |
set -eu -o pipefail
make build-cross
make dist checksum VERSION="${{ github.ref_name }}"
- name: Set latest version
run: |
set -eu -o pipefail
mkdir -p _dist_versions
# Push the latest semver tag, excluding prerelease tags
git tag | sort -r --version-sort | grep '^v[0-9]' | grep -v '-' | head -n1 > _dist/helm-latest-version
LATEST_VERSION="$(git tag | sort -r --version-sort | grep '^v[0-9]' | grep -v '-' | head -n1)"
echo "LATEST_VERSION=${LATEST_VERSION}"
echo "${LATEST_VERSION}" > _dist_versions/helm-latest-version
echo "${LATEST_VERSION}" > _dist_versions/helm3-latest-version
- name: Upload Binaries
uses: bacongobbler/azure-blob-storage-upload@50f7d898b7697e864130ea04c303ca38b5751c50 # [email protected]
Expand All @@ -51,6 +60,17 @@ jobs:
connection_string: ${{ secrets.AZURE_STORAGE_CONNECTION_STRING }}
extra_args: '--pattern helm-*'

- name: Upload Version tag files
uses: bacongobbler/azure-blob-storage-upload@50f7d898b7697e864130ea04c303ca38b5751c50 # [email protected]
env:
AZURE_STORAGE_CONNECTION_STRING: "${{ secrets.AZURE_STORAGE_CONNECTION_STRING }}"
AZURE_STORAGE_CONTAINER_NAME: "${{ secrets.AZURE_STORAGE_CONTAINER_NAME }}"
with:
overwrite: 'true'
source_dir: _dist_versions
container_name: ${{ secrets.AZURE_STORAGE_CONTAINER_NAME }}
connection_string: ${{ secrets.AZURE_STORAGE_CONNECTION_STRING }}

canary-release:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
.vimrc
.vscode/
_dist/
_dist_versions/
bin/
vendor/
# Ignores charts pulled for dependency build tests
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ GOBIN = $(shell go env GOPATH)/bin
endif
GOX = $(GOBIN)/gox
GOIMPORTS = $(GOBIN)/goimports
ARCH = $(shell uname -p)
ARCH = $(shell go env GOARCH)

ACCEPTANCE_DIR:=../acceptance-testing
# To specify the subset of acceptance tests to run. '.' means all tests
Expand Down
6 changes: 5 additions & 1 deletion cmd/helm/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,11 @@ And in the following example, 'foo' is set to '{"key1":"value1","key2":"bar"}':
$ helm install --set-json='foo={"key1":"value1","key2":"value2"}' --set-json='foo.key2="bar"' myredis ./redis
To check the generated manifests of a release without installing the chart,
the '--debug' and '--dry-run' flags can be combined.
the --debug and --dry-run flags can be combined.
The --dry-run flag will output all generated chart manifests, including Secrets
which can contain sensitive values. Please carefully consider how and when this
flag is used.
If --verify is set, the chart MUST have a provenance file, and the provenance
file MUST pass all verification steps.
Expand Down
4 changes: 4 additions & 0 deletions cmd/helm/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ parameters, and existing values will be merged with any values set via '--values
or '--set' flags. Priority is given to new values.
$ helm upgrade --reuse-values --set foo=bar --set foo=newbar redis ./redis
The --dry-run flag will output all generated chart manifests, including Secrets
which can contain sensitive values. Please carefully consider how and when this
flag is used.
`

func NewUpgradeCmd(cfg *action.Configuration, out io.Writer, opts UpgradeCmdOptions) (*cobra.Command, *action.Upgrade) {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ toolchain go1.21.6

require (
github.com/BurntSushi/toml v1.3.2
github.com/DATA-DOG/go-sqlmock v1.5.0
github.com/DATA-DOG/go-sqlmock v1.5.2
github.com/Masterminds/semver/v3 v3.2.1
github.com/Masterminds/sprig/v3 v3.2.3
github.com/Masterminds/squirrel v1.5.4
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4=
github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
Expand Down
6 changes: 6 additions & 0 deletions pkg/chart/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ limitations under the License.
package chart

import (
"path/filepath"
"strings"
"unicode"

Expand Down Expand Up @@ -110,6 +111,11 @@ func (md *Metadata) Validate() error {
if md.Name == "" {
return ValidationError("chart.metadata.name is required")
}

if md.Name != filepath.Base(md.Name) {
return ValidationErrorf("chart.metadata.name %q is invalid", md.Name)
}

if md.Version == "" {
return ValidationError("chart.metadata.version is required")
}
Expand Down
5 changes: 5 additions & 0 deletions pkg/chart/metadata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ func TestValidate(t *testing.T) {
&Metadata{APIVersion: "v2", Version: "1.0"},
ValidationError("chart.metadata.name is required"),
},
{
"chart without name",
&Metadata{Name: "../../test", APIVersion: "v2", Version: "1.0"},
ValidationError("chart.metadata.name \"../../test\" is invalid"),
},
{
"chart without version",
&Metadata{Name: "test", APIVersion: "v2"},
Expand Down
8 changes: 8 additions & 0 deletions pkg/chartutil/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,11 @@ type ErrNoValue struct {
}

func (e ErrNoValue) Error() string { return fmt.Sprintf("%q is not a value", e.Key) }

type ErrInvalidChartName struct {
Name string
}

func (e ErrInvalidChartName) Error() string {
return fmt.Sprintf("%q is not a valid chart name", e.Name)
}
20 changes: 20 additions & 0 deletions pkg/chartutil/save.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ func SaveDir(c *chart.Chart, dest string) error {
// directory, writing the chart's contents to that subdirectory.
func SaveIntoDir(c *chart.Chart, dest string) error {
// Create the chart directory
err := validateName(c.Name())
if err != nil {
return err
}
outdir := dest
if fi, err := os.Stat(outdir); err == nil && !fi.IsDir() {
return errors.Errorf("file %s already exists and is not a directory", outdir)
Expand Down Expand Up @@ -166,6 +170,10 @@ func Save(c *chart.Chart, outDir string) (string, error) {
}

func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error {
err := validateName(c.Name())
if err != nil {
return err
}
base := filepath.Join(prefix, c.Name())

// Pull out the dependencies of a v1 Chart, since there's no way
Expand Down Expand Up @@ -259,3 +267,15 @@ func writeToTar(out *tar.Writer, name string, body []byte) error {
_, err := out.Write(body)
return err
}

// If the name has directory name has characters which would change the location
// they need to be removed.
func validateName(name string) error {
nname := filepath.Base(name)

if nname != name {
return ErrInvalidChartName{name}
}

return nil
}
29 changes: 29 additions & 0 deletions pkg/chartutil/save_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,24 @@ func TestSave(t *testing.T) {
}
})
}

c := &chart.Chart{
Metadata: &chart.Metadata{
APIVersion: chart.APIVersionV1,
Name: "../ahab",
Version: "1.2.3",
},
Lock: &chart.Lock{
Digest: "testdigest",
},
Files: []*chart.File{
{Name: "scheherazade/shahryar.txt", Data: []byte("1,001 Nights")},
},
}
_, err := Save(c, tmp)
if err == nil {
t.Fatal("Expected error saving chart with invalid name")
}
}

// Creates a copy with a different schema; does not modify anything.
Expand Down Expand Up @@ -232,4 +250,15 @@ func TestSaveDir(t *testing.T) {
if len(c2.Files) != 1 || c2.Files[0].Name != c.Files[0].Name {
t.Fatal("Files data did not match")
}

tmp2 := t.TempDir()
c.Metadata.Name = "../ahab"
pth := filepath.Join(tmp2, "tmpcharts")
if err := os.MkdirAll(filepath.Join(pth), 0755); err != nil {
t.Fatal(err)
}

if err := SaveDir(c, pth); err.Error() != "\"../ahab\" is not a valid chart name" {
t.Fatalf("Did not get expected error for chart named %q", c.Name())
}
}
26 changes: 26 additions & 0 deletions pkg/downloader/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,32 @@ func TestDownloadAll(t *testing.T) {
if _, err := os.Stat(filepath.Join(chartPath, "charts", "signtest-0.1.0.tgz")); os.IsNotExist(err) {
t.Error(err)
}

// A chart with a bad name like this cannot be loaded and saved. Handling in
// the loading and saving will return an error about the invalid name. In
// this case, the chart needs to be created directly.
badchartyaml := `apiVersion: v2
description: A Helm chart for Kubernetes
name: ../bad-local-subchart
version: 0.1.0`
if err := os.MkdirAll(filepath.Join(chartPath, "testdata", "bad-local-subchart"), 0755); err != nil {
t.Fatal(err)
}
err = os.WriteFile(filepath.Join(chartPath, "testdata", "bad-local-subchart", "Chart.yaml"), []byte(badchartyaml), 0644)
if err != nil {
t.Fatal(err)
}

badLocalDep := &chart.Dependency{
Name: "../bad-local-subchart",
Repository: "file://./testdata/bad-local-subchart",
Version: "0.1.0",
}

err = m.downloadAll([]*chart.Dependency{badLocalDep})
if err == nil {
t.Fatal("Expected error for bad dependency name")
}
}

func TestUpdateBeforeBuild(t *testing.T) {
Expand Down
4 changes: 4 additions & 0 deletions pkg/lint/rules/chartfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ func validateChartName(cf *chart.Metadata) error {
if cf.Name == "" {
return errors.New("name is required")
}
name := filepath.Base(cf.Name)
if name != cf.Name {
return fmt.Errorf("chart name %q is invalid", cf.Name)
}
return nil
}

Expand Down
8 changes: 8 additions & 0 deletions pkg/lint/rules/chartfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,19 @@ import (
)

const (
badCharNametDir = "testdata/badchartname"
badChartDir = "testdata/badchartfile"
anotherBadChartDir = "testdata/anotherbadchartfile"
)

var (
badChartNamePath = filepath.Join(badCharNametDir, "Chart.yaml")
badChartFilePath = filepath.Join(badChartDir, "Chart.yaml")
nonExistingChartFilePath = filepath.Join(os.TempDir(), "Chart.yaml")
)

var badChart, _ = chartutil.LoadChartfile(badChartFilePath)
var badChartName, _ = chartutil.LoadChartfile(badChartNamePath)

// Validation functions Test
func TestValidateChartYamlNotDirectory(t *testing.T) {
Expand Down Expand Up @@ -69,6 +72,11 @@ func TestValidateChartName(t *testing.T) {
if err == nil {
t.Errorf("validateChartName to return a linter error, got no error")
}

err = validateChartName(badChartName)
if err == nil {
t.Error("expected validateChartName to return a linter error for an invalid name, got no error")
}
}

func TestValidateChartVersion(t *testing.T) {
Expand Down
5 changes: 5 additions & 0 deletions pkg/lint/rules/testdata/badchartname/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
apiVersion: v2
description: A Helm chart for Kubernetes
version: 0.1.0
name: "../badchartname"
type: application
1 change: 1 addition & 0 deletions pkg/lint/rules/testdata/badchartname/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Default values for badchartfile.
4 changes: 4 additions & 0 deletions pkg/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ var validPluginName = regexp.MustCompile("^[A-Za-z0-9_-]+$")

// validatePluginData validates a plugin's YAML data.
func validatePluginData(plug *Plugin, filepath string) error {
// When metadata section missing, initialize with no data
if plug.Metadata == nil {
plug.Metadata = &Metadata{}
}
if !validPluginName.MatchString(plug.Metadata.Name) {
return fmt.Errorf("invalid plugin name at %q", filepath)
}
Expand Down
6 changes: 6 additions & 0 deletions pkg/plugin/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,11 @@ func TestSetupEnvWithSpace(t *testing.T) {
}

func TestValidatePluginData(t *testing.T) {
// A mock plugin missing any metadata.
mockMissingMeta := &Plugin{
Dir: "no-such-dir",
}

for i, item := range []struct {
pass bool
plug *Plugin
Expand All @@ -363,6 +368,7 @@ func TestValidatePluginData(t *testing.T) {
{false, mockPlugin("$foo -bar")}, // Test leading chars
{false, mockPlugin("foo -bar ")}, // Test trailing chars
{false, mockPlugin("foo\nbar")}, // Test newline
{false, mockMissingMeta}, // Test if the metadata section missing
} {
err := validatePluginData(item.plug, fmt.Sprintf("test-%d", i))
if item.pass && err != nil {
Expand Down
26 changes: 25 additions & 1 deletion pkg/repo/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,10 +359,14 @@ func loadIndex(data []byte, source string) (*IndexFile, error) {
log.Printf("skipping loading invalid entry for chart %q from %s: empty entry", name, source)
continue
}
// When metadata section missing, initialize with no data
if cvs[idx].Metadata == nil {
cvs[idx].Metadata = &chart.Metadata{}
}
if cvs[idx].APIVersion == "" {
cvs[idx].APIVersion = chart.APIVersionV1
}
if err := cvs[idx].Validate(); err != nil {
if err := cvs[idx].Validate(); ignoreSkippableChartValidationError(err) != nil {
log.Printf("skipping loading invalid entry for chart %q %q from %s: %s", name, cvs[idx].Version, source, err)
cvs = append(cvs[:idx], cvs[idx+1:]...)
}
Expand All @@ -388,3 +392,23 @@ func jsonOrYamlUnmarshal(b []byte, i interface{}) error {
}
return yaml.UnmarshalStrict(b, i)
}

// ignoreSkippableChartValidationError inspect the given error and returns nil if
// the error isn't important for index loading
//
// In particular, charts may introduce validations that don't impact repository indexes
// And repository indexes may be generated by older/non-complient software, which doesn't
// conform to all validations.
func ignoreSkippableChartValidationError(err error) error {
verr, ok := err.(chart.ValidationError)
if !ok {
return err
}

// https://github.com/helm/helm/issues/12748 (JFrog repository strips alias field)
if strings.HasPrefix(verr.Error(), "validation: more than one dependency with name or alias") {
return nil
}

return err
}
Loading

0 comments on commit 8274718

Please sign in to comment.