From 6057440e4d1327633ad5f9f443160b06441821aa Mon Sep 17 00:00:00 2001 From: Benoit Tigeot Date: Fri, 5 Sep 2025 10:38:16 +0200 Subject: [PATCH] jsonschema: warn and ignore unresolved URN $ref to match v3.18.4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - v3.18.5 switched jsonschema and began resolving external $ref at compile-time, exposing missing urn handling (“no URLLoader registered for urn:…”). - Add urn scheme loader and pluggable URNResolver. If unresolved, log a warning and return a permissive true schema (back-compat). - Avoid having a duplicated warn logs when we Load the schema twice. Note: external URNs need AddResource/Resolver (the CLI uses --map for this). Close: #31170 Signed-off-by: Benoit Tigeot --- pkg/chartutil/jsonschema.go | 32 ++++++++++++++++++++++++++++++++ pkg/chartutil/jsonschema_test.go | 13 +++++++++++++ 2 files changed, 45 insertions(+) diff --git a/pkg/chartutil/jsonschema.go b/pkg/chartutil/jsonschema.go index d712316c5..74ac521f6 100644 --- a/pkg/chartutil/jsonschema.go +++ b/pkg/chartutil/jsonschema.go @@ -21,7 +21,9 @@ import ( "crypto/tls" "errors" "fmt" + "log" "strings" + "sync" "time" "github.com/santhosh-tekuri/jsonschema/v6" @@ -115,6 +117,7 @@ func ValidateAgainstSingleSchema(values Values, schemaJSON []byte) (reterr error "file": jsonschema.FileLoader{}, "http": newHTTPURLLoader(), "https": newHTTPURLLoader(), + "urn": urnLoader{}, } compiler := jsonschema.NewCompiler() @@ -148,3 +151,32 @@ func (e JSONSchemaValidationError) Error() string { return errStr + "\n" } + +// URNResolverFunc allows SDK to plug a URN resolver. It must return a +// schema document compatible with the validator (e.g., result of +// jsonschema.UnmarshalJSON). +type URNResolverFunc func(urn string) (any, error) + +// URNResolver is the default resolver used by the URN loader. By default it +// returns a clear error. +var URNResolver URNResolverFunc = func(urn string) (any, error) { + return nil, fmt.Errorf("URN not resolved: %s", urn) +} + +// urnLoader implements resolution for the urn: scheme by delegating to +// URNResolver. If unresolved, it logs a warning and returns a permissive +// boolean-true schema to avoid hard failures (back-compat behavior). +type urnLoader struct{} + +// warnedURNs ensures we log the unresolved-URN warning only once per URN. +var warnedURNs sync.Map + +func (l urnLoader) Load(urlStr string) (any, error) { + if doc, err := URNResolver(urlStr); err == nil && doc != nil { + return doc, nil + } + if _, loaded := warnedURNs.LoadOrStore(urlStr, struct{}{}); !loaded { + log.Printf("WARNING: unresolved URN reference ignored; using permissive schema: %s", urlStr) + } + return jsonschema.UnmarshalJSON(strings.NewReader("true")) +} diff --git a/pkg/chartutil/jsonschema_test.go b/pkg/chartutil/jsonschema_test.go index 8084b8602..00ec1f838 100644 --- a/pkg/chartutil/jsonschema_test.go +++ b/pkg/chartutil/jsonschema_test.go @@ -286,3 +286,16 @@ func TestHTTPURLLoader_Load(t *testing.T) { } }) } + +// Test that an unresolved URN $ref is soft-ignored and validation succeeds. +// it mimics the behavior of Helm 3.18.4 +func TestValidateAgainstSingleSchema_UnresolvedURN_Ignored(t *testing.T) { + schema := []byte(`{ + "$schema": "https://json-schema.org/draft-07/schema#", + "$ref": "urn:example:helm:schemas:v1:helm-schema-validation-conditions:v1/helmSchemaValidation-true" + }`) + vals := map[string]interface{}{"any": "value"} + if err := ValidateAgainstSingleSchema(vals, schema); err != nil { + t.Fatalf("expected no error when URN unresolved is ignored, got: %v", err) + } +}