pull/31274/merge
Benoit Tigeot 12 hours ago committed by GitHub
commit f6176da0fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -75,9 +75,9 @@ func validateValuesFile(valuesPath string, overrides map[string]interface{}, ski
if err != nil {
return err
}
baseDir := filepath.Dir(schemaPath)
if !skipSchemaValidation {
return util.ValidateAgainstSingleSchema(coalescedValues, schema)
return util.ValidateAgainstSingleSchema(coalescedValues, schema, baseDir)
}
return nil

@ -23,6 +23,7 @@ import (
"fmt"
"log/slog"
"net/http"
"path/filepath"
"strings"
"time"
@ -80,7 +81,7 @@ func ValidateAgainstSchema(ch chart.Charter, values map[string]interface{}) erro
var sb strings.Builder
if chrt.Schema() != nil {
slog.Debug("chart name", "chart-name", chrt.Name())
err := ValidateAgainstSingleSchema(values, chrt.Schema())
err := ValidateAgainstSingleSchema(values, chrt.Schema(), chrt.ChartFullPath())
if err != nil {
sb.WriteString(fmt.Sprintf("%s:\n", chrt.Name()))
sb.WriteString(err.Error())
@ -107,7 +108,7 @@ func ValidateAgainstSchema(ch chart.Charter, values map[string]interface{}) erro
}
// ValidateAgainstSingleSchema checks that values does not violate the structure laid out in this schema
func ValidateAgainstSingleSchema(values common.Values, schemaJSON []byte) (reterr error) {
func ValidateAgainstSingleSchema(values common.Values, schemaJSON []byte, absBaseDir string) (reterr error) {
defer func() {
if r := recover(); r != nil {
reterr = fmt.Errorf("unable to validate schema: %s", r)
@ -131,12 +132,13 @@ func ValidateAgainstSingleSchema(values common.Values, schemaJSON []byte) (reter
compiler := jsonschema.NewCompiler()
compiler.UseLoader(loader)
err = compiler.AddResource("file:///values.schema.json", schema)
base := "file://" + filepath.ToSlash(absBaseDir) + "/values.schema.json"
err = compiler.AddResource(base, schema)
if err != nil {
return err
}
validator, err := compiler.Compile("file:///values.schema.json")
validator, err := compiler.Compile(base)
if err != nil {
return err
}
@ -165,7 +167,11 @@ 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.
errStr = strings.TrimPrefix(errStr, "jsonschema validation failed with 'file:///values.schema.json#'\n")
if strings.HasPrefix(errStr, "jsonschema validation failed with ") {
if idx := strings.Index(errStr, "#'\n"); idx != -1 {
errStr = errStr[idx+3:]
}
}
// The extra new line is needed for when there are sub-charts.
return errStr + "\n"

@ -20,6 +20,7 @@ import (
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
@ -37,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)
}
}
@ -53,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()
@ -77,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()
@ -177,11 +178,12 @@ func TestValidateAgainstSchemaNegative(t *testing.T) {
errString = err.Error()
}
expectedErrString := `subchart:
- at '': missing property 'age'
`
if errString != expectedErrString {
t.Errorf("Error string :\n`%s`\ndoes not match expected\n`%s`", errString, expectedErrString)
expectedValidationError := "missing property 'age'"
if !strings.Contains(errString, "subchart:") {
t.Errorf("Error string should contain 'subchart:', got: %s", errString)
}
if !strings.Contains(errString, expectedValidationError) {
t.Errorf("Error string should contain '%s', got: %s", expectedValidationError, errString)
}
}
@ -241,12 +243,64 @@ func TestValidateAgainstSchema2020Negative(t *testing.T) {
errString = err.Error()
}
expectedErrString := `subchart:
- at '/data': no items match contains schema
- at '/data/0': got number, want string
`
if errString != expectedErrString {
t.Errorf("Error string :\n`%s`\ndoes not match expected\n`%s`", errString, expectedErrString)
expectedValidationErrors := []string{
"no items match contains schema",
"got number, want string",
}
if !strings.Contains(errString, "subchart:") {
t.Errorf("Error string should contain 'subchart:', got: %s", errString)
}
for _, expectedErr := range expectedValidationErrors {
if !strings.Contains(errString, expectedErr) {
t.Errorf("Error string should contain '%s', got: %s", expectedErr, errString)
}
}
}
// TestValidateWithRelativeSchemaReferences tests schema validation with relative $ref paths
// This mimics the behavior of "helm lint ." where the schema is in the current directory
func TestValidateWithRelativeSchemaReferencesCurrentDir(t *testing.T) {
values, err := common.ReadValuesFile("./testdata/current-dir-test/test-values.yaml")
if err != nil {
t.Fatalf("Error reading YAML file: %s", err)
}
schema, err := os.ReadFile("./testdata/current-dir-test/values.schema.json")
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)
if err != nil {
t.Fatalf("Error getting absolute path: %s", err)
}
if err := ValidateAgainstSingleSchema(values, schema, absBaseDir); err != nil {
t.Errorf("Error validating Values against Schema with relative references: %s", err)
}
}
// TestValidateWithRelativeSchemaReferencesSubfolder tests schema validation with relative $ref paths
// This mimics the behavior of "helm lint subfolder" where the schema is in a subdirectory
func TestValidateWithRelativeSchemaReferencesSubfolder(t *testing.T) {
values, err := common.ReadValuesFile("./testdata/subdir-test/subfolder/test-values.yaml")
if err != nil {
t.Fatalf("Error reading YAML file: %s", err)
}
schema, err := os.ReadFile("./testdata/subdir-test/subfolder/values.schema.json")
if err != nil {
t.Fatalf("Error reading JSON schema file: %s", err)
}
baseDir := "./testdata/subdir-test/subfolder"
absBaseDir, err := filepath.Abs(baseDir)
if err != nil {
t.Fatalf("Error getting absolute path: %s", err)
}
if err := ValidateAgainstSingleSchema(values, schema, absBaseDir); err != nil {
t.Errorf("Error validating Values against Schema with relative references from subfolder: %s", err)
}
}

@ -0,0 +1,10 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"name": {
"type": "string"
}
},
"required": ["name"]
}

@ -0,0 +1,3 @@
user:
name: "John Doe"
age: 30

@ -0,0 +1,14 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"user": {
"$ref": "./base.schema.json"
},
"age": {
"type": "integer",
"minimum": 0
}
},
"required": ["user", "age"]
}

@ -0,0 +1,10 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"config": {
"type": "string"
}
},
"required": ["config"]
}

@ -0,0 +1,3 @@
appConfig:
config: "production"
replicas: 3

@ -0,0 +1,14 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"appConfig": {
"$ref": "../shared.schema.json"
},
"replicas": {
"type": "integer",
"minimum": 1
}
},
"required": ["appConfig", "replicas"]
}

@ -75,9 +75,9 @@ func validateValuesFile(valuesPath string, overrides map[string]interface{}, ski
if err != nil {
return err
}
baseDir := filepath.Dir(schemaPath)
if !skipSchemaValidation {
return util.ValidateAgainstSingleSchema(coalescedValues, schema)
return util.ValidateAgainstSingleSchema(coalescedValues, schema, baseDir)
}
return nil

Loading…
Cancel
Save