From 7987ad18d9cd2667ea99646aa18dc3efb72395ca Mon Sep 17 00:00:00 2001 From: nyxst4ck <289980115+nyxst4ck@users.noreply.github.com> Date: Tue, 16 Jun 2026 20:15:39 -0300 Subject: [PATCH] Fix relative-json-pointer rejecting multi-digit integers with a zero The relative-json-pointer format checker disallowed a leading zero by checking the *previous* character (int(instance[i - 1]) == 0), so any non-negative integer prefix containing a 0 followed by another digit -- '100', '205', '1000', '100/foo', '100#' -- was wrongly rejected. Per draft-handrews-relative-json-pointer-01 section 3 only a leading zero is forbidden ('0' alone is valid; '01' is not). Reject only when the accumulated integer is exactly '0' and another digit follows. --- jsonschema/_format.py | 7 +++++-- jsonschema/tests/test_format.py | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/jsonschema/_format.py b/jsonschema/_format.py index 5efda86e6..cd057f0f8 100644 --- a/jsonschema/_format.py +++ b/jsonschema/_format.py @@ -488,8 +488,11 @@ def is_relative_json_pointer(instance: object) -> bool: non_negative_integer, rest = [], "" for i, character in enumerate(instance): if character.isdigit(): - # digits with a leading "0" are not allowed - if i > 0 and int(instance[i - 1]) == 0: + # a leading "0" is not allowed: "0" by itself is valid, but a + # multi-digit integer may not start with "0" (e.g. "01"). Only + # the single accumulated "0" followed by another digit is a + # leading zero -- "100"/"205" are fine. + if non_negative_integer == ["0"]: return False non_negative_integer.append(character) diff --git a/jsonschema/tests/test_format.py b/jsonschema/tests/test_format.py index d829f9848..6d4183006 100644 --- a/jsonschema/tests/test_format.py +++ b/jsonschema/tests/test_format.py @@ -80,6 +80,25 @@ def test_format_checkers_come_with_defaults(self): with self.assertRaises(FormatError): checker.check(instance="not-an-ipv4", format="ipv4") + def test_relative_json_pointer_allows_multidigit_integers(self): + checker = FormatChecker() + if "relative-json-pointer" not in checker.checkers: + self.skipTest("jsonpointer is not available") + + # Only a *leading* zero is disallowed; a multi-digit integer with an + # internal or trailing zero is valid. + valids = ("0", "1", "120", "100", "205", "1000", "100/foo", "100#") + for valid in valids: + self.assertTrue( + checker.conforms(valid, "relative-json-pointer"), + msg=f"{valid!r} should be a valid relative-json-pointer", + ) + for invalid in ("01", "00", "007", "01/a", "01#"): + self.assertFalse( + checker.conforms(invalid, "relative-json-pointer"), + msg=f"{invalid!r} should not be a valid relative-json-pointer", + ) + def test_repr(self): checker = FormatChecker(formats=()) checker.checks("foo")(lambda thing: True) # pragma: no cover