From 03bb62f63dabb9f7f7db70e2e070e5e276384a8b Mon Sep 17 00:00:00 2001 From: Benoit Tigeot Date: Thu, 4 Sep 2025 15:40:59 +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). - Apply to pkg/chart/v2 and internal/chart/v3 validators. Not sure about that Note: external URNs need AddResource/Resolver (the CLI uses --map for this). Warning may appear twice since both validators run. Another strategy could be to add the option to import more "external schema" explicitly but it is another PR. Something similar to `--map` from jsonschema package (santhosh-tekuri/jsonschema@ed65924). Close: #31170 Signed-off-by: Benoit Tigeot --- pkg/chart/common/util/jsonschema.go | 25 ++++++++++++++++++++++++ pkg/chart/common/util/jsonschema_test.go | 13 ++++++++++++ 2 files changed, 38 insertions(+) diff --git a/pkg/chart/common/util/jsonschema.go b/pkg/chart/common/util/jsonschema.go index acd2ca100..827ce4128 100644 --- a/pkg/chart/common/util/jsonschema.go +++ b/pkg/chart/common/util/jsonschema.go @@ -127,6 +127,7 @@ func ValidateAgainstSingleSchema(values common.Values, schemaJSON []byte) (reter "file": jsonschema.FileLoader{}, "http": newHTTPURLLoader(), "https": newHTTPURLLoader(), + "urn": urnLoader{}, } compiler := jsonschema.NewCompiler() @@ -149,6 +150,30 @@ func ValidateAgainstSingleSchema(values common.Values, schemaJSON []byte) (reter return nil } +// 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{} + +func (l urnLoader) Load(urlStr string) (any, error) { + if doc, err := URNResolver(urlStr); err == nil && doc != nil { + return doc, nil + } + slog.Warn("unresolved URN reference ignored; using permissive schema", "urn", urlStr) + return jsonschema.UnmarshalJSON(strings.NewReader("true")) +} + // Note, JSONSchemaValidationError is used to wrap the error from the underlying // validation package so that Helm has a clean interface and the validation package // could be replaced without changing the Helm SDK API. diff --git a/pkg/chart/common/util/jsonschema_test.go b/pkg/chart/common/util/jsonschema_test.go index b34f9d514..f50cc81a6 100644 --- a/pkg/chart/common/util/jsonschema_test.go +++ b/pkg/chart/common/util/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) + } +}