Skip to content

Commit 36e7187

Browse files
committed
Reject negative array indices in JSON pointers
1 parent 40be109 commit 36e7187

2 files changed

Lines changed: 25 additions & 0 deletions

File tree

‎referencing/_core.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,12 @@ def pointer(self, pointer: str, resolver: Resolver[D]) -> Resolved[D]:
265265
for segment in unquote(pointer[1:]).split("/"):
266266
if isinstance(contents, Sequence):
267267
segment = int(segment)
268+
# 2026-10-08: JSON array indices cannot count from the end.
269+
if segment < 0:
270+
raise exceptions.PointerToNowhere(
271+
ref=pointer,
272+
resource=self,
273+
)
268274
else:
269275
segment = segment.replace("~1", "/").replace("~0", "~")
270276
try:

‎referencing/tests/test_core.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,25 @@ def test_lookup_non_existent_pointer_to_array_index(self):
762762
resource=resource,
763763
)
764764

765+
@pytest.mark.parametrize("index", [-1, -2, -4])
766+
def test_lookup_negative_array_index(self, index):
767+
# 2026-10-08: JSON arrays have no negative-index members.
768+
resource = Resource.opaque([1, 2, 4, 8])
769+
resolver = Registry({"http://example.com/1": resource}).resolver()
770+
pointer = f"/{index}"
771+
with pytest.raises(exceptions.PointerToNowhere) as exc:
772+
resolver.lookup(f"http://example.com/1#{pointer}")
773+
assert exc.value == exceptions.PointerToNowhere(
774+
ref=pointer,
775+
resource=resource,
776+
)
777+
778+
def test_lookup_negative_integer_object_key(self):
779+
# 2026-10-08: Object member names remain literal strings.
780+
resource = Resource.opaque({"-1": "value"})
781+
resolver = Registry().resolver_with_root(resource)
782+
assert resolver.lookup("#/-1").contents == "value"
783+
765784
def test_lookup_pointer_to_empty_string(self):
766785
resolver = Registry().resolver_with_root(Resource.opaque({"": {}}))
767786
assert resolver.lookup("#/").contents == {}

0 commit comments

Comments
 (0)