json schema fix

Signed-off-by: Robert Sirchia <rsirchia@outlook.com>
pull/31153/head
Robert Sirchia 2 months ago
parent 9ec1679d60
commit 6d9509aadc
No known key found for this signature in database
GPG Key ID: C2D40F4D8196E874

@ -1,4 +1,4 @@
Error: INSTALLATION FAILED: values don't meet the specifications of the schema(s) in the following chart(s):
empty:
- age: Must be greater than or equal to 0
- at '/age': minimum: got -5, want 0

@ -1,5 +1,5 @@
Error: INSTALLATION FAILED: values don't meet the specifications of the schema(s) in the following chart(s):
empty:
- (root): employmentInfo is required
- age: Must be greater than or equal to 0
- at '': missing property 'employmentInfo'
- at '/age': minimum: got -5, want 0

@ -1,4 +1,4 @@
Error: INSTALLATION FAILED: values don't meet the specifications of the schema(s) in the following chart(s):
subchart-with-schema:
- age: Must be greater than or equal to 0
- at '/age': minimum: got -25, want 0

@ -1,6 +1,6 @@
Error: INSTALLATION FAILED: values don't meet the specifications of the schema(s) in the following chart(s):
chart-without-schema:
- (root): lastname is required
- at '': missing property 'lastname'
subchart-with-schema:
- (root): age is required
- at '': missing property 'age'

@ -29,10 +29,10 @@ require (
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5
github.com/pkg/errors v0.9.1
github.com/rubenv/sql-migrate v1.8.0
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2
github.com/spf13/cobra v1.9.1
github.com/spf13/pflag v1.0.7
github.com/stretchr/testify v1.10.0
github.com/xeipuuv/gojsonschema v1.2.0
golang.org/x/crypto v0.40.0
golang.org/x/term v0.33.0
golang.org/x/text v0.27.0
@ -133,8 +133,6 @@ require (
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/cast v1.7.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/bridges/prometheus v0.57.0 // indirect

@ -76,6 +76,8 @@ github.com/distribution/distribution/v3 v3.0.0 h1:q4R8wemdRQDClzoNNStftB2ZAfqOiN
github.com/distribution/distribution/v3 v3.0.0/go.mod h1:tRNuFoZsUdyRVegq8xGNeds4KLjwLCRin/tTo6i1DhU=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
@ -303,6 +305,8 @@ github.com/rubenv/sql-migrate v1.8.0 h1:dXnYiJk9k3wetp7GfQbKJcPHjVJL6YK19tKj8t2N
github.com/rubenv/sql-migrate v1.8.0/go.mod h1:F2bGFBwCU+pnmbtNYDeKvSuvL6lBVtXDXUUv5t+u1qw=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
@ -334,13 +338,6 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=

@ -18,12 +18,11 @@ package chartutil
import (
"bytes"
"errors"
"fmt"
"strings"
"github.com/pkg/errors"
"github.com/xeipuuv/gojsonschema"
"sigs.k8s.io/yaml"
"github.com/santhosh-tekuri/jsonschema/v6"
"helm.sh/helm/v3/pkg/chart"
)
@ -32,6 +31,7 @@ import (
func ValidateAgainstSchema(chrt *chart.Chart, values map[string]interface{}) error {
var sb strings.Builder
if chrt.Schema != nil {
err := ValidateAgainstSingleSchema(values, chrt.Schema)
if err != nil {
sb.WriteString(fmt.Sprintf("%s:\n", chrt.Name()))
@ -39,7 +39,6 @@ func ValidateAgainstSchema(chrt *chart.Chart, values map[string]interface{}) err
}
}
// For each dependency, recursively call this function with the coalesced values
for _, subchart := range chrt.Dependencies() {
subchartValues := values[subchart.Name()].(map[string]interface{})
if err := ValidateAgainstSchema(subchart, subchartValues); err != nil {
@ -62,32 +61,40 @@ func ValidateAgainstSingleSchema(values Values, schemaJSON []byte) (reterr error
}
}()
valuesData, err := yaml.Marshal(values)
// This unmarshal function leverages UseNumber() for number precision. The parser
// used for values does this as well.
schema, err := jsonschema.UnmarshalJSON(bytes.NewReader(schemaJSON))
if err != nil {
return err
}
valuesJSON, err := yaml.YAMLToJSON(valuesData)
compiler := jsonschema.NewCompiler()
err = compiler.AddResource("file:///values.schema.json", schema)
if err != nil {
return err
}
if bytes.Equal(valuesJSON, []byte("null")) {
valuesJSON = []byte("{}")
}
schemaLoader := gojsonschema.NewBytesLoader(schemaJSON)
valuesLoader := gojsonschema.NewBytesLoader(valuesJSON)
result, err := gojsonschema.Validate(schemaLoader, valuesLoader)
validator, err := compiler.Compile("file:///values.schema.json")
if err != nil {
return err
}
if !result.Valid() {
var sb strings.Builder
for _, desc := range result.Errors() {
sb.WriteString(fmt.Sprintf("- %s\n", desc))
}
return errors.New(sb.String())
err = validator.Validate(values.AsMap())
if err != nil {
return JSONSchemaValidationError{err}
}
return nil
}
type JSONSchemaValidationError struct {
embeddedErr error
}
func (e JSONSchemaValidationError) Error() string {
errStr := e.embeddedErr.Error()
errStr = strings.TrimPrefix(errStr, "jsonschema validation failed with 'file:///values.schema.json#'\n")
return errStr + "\n"
}

@ -55,8 +55,9 @@ func TestValidateAgainstInvalidSingleSchema(t *testing.T) {
errString = err.Error()
}
expectedErrString := "unable to validate schema: runtime error: invalid " +
"memory address or nil pointer dereference"
expectedErrString := `"file:///values.schema.json#" is not valid against metaschema: jsonschema validation failed with 'https://json-schema.org/draft/2020-12/schema#'
- at '': got number, want boolean or object`
if errString != expectedErrString {
t.Errorf("Error string :\n`%s`\ndoes not match expected\n`%s`", errString, expectedErrString)
}
@ -79,8 +80,8 @@ func TestValidateAgainstSingleSchemaNegative(t *testing.T) {
errString = err.Error()
}
expectedErrString := `- (root): employmentInfo is required
- age: Must be greater than or equal to 0
expectedErrString := `- at '': missing property 'employmentInfo'
- at '/age': minimum: got -5, want 0
`
if errString != expectedErrString {
t.Errorf("Error string :\n`%s`\ndoes not match expected\n`%s`", errString, expectedErrString)
@ -159,7 +160,7 @@ func TestValidateAgainstSchemaNegative(t *testing.T) {
}
expectedErrString := `subchart:
- (root): age is required
- at '': missing property 'age'
`
if errString != expectedErrString {
t.Errorf("Error string :\n`%s`\ndoes not match expected\n`%s`", errString, expectedErrString)

@ -96,7 +96,7 @@ func TestValidateValuesFileSchemaFailure(t *testing.T) {
t.Fatal("expected values file to fail parsing")
}
assert.Contains(t, err.Error(), "Expected: string, given: integer", "integer should be caught by schema")
assert.Contains(t, err.Error(), "- at '/username': got number, want string")
}
func TestValidateValuesFileSchemaOverrides(t *testing.T) {
@ -129,7 +129,7 @@ func TestValidateValuesFile(t *testing.T) {
name: "value not overridden",
yaml: "username: admin\npassword:",
overrides: map[string]interface{}{"username": "anotherUser"},
errorMessage: "Expected: string, given: null",
errorMessage: "- at '/password': got null, want string",
},
{
name: "value overridden",

Loading…
Cancel
Save