Skip to content
Permalink
Browse files Browse the repository at this point in the history
Merge pull request from GHSA-c38g-469g-cmgx
fix(*): Validate metadata semver and printable characters
  • Loading branch information
adamreese committed Feb 4, 2021
2 parents 46d80f6 + 657ce55 commit 6ce9ba6
Show file tree
Hide file tree
Showing 30 changed files with 394 additions and 226 deletions.
8 changes: 7 additions & 1 deletion cmd/helm/repo_update.go
Expand Up @@ -63,9 +63,15 @@ func newRepoUpdateCmd(out io.Writer) *cobra.Command {

func (o *repoUpdateOptions) run(out io.Writer) error {
f, err := repo.LoadFile(o.repoFile)
if isNotExist(err) || len(f.Repositories) == 0 {
switch {
case isNotExist(err):
return errNoRepositories
case err != nil:
return errors.Wrapf(err, "failed loading file: %s", o.repoFile)
case len(f.Repositories) == 0:
return errNoRepositories
}

var repos []*repo.ChartRepository
for _, cfg := range f.Repositories {
r, err := repo.NewChartRepository(cfg, getter.All(settings))
Expand Down
18 changes: 13 additions & 5 deletions cmd/helm/repo_update_test.go
Expand Up @@ -19,6 +19,7 @@ import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -53,20 +54,27 @@ func TestUpdateCmd(t *testing.T) {
}

func TestUpdateCustomCacheCmd(t *testing.T) {
var out bytes.Buffer
rootDir := ensure.TempDir(t)
cachePath := filepath.Join(rootDir, "updcustomcache")
_ = os.Mkdir(cachePath, os.ModePerm)
os.Mkdir(cachePath, os.ModePerm)
defer os.RemoveAll(cachePath)

ts, err := repotest.NewTempServerWithCleanup(t, "testdata/testserver/*.*")
if err != nil {
t.Fatal(err)
}
defer ts.Stop()

o := &repoUpdateOptions{
update: updateCharts,
repoFile: "testdata/repositories.yaml",
repoFile: filepath.Join(ts.Root(), "repositories.yaml"),
repoCache: cachePath,
}
if err := o.run(&out); err != nil {
b := ioutil.Discard
if err := o.run(b); err != nil {
t.Fatal(err)
}
if _, err := os.Stat(filepath.Join(cachePath, "charts-index.yaml")); err != nil {
if _, err := os.Stat(filepath.Join(cachePath, "test-index.yaml")); err != nil {
t.Fatalf("error finding created index file in custom cache: %v", err)
}
}
Expand Down
26 changes: 10 additions & 16 deletions cmd/helm/search_repo.go
Expand Up @@ -143,7 +143,7 @@ func (o *searchRepoOptions) setupSearchedVersion() {
}

func (o *searchRepoOptions) applyConstraint(res []*search.Result) ([]*search.Result, error) {
if len(o.version) == 0 {
if o.version == "" {
return res, nil
}

Expand All @@ -154,26 +154,19 @@ func (o *searchRepoOptions) applyConstraint(res []*search.Result) ([]*search.Res

data := res[:0]
foundNames := map[string]bool{}
appendSearchResults := func(res *search.Result) {
data = append(data, res)
if !o.versions {
foundNames[res.Name] = true // If user hasn't requested all versions, only show the latest that matches
}
}
for _, r := range res {
if _, found := foundNames[r.Name]; found {
// if not returning all versions and already have found a result,
// you're done!
if !o.versions && foundNames[r.Name] {
continue
}
v, err := semver.NewVersion(r.Chart.Version)

if err != nil {
// If the current version number check appears ErrSegmentStartsZero or ErrInvalidPrerelease error and not devel mode, ignore
if (err == semver.ErrSegmentStartsZero || err == semver.ErrInvalidPrerelease) && !o.devel {
continue
}
appendSearchResults(r)
} else if constraint.Check(v) {
appendSearchResults(r)
continue
}
if constraint.Check(v) {
data = append(data, r)
foundNames[r.Name] = true
}
}

Expand All @@ -194,6 +187,7 @@ func (o *searchRepoOptions) buildIndex() (*search.Index, error) {
ind, err := repo.LoadIndexFile(f)
if err != nil {
warning("Repo %q is corrupt or missing. Try 'helm repo update'.", n)
warning("%s", err)
continue
}

Expand Down
8 changes: 0 additions & 8 deletions cmd/helm/search_repo_test.go
Expand Up @@ -68,14 +68,6 @@ func TestSearchRepositoriesCmd(t *testing.T) {
name: "search for 'maria', expect valid json output",
cmd: "search repo maria --output json",
golden: "output/search-output-json.txt",
}, {
name: "search for 'maria', expect one match with semver begin with zero development version",
cmd: "search repo maria --devel",
golden: "output/search-semver-pre-zero-devel-release.txt",
}, {
name: "search for 'nginx-ingress', expect one match with invalid development pre version",
cmd: "search repo nginx-ingress --devel",
golden: "output/search-semver-pre-invalid-release.txt",
}, {
name: "search for 'alpine', expect valid yaml output",
cmd: "search repo alpine --output yaml",
Expand Down
34 changes: 4 additions & 30 deletions cmd/helm/testdata/helmhome/helm/repository/testing-index.yaml
Expand Up @@ -13,6 +13,7 @@ entries:
keywords: []
maintainers: []
icon: ""
apiVersion: v2
- name: alpine
url: https://charts.helm.sh/stable/alpine-0.2.0.tgz
checksum: 0e6661f193211d7a5206918d42f5c2a9470b737d
Expand All @@ -25,6 +26,7 @@ entries:
keywords: []
maintainers: []
icon: ""
apiVersion: v2
- name: alpine
url: https://charts.helm.sh/stable/alpine-0.3.0-rc.1.tgz
checksum: 0e6661f193211d7a5206918d42f5c2a9470b737d
Expand All @@ -37,6 +39,7 @@ entries:
keywords: []
maintainers: []
icon: ""
apiVersion: v2
mariadb:
- name: mariadb
url: https://charts.helm.sh/stable/mariadb-0.3.0.tgz
Expand All @@ -55,33 +58,4 @@ entries:
- name: Bitnami
email: containers@bitnami.com
icon: ""
- name: mariadb
url: https://charts.helm.sh/stable/mariadb-0.3.0-0565674.tgz
checksum: 65229f6de44a2be9f215d11dbff311673fc8ba56
home: https://mariadb.org
sources:
- https://github.com/bitnami/bitnami-docker-mariadb
version: 0.3.0-0565674
description: Chart for MariaDB
keywords:
- mariadb
- mysql
- database
- sql
maintainers:
- name: Bitnami
email: containers@bitnami.com
icon: ""
nginx-ingress:
- name: nginx-ingress
url: https://github.com/kubernetes/ingress-nginx/ingress-a.b.c.sdfsdf.tgz
checksum: 25229f6de44a2be9f215d11dbff31167ddc8ba56
home: https://github.com/kubernetes/ingress-nginx
sources:
- https://github.com/kubernetes/ingress-nginx
version: a.b.c.sdfsdf
description: Chart for nginx-ingress
keywords:
- ingress
- nginx
icon: ""
apiVersion: v2

This file was deleted.

This file was deleted.

Expand Up @@ -13,6 +13,7 @@ entries:
keywords: []
maintainers: []
icon: ""
apiVersion: v2
- name: alpine
urls:
- https://charts.helm.sh/stable/alpine-0.2.0.tgz
Expand All @@ -25,6 +26,7 @@ entries:
keywords: []
maintainers: []
icon: ""
apiVersion: v2
mariadb:
- name: mariadb
urls:
Expand All @@ -44,3 +46,4 @@ entries:
- name: Bitnami
email: containers@bitnami.com
icon: ""
apiVersion: v2
17 changes: 17 additions & 0 deletions pkg/chart/dependency.go
Expand Up @@ -49,6 +49,23 @@ type Dependency struct {
Alias string `json:"alias,omitempty"`
}

// Validate checks for common problems with the dependency datastructure in
// the chart. This check must be done at load time before the dependency's charts are
// loaded.
func (d *Dependency) Validate() error {
d.Name = sanitizeString(d.Name)
d.Version = sanitizeString(d.Version)
d.Repository = sanitizeString(d.Repository)
d.Condition = sanitizeString(d.Condition)
for i := range d.Tags {
d.Tags[i] = sanitizeString(d.Tags[i])
}
if d.Alias != "" && !aliasNameFormat.MatchString(d.Alias) {
return ValidationErrorf("dependency %q has disallowed characters in the alias", d.Name)
}
return nil
}

// Lock is a lock file for dependencies.
//
// It represents the state that the dependencies should be in.
Expand Down
44 changes: 44 additions & 0 deletions pkg/chart/dependency_test.go
@@ -0,0 +1,44 @@
/*
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 chart

import (
"testing"
)

func TestValidateDependency(t *testing.T) {
dep := &Dependency{
Name: "example",
}
for value, shouldFail := range map[string]bool{
"abcdefghijklmenopQRSTUVWXYZ-0123456780_": false,
"-okay": false,
"_okay": false,
"- bad": true,
" bad": true,
"bad\nvalue": true,
"bad ": true,
"bad$": true,
} {
dep.Alias = value
res := dep.Validate()
if res != nil && !shouldFail {
t.Errorf("Failed on case %q", dep.Alias)
} else if res == nil && shouldFail {
t.Errorf("Expected failure for %q", dep.Alias)
}
}
}

0 comments on commit 6ce9ba6

Please sign in to comment.