diff --git a/pkg/chart/v2/util/chartfile.go b/pkg/chart/v2/util/chartfile.go index 87323c201..b48687d55 100644 --- a/pkg/chart/v2/util/chartfile.go +++ b/pkg/chart/v2/util/chartfile.go @@ -37,6 +37,17 @@ func LoadChartfile(filename string) (*chart.Metadata, error) { return y, err } +// StrictLoadChartFile loads a Chart.yaml into a *chart.Metadata using a strict unmarshaling +func StrictLoadChartfile(filename string) (*chart.Metadata, error) { + b, err := os.ReadFile(filename) + if err != nil { + return nil, err + } + y := new(chart.Metadata) + err = yaml.UnmarshalStrict(b, y) + return y, err +} + // SaveChartfile saves the given metadata as a Chart.yaml file at the given path. // // 'filename' should be the complete path and filename ('foo/Chart.yaml') diff --git a/pkg/lint/lint_test.go b/pkg/lint/lint_test.go index 067d140f6..888d3dfe6 100644 --- a/pkg/lint/lint_test.go +++ b/pkg/lint/lint_test.go @@ -35,6 +35,7 @@ const badYamlFileDir = "rules/testdata/albatross" const goodChartDir = "rules/testdata/goodone" const subChartValuesDir = "rules/testdata/withsubchart" const malformedTemplate = "rules/testdata/malformed-template" +const invalidChartFileDir = "rules/testdata/invalidchartfile" func TestBadChart(t *testing.T) { m := RunAll(badChartDir, values, namespace).Messages @@ -90,6 +91,16 @@ func TestInvalidYaml(t *testing.T) { } } +func TestInvalidChartYaml(t *testing.T) { + m := RunAll(invalidChartFileDir, values, namespace).Messages + if len(m) != 1 { + t.Fatalf("All didn't fail with expected errors, got %#v", m) + } + if !strings.Contains(m[0].Err.Error(), "failed to strictly parse chart metadata file") { + t.Errorf("All didn't have the error for duplicate YAML keys") + } +} + func TestBadValues(t *testing.T) { m := RunAll(badValuesFileDir, values, namespace).Messages if len(m) < 1 { diff --git a/pkg/lint/rules/chartfile.go b/pkg/lint/rules/chartfile.go index 598557a97..13ae77222 100644 --- a/pkg/lint/rules/chartfile.go +++ b/pkg/lint/rules/chartfile.go @@ -46,6 +46,9 @@ func Chartfile(linter *support.Linter) { return } + _, err = chartutil.StrictLoadChartfile(chartPath) + linter.RunLinterRule(support.WarningSev, chartFileName, validateChartYamlStrictFormat(err)) + // type check for Chart.yaml . ignoring error as any parse // errors would already be caught in the above load function chartFileForTypeCheck, _ := loadChartFileForTypeCheck(chartPath) @@ -102,6 +105,13 @@ func validateChartYamlFormat(chartFileError error) error { return nil } +func validateChartYamlStrictFormat(chartFileError error) error { + if chartFileError != nil { + return errors.Errorf("failed to strictly parse chart metadata file\n\t%s", chartFileError.Error()) + } + return nil +} + func validateChartName(cf *chart.Metadata) error { if cf.Name == "" { return errors.New("name is required") diff --git a/pkg/lint/rules/testdata/invalidchartfile/Chart.yaml b/pkg/lint/rules/testdata/invalidchartfile/Chart.yaml new file mode 100644 index 000000000..0fd58d1d4 --- /dev/null +++ b/pkg/lint/rules/testdata/invalidchartfile/Chart.yaml @@ -0,0 +1,6 @@ +name: some-chart +apiVersion: v2 +apiVersion: v1 +description: A Helm chart for Kubernetes +version: 1.3.0 +icon: http://example.com diff --git a/pkg/lint/rules/testdata/invalidchartfile/values.yaml b/pkg/lint/rules/testdata/invalidchartfile/values.yaml new file mode 100644 index 000000000..e69de29bb