From dc683c3105216f0c3fbfba78815b97f510e434c8 Mon Sep 17 00:00:00 2001 From: Julian Berman Date: Tue, 25 Apr 2023 16:21:15 -0400 Subject: Re-enable (but deprecate) automatic reference retrieval. Changing this without deprecation is backwards incompatible, so we re-introduce a warning. This only applies if you have not configured neither a Registry nor a legacy RefResolver. Both of the former 2 cases already have 'correct' behavior (the former will not automatically retrieve references and is not backwards incompatible as it is a new API, and the latter will do so but is already fully deprecated by this release). Cloess: #1089 --- jsonschema/tests/test_deprecations.py | 6 +++--- jsonschema/validators.py | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 7 deletions(-) (limited to 'jsonschema') diff --git a/jsonschema/tests/test_deprecations.py b/jsonschema/tests/test_deprecations.py index cf5538f..1b19736 100644 --- a/jsonschema/tests/test_deprecations.py +++ b/jsonschema/tests/test_deprecations.py @@ -178,12 +178,12 @@ class TestDeprecations(TestCase): multiple inheritance subclass, we need to be extra sure it works and stays working. """ - validator = validators.Draft202012Validator({"$ref": "http://foo.com"}) + validator = validators.Draft202012Validator({"$ref": "urn:nothing"}) with self.assertRaises(referencing.exceptions.Unresolvable) as e: validator.validate(12) - expected = referencing.exceptions.Unresolvable(ref="http://foo.com") + expected = referencing.exceptions.Unresolvable(ref="urn:nothing") self.assertEqual(e.exception, expected) def test_catching_Unresolvable_via_RefResolutionError(self): @@ -195,7 +195,7 @@ class TestDeprecations(TestCase): with self.assertWarns(DeprecationWarning): from jsonschema import RefResolutionError - validator = validators.Draft202012Validator({"$ref": "http://foo.com"}) + validator = validators.Draft202012Validator({"$ref": "urn:nothing"}) with self.assertRaises(referencing.exceptions.Unresolvable): validator.validate(12) diff --git a/jsonschema/validators.py b/jsonschema/validators.py index 78e5829..5b16fdc 100644 --- a/jsonschema/validators.py +++ b/jsonschema/validators.py @@ -17,7 +17,6 @@ import warnings from attrs import define, field, fields from jsonschema_specifications import REGISTRY as SPECIFICATIONS -from referencing import Specification from rpds import HashTrieMap import referencing.exceptions import referencing.jsonschema @@ -103,6 +102,29 @@ def validates(version): return _validates +def _warn_for_remote_retrieve(uri: str): + from urllib.request import urlopen + with urlopen(uri) as response: + warnings.warn( + "Automatically retrieving remote references can be a security " + "vulnerability and is discouraged by the JSON Schema " + "specifications. Relying on this behavior is deprecated " + "and will shortly become an error. If you are sure you want to " + "remotely retrieve your reference and that it is safe to do so, " + "you can find instructions for doing so via referencing.Registry " + "in the referencing documentation " + "(https://referencing.readthedocs.org).", + DeprecationWarning, + stacklevel=9, # Ha ha ha ha magic numbers :/ + ) + return referencing.Resource.from_contents(json.load(response)) + + +_DEFAULT_REGISTRY = SPECIFICATIONS.combine( + referencing.Registry(retrieve=_warn_for_remote_retrieve), +) + + def create( meta_schema: referencing.jsonschema.ObjectSchema, validators: ( @@ -185,7 +207,7 @@ def create( specification = referencing.jsonschema.specification_with( dialect_id=id_of(meta_schema) or "urn:unknown-dialect", - default=Specification.OPAQUE, + default=referencing.Specification.OPAQUE, ) @define @@ -202,8 +224,12 @@ def create( format_checker: _format.FormatChecker | None = field(default=None) # TODO: include new meta-schemas added at runtime _registry: referencing.jsonschema.SchemaRegistry = field( - default=SPECIFICATIONS, - converter=SPECIFICATIONS.combine, # type: ignore[misc] + default=_DEFAULT_REGISTRY, + converter=lambda value: ( + _DEFAULT_REGISTRY + if value is _DEFAULT_REGISTRY + else SPECIFICATIONS.combine(value) + ), kw_only=True, repr=False, ) -- cgit v1.2.1