diff --git a/internal/chart/v3/lint/rules/template.go b/internal/chart/v3/lint/rules/template.go index 35e4940ab..22f2e39bf 100644 --- a/internal/chart/v3/lint/rules/template.go +++ b/internal/chart/v3/lint/rules/template.go @@ -97,7 +97,7 @@ func TemplatesWithSkipSchemaValidation(linter *support.Linter, values map[string return } - valuesToRender, err := util.ToRenderValuesWithSchemaValidation(chart, cvals, options, caps, skipSchemaValidation) + valuesToRender, err := util.ToRenderValuesWithSchemaValidationAndPath(chart, cvals, options, caps, skipSchemaValidation, linter.ChartDir) if err != nil { linter.RunLinterRule(support.ErrorSev, fpath, err) return diff --git a/internal/chart/v3/lint/rules/values.go b/internal/chart/v3/lint/rules/values.go index 43eec40c2..2083a9bbd 100644 --- a/internal/chart/v3/lint/rules/values.go +++ b/internal/chart/v3/lint/rules/values.go @@ -41,7 +41,7 @@ func ValuesWithOverrides(linter *support.Linter, valueOverrides map[string]any, return } - linter.RunLinterRule(support.ErrorSev, file, validateValuesFile(vf, valueOverrides, skipSchemaValidation)) + linter.RunLinterRule(support.ErrorSev, file, validateValuesFile(linter.ChartDir, valueOverrides, skipSchemaValidation)) } func validateValuesFileExistence(valuesPath string) error { @@ -52,7 +52,10 @@ func validateValuesFileExistence(valuesPath string) error { return nil } -func validateValuesFile(valuesPath string, overrides map[string]any, skipSchemaValidation bool) error { +func validateValuesFile(chartDir string, overrides map[string]any, skipSchemaValidation bool) error { + valuesPath := filepath.Join(chartDir, "values.yaml") + schemaPath := filepath.Join(chartDir, "values.schema.json") + values, err := common.ReadValuesFile(valuesPath) if err != nil { return fmt.Errorf("unable to parse YAML: %w", err) @@ -66,8 +69,6 @@ func validateValuesFile(valuesPath string, overrides map[string]any, skipSchemaV coalescedValues := util.CoalesceTables(make(map[string]any, len(overrides)), overrides) coalescedValues = util.CoalesceTables(coalescedValues, values) - ext := filepath.Ext(valuesPath) - schemaPath := valuesPath[:len(valuesPath)-len(ext)] + ".schema.json" schema, err := os.ReadFile(schemaPath) if len(schema) == 0 { return nil @@ -75,9 +76,9 @@ func validateValuesFile(valuesPath string, overrides map[string]any, skipSchemaV if err != nil { return err } - baseDir := filepath.Dir(schemaPath) + if !skipSchemaValidation { - return util.ValidateAgainstSingleSchema(coalescedValues, schema, baseDir) + return util.ValidateAgainstSingleSchemaWithPath(coalescedValues, schema, schemaPath) } return nil diff --git a/internal/chart/v3/lint/rules/values_test.go b/internal/chart/v3/lint/rules/values_test.go index afc544ebd..b40c7b7de 100644 --- a/internal/chart/v3/lint/rules/values_test.go +++ b/internal/chart/v3/lint/rules/values_test.go @@ -66,8 +66,7 @@ func TestValidateValuesFileWellFormed(t *testing.T) { not:well[]{}formed ` tmpdir := ensure.TempFile(t, "values.yaml", []byte(badYaml)) - valfile := filepath.Join(tmpdir, "values.yaml") - if err := validateValuesFile(valfile, map[string]any{}, false); err == nil { + if err := validateValuesFile(tmpdir, map[string]any{}, false); err == nil { t.Fatal("expected values file to fail parsing") } } @@ -77,8 +76,7 @@ func TestValidateValuesFileSchema(t *testing.T) { tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml)) createTestingSchema(t, tmpdir) - valfile := filepath.Join(tmpdir, "values.yaml") - if err := validateValuesFile(valfile, map[string]any{}, false); err != nil { + if err := validateValuesFile(tmpdir, map[string]any{}, false); err != nil { t.Fatalf("Failed validation with %s", err) } } @@ -89,9 +87,7 @@ func TestValidateValuesFileSchemaFailure(t *testing.T) { tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml)) createTestingSchema(t, tmpdir) - valfile := filepath.Join(tmpdir, "values.yaml") - - err := validateValuesFile(valfile, map[string]any{}, false) + err := validateValuesFile(tmpdir, map[string]any{}, false) if err == nil { t.Fatal("expected values file to fail parsing") } @@ -105,9 +101,7 @@ func TestValidateValuesFileSchemaFailureButWithSkipSchemaValidation(t *testing.T tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml)) createTestingSchema(t, tmpdir) - valfile := filepath.Join(tmpdir, "values.yaml") - - err := validateValuesFile(valfile, map[string]any{}, true) + err := validateValuesFile(tmpdir, map[string]any{}, true) if err != nil { t.Fatal("expected values file to pass parsing because of skipSchemaValidation") } @@ -121,8 +115,7 @@ func TestValidateValuesFileSchemaOverrides(t *testing.T) { tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml)) createTestingSchema(t, tmpdir) - valfile := filepath.Join(tmpdir, "values.yaml") - if err := validateValuesFile(valfile, overrides, false); err != nil { + if err := validateValuesFile(tmpdir, overrides, false); err != nil { t.Fatalf("Failed validation with %s", err) } } @@ -157,9 +150,7 @@ func TestValidateValuesFile(t *testing.T) { tmpdir := ensure.TempFile(t, "values.yaml", []byte(tt.yaml)) createTestingSchema(t, tmpdir) - valfile := filepath.Join(tmpdir, "values.yaml") - - err := validateValuesFile(valfile, tt.overrides, false) + err := validateValuesFile(tmpdir, tt.overrides, false) switch { case err != nil && tt.errorMessage == "": diff --git a/pkg/action/install.go b/pkg/action/install.go index 2f747a789..1e138b3c7 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -127,6 +127,9 @@ type Install struct { // Used by helm template to add the release as part of OutputDir path // OutputDir/ UseReleaseName bool + // ChartDir is the local directory path of the chart, used for resolving + // relative $ref in JSON schemas. Empty for remote charts. + ChartDir string // TakeOwnership will ignore the check for helm annotations and take ownership of the resources. TakeOwnership bool PostRenderer postrenderer.PostRenderer @@ -358,7 +361,7 @@ func (i *Install) RunWithContext(ctx context.Context, ch ci.Charter, vals map[st IsInstall: !isUpgrade, IsUpgrade: isUpgrade, } - valuesToRender, err := util.ToRenderValuesWithSchemaValidation(chrt, vals, options, caps, i.SkipSchemaValidation) + valuesToRender, err := util.ToRenderValuesWithSchemaValidationAndPath(chrt, vals, options, caps, i.SkipSchemaValidation, i.ChartDir) if err != nil { return nil, err } diff --git a/pkg/action/lint_test.go b/pkg/action/lint_test.go index 6ee1e07fa..63b2f51ae 100644 --- a/pkg/action/lint_test.go +++ b/pkg/action/lint_test.go @@ -71,6 +71,10 @@ func TestLintChart(t *testing.T) { name: "chart-with-schema", chartPath: "testdata/charts/chart-with-schema", }, + { + name: "chart-with-schema-ref", + chartPath: "testdata/charts/chart-with-schema-ref", + }, { name: "chart-with-schema-negative", chartPath: "testdata/charts/chart-with-schema-negative", diff --git a/pkg/action/testdata/charts/chart-with-schema-ref/Chart.yaml b/pkg/action/testdata/charts/chart-with-schema-ref/Chart.yaml new file mode 100644 index 000000000..c344a04d9 --- /dev/null +++ b/pkg/action/testdata/charts/chart-with-schema-ref/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: chart-with-schema-ref +version: 0.1.0 diff --git a/pkg/action/testdata/charts/chart-with-schema-ref/name.schema.json b/pkg/action/testdata/charts/chart-with-schema-ref/name.schema.json new file mode 100644 index 000000000..290e9cca5 --- /dev/null +++ b/pkg/action/testdata/charts/chart-with-schema-ref/name.schema.json @@ -0,0 +1,4 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "string" +} diff --git a/pkg/action/testdata/charts/chart-with-schema-ref/values.schema.json b/pkg/action/testdata/charts/chart-with-schema-ref/values.schema.json new file mode 100644 index 000000000..e253c4c7e --- /dev/null +++ b/pkg/action/testdata/charts/chart-with-schema-ref/values.schema.json @@ -0,0 +1,7 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "name": { "$ref": "name.schema.json" } + } +} diff --git a/pkg/action/testdata/charts/chart-with-schema-ref/values.yaml b/pkg/action/testdata/charts/chart-with-schema-ref/values.yaml new file mode 100644 index 000000000..0b9fc7e3a --- /dev/null +++ b/pkg/action/testdata/charts/chart-with-schema-ref/values.yaml @@ -0,0 +1 @@ +name: "test" diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go index 4c5a5b55e..7376c34eb 100644 --- a/pkg/action/upgrade.go +++ b/pkg/action/upgrade.go @@ -113,6 +113,9 @@ type Upgrade struct { HideNotes bool // SkipSchemaValidation determines if JSON schema validation is disabled. SkipSchemaValidation bool + // ChartDir is the local directory path of the chart, used for resolving + // relative $ref in JSON schemas. Empty for remote charts. + ChartDir string // Description is the description of this operation Description string Labels map[string]string @@ -291,7 +294,7 @@ func (u *Upgrade) prepareUpgrade(name string, chart *chartv2.Chart, vals map[str if err != nil { return nil, nil, false, err } - valuesToRender, err := util.ToRenderValuesWithSchemaValidation(chart, vals, options, caps, u.SkipSchemaValidation) + valuesToRender, err := util.ToRenderValuesWithSchemaValidationAndPath(chart, vals, options, caps, u.SkipSchemaValidation, u.ChartDir) if err != nil { return nil, nil, false, err } diff --git a/pkg/chart/common/util/jsonschema.go b/pkg/chart/common/util/jsonschema.go index 8a37e103e..e34691f7d 100644 --- a/pkg/chart/common/util/jsonschema.go +++ b/pkg/chart/common/util/jsonschema.go @@ -75,14 +75,31 @@ func newHTTPURLLoader() *HTTPURLLoader { // ValidateAgainstSchema checks that values does not violate the structure laid out in schema func ValidateAgainstSchema(ch chart.Charter, values map[string]any) error { + return ValidateAgainstSchemaWithPath(ch, values, "") +} + +func ValidateAgainstSchemaWithPath(ch chart.Charter, values map[string]any, chartDir string) error { chrt, err := chart.NewAccessor(ch) if err != nil { return err } + + var absChartPath string + if chartDir != "" { + absChartPath, err = filepath.Abs(chartDir) + } else { + absChartPath, err = filepath.Abs(chrt.ChartFullPath()) + } + if err != nil { + return err + } + var sb strings.Builder if chrt.Schema() != nil { slog.Debug("chart name", "chart-name", chrt.Name()) - err := ValidateAgainstSingleSchema(values, chrt.Schema(), chrt.ChartFullPath()) + + schemaPath := filepath.Join(absChartPath, "values.schema.json") + err = ValidateAgainstSingleSchemaWithPath(values, chrt.Schema(), schemaPath) if err != nil { fmt.Fprintf(&sb, "%s:\n", chrt.Name()) sb.WriteString(err.Error()) @@ -109,7 +126,8 @@ func ValidateAgainstSchema(ch chart.Charter, values map[string]any) error { continue } - if err := ValidateAgainstSchema(subchart, subchartValues); err != nil { + subchartPath := filepath.Join(absChartPath, "charts", sub.Name()) + if err := ValidateAgainstSchemaWithPath(subchart, subchartValues, subchartPath); err != nil { sb.WriteString(err.Error()) } } @@ -122,7 +140,13 @@ func ValidateAgainstSchema(ch chart.Charter, values map[string]any) error { } // ValidateAgainstSingleSchema checks that values does not violate the structure laid out in this schema -func ValidateAgainstSingleSchema(values common.Values, schemaJSON []byte, absBaseDir string) (reterr error) { +func ValidateAgainstSingleSchema(values common.Values, schemaJSON []byte) (reterr error) { + return ValidateAgainstSingleSchemaWithPath(values, schemaJSON, "/values.schema.json") +} + +// ValidateAgainstSingleSchemaWithPath checks that values does not violate the structure laid out in this schema. +// schemaPath is the absolute path to the schema file, used to resolve relative $ref references. +func ValidateAgainstSingleSchemaWithPath(values common.Values, schemaJSON []byte, schemaPath string) (reterr error) { defer func() { if r := recover(); r != nil { reterr = fmt.Errorf("unable to validate schema: %s", r) @@ -147,13 +171,14 @@ func ValidateAgainstSingleSchema(values common.Values, schemaJSON []byte, absBas compiler := jsonschema.NewCompiler() compiler.UseLoader(loader) - base := "file://" + filepath.ToSlash(absBaseDir) + "/values.schema.json" - err = compiler.AddResource(base, schema) + + schemaURL := fmt.Sprintf("file://%s", schemaPath) + err = compiler.AddResource(schemaURL, schema) if err != nil { return err } - validator, err := compiler.Compile(base) + validator, err := compiler.Compile(schemaURL) if err != nil { return err } @@ -211,11 +236,7 @@ func (e JSONSchemaValidationError) Error() string { // This string prefixes all of our error details. Further up the stack of helm error message // building more detail is provided to users. This is removed. - if strings.HasPrefix(errStr, "jsonschema validation failed with ") { - if idx := strings.Index(errStr, "#'\n"); idx != -1 { - errStr = errStr[idx+3:] - } - } + errStr = strings.TrimPrefix(errStr, "jsonschema validation failed with 'file:///values.schema.json#'\n") // The extra new line is needed for when there are sub-charts. return errStr + "\n" diff --git a/pkg/chart/common/util/jsonschema_test.go b/pkg/chart/common/util/jsonschema_test.go index 06c518d73..33e82cf5f 100644 --- a/pkg/chart/common/util/jsonschema_test.go +++ b/pkg/chart/common/util/jsonschema_test.go @@ -38,7 +38,7 @@ func TestValidateAgainstSingleSchema(t *testing.T) { t.Fatalf("Error reading YAML file: %s", err) } - if err := ValidateAgainstSingleSchema(values, schema, ""); err != nil { + if err := ValidateAgainstSingleSchema(values, schema); err != nil { t.Errorf("Error validating Values against Schema: %s", err) } } @@ -54,7 +54,7 @@ func TestValidateAgainstInvalidSingleSchema(t *testing.T) { } var errString string - if err := ValidateAgainstSingleSchema(values, schema, ""); err == nil { + if err := ValidateAgainstSingleSchema(values, schema); err == nil { t.Fatalf("Expected an error, but got nil") } else { errString = err.Error() @@ -78,7 +78,7 @@ func TestValidateAgainstSingleSchemaNegative(t *testing.T) { } var errString string - if err := ValidateAgainstSingleSchema(values, schema, ""); err == nil { + if err := ValidateAgainstSingleSchema(values, schema); err == nil { t.Fatalf("Expected an error, but got nil") } else { errString = err.Error() @@ -264,19 +264,18 @@ func TestValidateWithRelativeSchemaReferencesCurrentDir(t *testing.T) { if err != nil { t.Fatalf("Error reading YAML file: %s", err) } - schema, err := os.ReadFile("./testdata/current-dir-test/values.schema.json") + schemaPath := "./testdata/current-dir-test/values.schema.json" + schema, err := os.ReadFile(schemaPath) if err != nil { t.Fatalf("Error reading JSON schema file: %s", err) } - // Test with absolute base directory - this should work with your fix - baseDir := "./testdata/current-dir-test" - absBaseDir, err := filepath.Abs(baseDir) + absSchemaPath, err := filepath.Abs(schemaPath) if err != nil { t.Fatalf("Error getting absolute path: %s", err) } - if err := ValidateAgainstSingleSchema(values, schema, absBaseDir); err != nil { + if err := ValidateAgainstSingleSchemaWithPath(values, schema, absSchemaPath); err != nil { t.Errorf("Error validating Values against Schema with relative references: %s", err) } } @@ -288,18 +287,18 @@ func TestValidateWithRelativeSchemaReferencesSubfolder(t *testing.T) { if err != nil { t.Fatalf("Error reading YAML file: %s", err) } - schema, err := os.ReadFile("./testdata/subdir-test/subfolder/values.schema.json") + schemaPath := "./testdata/subdir-test/subfolder/values.schema.json" + schema, err := os.ReadFile(schemaPath) if err != nil { t.Fatalf("Error reading JSON schema file: %s", err) } - baseDir := "./testdata/subdir-test/subfolder" - absBaseDir, err := filepath.Abs(baseDir) + absSchemaPath, err := filepath.Abs(schemaPath) if err != nil { t.Fatalf("Error getting absolute path: %s", err) } - if err := ValidateAgainstSingleSchema(values, schema, absBaseDir); err != nil { + if err := ValidateAgainstSingleSchemaWithPath(values, schema, absSchemaPath); err != nil { t.Errorf("Error validating Values against Schema with relative references from subfolder: %s", err) } } diff --git a/pkg/chart/common/util/values.go b/pkg/chart/common/util/values.go index 95ac7ba4d..492e99f33 100644 --- a/pkg/chart/common/util/values.go +++ b/pkg/chart/common/util/values.go @@ -34,6 +34,12 @@ func ToRenderValues(chrt chart.Charter, chrtVals map[string]any, options common. // // This takes both ReleaseOptions and Capabilities to merge into the render values. func ToRenderValuesWithSchemaValidation(chrt chart.Charter, chrtVals map[string]any, options common.ReleaseOptions, caps *common.Capabilities, skipSchemaValidation bool) (common.Values, error) { + return ToRenderValuesWithSchemaValidationAndPath(chrt, chrtVals, options, caps, skipSchemaValidation, "") +} + +// ToRenderValuesWithSchemaValidationAndPath is like ToRenderValuesWithSchemaValidation but accepts chartDir +// for resolving relative $ref in JSON schemas. +func ToRenderValuesWithSchemaValidationAndPath(chrt chart.Charter, chrtVals map[string]any, options common.ReleaseOptions, caps *common.Capabilities, skipSchemaValidation bool, chartDir string) (common.Values, error) { if caps == nil { caps = common.DefaultCapabilities } @@ -60,7 +66,7 @@ func ToRenderValuesWithSchemaValidation(chrt chart.Charter, chrtVals map[string] } if !skipSchemaValidation { - if err := ValidateAgainstSchema(chrt, vals); err != nil { + if err := ValidateAgainstSchemaWithPath(chrt, vals, chartDir); err != nil { return top, fmt.Errorf("values don't meet the specifications of the schema(s) in the following chart(s):\n%w", err) } } diff --git a/pkg/chart/v2/lint/rules/template.go b/pkg/chart/v2/lint/rules/template.go index 43665aa3a..97a403b2e 100644 --- a/pkg/chart/v2/lint/rules/template.go +++ b/pkg/chart/v2/lint/rules/template.go @@ -128,7 +128,7 @@ func (t *templateLinter) Lint() { return } - valuesToRender, err := util.ToRenderValuesWithSchemaValidation(chart, cvals, options, caps, t.skipSchemaValidation) + valuesToRender, err := util.ToRenderValuesWithSchemaValidationAndPath(chart, cvals, options, caps, t.skipSchemaValidation, t.linter.ChartDir) if err != nil { t.linter.RunLinterRule(support.ErrorSev, templatesDir, err) return diff --git a/pkg/chart/v2/lint/rules/values.go b/pkg/chart/v2/lint/rules/values.go index d06875320..77caf130b 100644 --- a/pkg/chart/v2/lint/rules/values.go +++ b/pkg/chart/v2/lint/rules/values.go @@ -41,7 +41,7 @@ func ValuesWithOverrides(linter *support.Linter, valueOverrides map[string]any, return } - linter.RunLinterRule(support.ErrorSev, file, validateValuesFile(vf, valueOverrides, skipSchemaValidation)) + linter.RunLinterRule(support.ErrorSev, file, validateValuesFile(linter.ChartDir, valueOverrides, skipSchemaValidation)) } func validateValuesFileExistence(valuesPath string) error { @@ -52,7 +52,10 @@ func validateValuesFileExistence(valuesPath string) error { return nil } -func validateValuesFile(valuesPath string, overrides map[string]any, skipSchemaValidation bool) error { +func validateValuesFile(chartDir string, overrides map[string]any, skipSchemaValidation bool) error { + valuesPath := filepath.Join(chartDir, "values.yaml") + schemaPath := filepath.Join(chartDir, "values.schema.json") + values, err := common.ReadValuesFile(valuesPath) if err != nil { return fmt.Errorf("unable to parse YAML: %w", err) @@ -66,8 +69,6 @@ func validateValuesFile(valuesPath string, overrides map[string]any, skipSchemaV coalescedValues := util.CoalesceTables(make(map[string]any, len(overrides)), overrides) coalescedValues = util.CoalesceTables(coalescedValues, values) - ext := filepath.Ext(valuesPath) - schemaPath := valuesPath[:len(valuesPath)-len(ext)] + ".schema.json" schema, err := os.ReadFile(schemaPath) if len(schema) == 0 { return nil @@ -75,9 +76,9 @@ func validateValuesFile(valuesPath string, overrides map[string]any, skipSchemaV if err != nil { return err } - baseDir := filepath.Dir(schemaPath) + if !skipSchemaValidation { - return util.ValidateAgainstSingleSchema(coalescedValues, schema, baseDir) + return util.ValidateAgainstSingleSchemaWithPath(coalescedValues, schema, schemaPath) } return nil diff --git a/pkg/chart/v2/lint/rules/values_test.go b/pkg/chart/v2/lint/rules/values_test.go index afc544ebd..b40c7b7de 100644 --- a/pkg/chart/v2/lint/rules/values_test.go +++ b/pkg/chart/v2/lint/rules/values_test.go @@ -66,8 +66,7 @@ func TestValidateValuesFileWellFormed(t *testing.T) { not:well[]{}formed ` tmpdir := ensure.TempFile(t, "values.yaml", []byte(badYaml)) - valfile := filepath.Join(tmpdir, "values.yaml") - if err := validateValuesFile(valfile, map[string]any{}, false); err == nil { + if err := validateValuesFile(tmpdir, map[string]any{}, false); err == nil { t.Fatal("expected values file to fail parsing") } } @@ -77,8 +76,7 @@ func TestValidateValuesFileSchema(t *testing.T) { tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml)) createTestingSchema(t, tmpdir) - valfile := filepath.Join(tmpdir, "values.yaml") - if err := validateValuesFile(valfile, map[string]any{}, false); err != nil { + if err := validateValuesFile(tmpdir, map[string]any{}, false); err != nil { t.Fatalf("Failed validation with %s", err) } } @@ -89,9 +87,7 @@ func TestValidateValuesFileSchemaFailure(t *testing.T) { tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml)) createTestingSchema(t, tmpdir) - valfile := filepath.Join(tmpdir, "values.yaml") - - err := validateValuesFile(valfile, map[string]any{}, false) + err := validateValuesFile(tmpdir, map[string]any{}, false) if err == nil { t.Fatal("expected values file to fail parsing") } @@ -105,9 +101,7 @@ func TestValidateValuesFileSchemaFailureButWithSkipSchemaValidation(t *testing.T tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml)) createTestingSchema(t, tmpdir) - valfile := filepath.Join(tmpdir, "values.yaml") - - err := validateValuesFile(valfile, map[string]any{}, true) + err := validateValuesFile(tmpdir, map[string]any{}, true) if err != nil { t.Fatal("expected values file to pass parsing because of skipSchemaValidation") } @@ -121,8 +115,7 @@ func TestValidateValuesFileSchemaOverrides(t *testing.T) { tmpdir := ensure.TempFile(t, "values.yaml", []byte(yaml)) createTestingSchema(t, tmpdir) - valfile := filepath.Join(tmpdir, "values.yaml") - if err := validateValuesFile(valfile, overrides, false); err != nil { + if err := validateValuesFile(tmpdir, overrides, false); err != nil { t.Fatalf("Failed validation with %s", err) } } @@ -157,9 +150,7 @@ func TestValidateValuesFile(t *testing.T) { tmpdir := ensure.TempFile(t, "values.yaml", []byte(tt.yaml)) createTestingSchema(t, tmpdir) - valfile := filepath.Join(tmpdir, "values.yaml") - - err := validateValuesFile(valfile, tt.overrides, false) + err := validateValuesFile(tmpdir, tt.overrides, false) switch { case err != nil && tt.errorMessage == "": diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go index d36cd9e34..e52bfcc71 100644 --- a/pkg/cmd/install.go +++ b/pkg/cmd/install.go @@ -247,6 +247,7 @@ func runInstall(args []string, client *action.Install, valueOpts *values.Options if err != nil { return nil, err } + client.ChartDir = cp slog.Debug("Chart path", "path", cp) diff --git a/pkg/cmd/install_test.go b/pkg/cmd/install_test.go index 5fa3c1340..3a88a9aa6 100644 --- a/pkg/cmd/install_test.go +++ b/pkg/cmd/install_test.go @@ -231,6 +231,11 @@ func TestInstall(t *testing.T) { cmd: "install schema testdata/testcharts/chart-with-schema-and-subchart --set lastname=doe --set subchart-with-schema.age=-25 --skip-schema-validation", golden: "output/schema.txt", }, + { + name: "install with schema file containing $ref", + cmd: "install reftest testdata/testcharts/chart-with-schema-ref", + golden: "output/schema-ref.txt", + }, // Install deprecated chart { name: "install with warning about deprecated chart", diff --git a/pkg/cmd/template_test.go b/pkg/cmd/template_test.go index 5bcccf5d0..6bfa29743 100644 --- a/pkg/cmd/template_test.go +++ b/pkg/cmd/template_test.go @@ -166,6 +166,11 @@ func TestTemplateCmd(t *testing.T) { cmd: fmt.Sprintf("template '%s' -f %s/extra_values.yaml", chartPath, chartPath), golden: "output/template-subchart-cm-set-file.txt", }, + { + name: "template with schema file containing $ref", + cmd: "template reftest testdata/testcharts/chart-with-schema-ref", + golden: "output/template-schema-ref.txt", + }, } runTestCmd(t, tests) } diff --git a/pkg/cmd/testdata/output/schema-ref.txt b/pkg/cmd/testdata/output/schema-ref.txt new file mode 100644 index 000000000..fa6015315 --- /dev/null +++ b/pkg/cmd/testdata/output/schema-ref.txt @@ -0,0 +1,7 @@ +NAME: reftest +LAST DEPLOYED: Fri Sep 2 22:04:05 1977 +NAMESPACE: default +STATUS: deployed +REVISION: 1 +DESCRIPTION: Install complete +TEST SUITE: None diff --git a/pkg/cmd/testdata/output/template-schema-ref.txt b/pkg/cmd/testdata/output/template-schema-ref.txt new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/pkg/cmd/testdata/output/template-schema-ref.txt @@ -0,0 +1 @@ + diff --git a/pkg/cmd/testdata/output/upgrade-schema-ref.txt b/pkg/cmd/testdata/output/upgrade-schema-ref.txt new file mode 100644 index 000000000..cceed6919 --- /dev/null +++ b/pkg/cmd/testdata/output/upgrade-schema-ref.txt @@ -0,0 +1,8 @@ +Release "reftest" has been upgraded. Happy Helming! +NAME: reftest +LAST DEPLOYED: Fri Sep 2 22:04:05 1977 +NAMESPACE: default +STATUS: deployed +REVISION: 2 +DESCRIPTION: Upgrade complete +TEST SUITE: None diff --git a/pkg/cmd/testdata/testcharts/chart-with-schema-ref b/pkg/cmd/testdata/testcharts/chart-with-schema-ref new file mode 120000 index 000000000..235b87210 --- /dev/null +++ b/pkg/cmd/testdata/testcharts/chart-with-schema-ref @@ -0,0 +1 @@ +../../../action/testdata/charts/chart-with-schema-ref \ No newline at end of file diff --git a/pkg/cmd/upgrade.go b/pkg/cmd/upgrade.go index b71c4ae2d..8aea8be50 100644 --- a/pkg/cmd/upgrade.go +++ b/pkg/cmd/upgrade.go @@ -186,6 +186,7 @@ func newUpgradeCmd(cfg *action.Configuration, out io.Writer) *cobra.Command { if err != nil { return err } + client.ChartDir = chartPath p := getter.All(settings) vals, err := valueOpts.MergeValues(p) diff --git a/pkg/cmd/upgrade_test.go b/pkg/cmd/upgrade_test.go index 0ae1e3561..0c7ef5671 100644 --- a/pkg/cmd/upgrade_test.go +++ b/pkg/cmd/upgrade_test.go @@ -190,6 +190,12 @@ func TestUpgradeCmd(t *testing.T) { golden: "output/upgrade-uninstalled-with-keep-history.txt", rels: []*release.Release{relWithStatusMock("funny-bunny", 2, ch, rcommon.StatusUninstalled)}, }, + { + name: "upgrade with schema file containing $ref", + cmd: "upgrade reftest testdata/testcharts/chart-with-schema-ref", + golden: "output/upgrade-schema-ref.txt", + rels: []*release.Release{relMock("reftest", 1, ch)}, + }, } runTestCmd(t, tests) }