Skip to content

Commit 9462cdb

Browse files
authored
(Issue: #842) Added a check to prevent deeper traversal (#847)
1 parent ea32db9 commit 9462cdb

File tree

3 files changed

+71
-3
lines changed

3 files changed

+71
-3
lines changed

src/rpdk/core/contract/resource_client.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ def compare(self, inputs, outputs, path=()):
414414
is_ordered = traverse_raw_schema(self._schema, new_path).get(
415415
"insertionOrder", True
416416
)
417+
417418
self.compare_collection(
418419
inputs[key], outputs[key], is_ordered, new_path
419420
)

src/rpdk/core/jsonutils/utils.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,18 @@ def traverse(document, path_parts):
132132
return document, tuple(path), parent
133133

134134

135-
def _resolve_ref(sub_schema, definitions):
135+
def _resolve_ref(sub_schema: dict, definitions: dict, last_step: bool = False):
136136
# resolve $ref
137-
ref = nested_lookup(REF, sub_schema)
137+
ref = nested_lookup(REF, sub_schema) # should be safe (always single value)
138+
# bc sub_schema is always per paranet property
139+
# (taken from definitions)
140+
141+
if last_step and REF not in sub_schema: # dont traverse deeper than requested
142+
# check if $ref is used directly ->
143+
# means that we need to check definition
144+
# otherwise it's an array and return subschema
145+
return sub_schema
146+
138147
if ref:
139148
# [0] should be a single $ref in subschema on the top level
140149
# [-1] $ref must follow #/definitions/object
@@ -178,8 +187,15 @@ def traverse_raw_schema(schema: dict, path: tuple):
178187
properties = schema["properties"]
179188
definitions = schema.get("definitions", {})
180189
sub_properties = properties
190+
last_step = (
191+
len(path) - 1
192+
) # get amount of steps to prevent deeper traversal than requested
181193
for step in path:
182-
sub_properties = _resolve_ref(sub_properties[step], definitions)
194+
sub_properties = _resolve_ref(
195+
sub_properties[step],
196+
definitions,
197+
last_step=path.index(step) == last_step,
198+
)
183199
return sub_properties
184200
except KeyError as e:
185201
LOG.debug("Malformed Schema or incorrect path provided\n%s\n%s", path, e)

tests/contract/test_resource_client.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,6 +1710,57 @@ def test_compare_should_throw_exception(resource_client):
17101710
},
17111711
},
17121712
),
1713+
(
1714+
{
1715+
"OptionConfigurations": [
1716+
{
1717+
"OptionSettings": [
1718+
{"Name": "BACKLOG_QUEUE_LIMIT", "Value": "1024"},
1719+
{"Name": "CHUNK_SIZE", "Value": "32"},
1720+
]
1721+
}
1722+
]
1723+
},
1724+
{
1725+
"OptionConfigurations": [
1726+
{
1727+
"OptionSettings": [
1728+
{"Name": "CHUNK_SIZE", "Value": "32"},
1729+
{"Name": "BACKLOG_QUEUE_LIMIT", "Value": "1024"},
1730+
]
1731+
}
1732+
]
1733+
},
1734+
{
1735+
"definitions": {
1736+
"OptionConfiguration": {
1737+
"type": "object",
1738+
"properties": {
1739+
"OptionSettings": {
1740+
"type": "array",
1741+
"insertionOrder": False,
1742+
"items": {"$ref": "#/definitions/OptionSetting"},
1743+
}
1744+
},
1745+
},
1746+
"OptionSetting": {
1747+
"type": "object",
1748+
"properties": {
1749+
"Name": {"type": "string"},
1750+
"Value": {"type": "string"},
1751+
},
1752+
"additionalProperties": False,
1753+
},
1754+
},
1755+
"properties": {
1756+
"OptionConfigurations": {
1757+
"type": "array",
1758+
"insertionOrder": False,
1759+
"items": {"$ref": "#/definitions/OptionConfiguration"},
1760+
},
1761+
},
1762+
},
1763+
),
17131764
],
17141765
)
17151766
def test_compare_collection(resource_client, inputs, outputs, schema_fragment):

0 commit comments

Comments
 (0)