Skip to content

Commit 5931e6d

Browse files
committed
patternProperties matches all patterns against all keys
In draft 4, patternProperties creates an all-of set of schemas for each property. Each property gets compared against all patterns. And it must match all of the schemas for the patterns it matches. So, we cannot avoid compiling some of the patterns. https://datatracker.ietf.org/doc/html/draft-fge-json-schema-validation-00#section-8.3
1 parent 398539e commit 5931e6d

File tree

1 file changed

+21
-13
lines changed

1 file changed

+21
-13
lines changed

st2common/st2common/util/config_loader.py

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -137,20 +137,28 @@ def _get_object_properties_schema(object_schema, object_keys=None):
137137
pattern_properties = object_schema.get("patternProperties", {})
138138
# patternProperties can be a boolean or a dict
139139
if pattern_properties and isinstance(pattern_properties, dict):
140-
for raw_pattern, pattern_schema in pattern_properties.items():
141-
pattern = re.compile(raw_pattern)
142-
for key in list(extra_keys):
140+
# we need to match all extra_keys against all patterns
141+
# and then compose the per-property schema from all
142+
# the matched patterns' properties.
143+
pattern_properties = {
144+
re.compile(raw_pattern): pattern_schema
145+
for raw_pattern, pattern_schema in pattern_properties.items()
146+
}
147+
for key in list(extra_keys):
148+
key_schemas = []
149+
for pattern, pattern_schema in pattern_properties.items():
143150
if pattern.search(key):
144-
# update matched key
145-
flattened_properties_schema[key] = pattern_schema
146-
# don't check matched key against any more patterns
147-
# and don't overwrite with additionalProperties
148-
extra_keys.remove(key)
149-
150-
if not extra_keys:
151-
# nothing to check. Don't compile any more patterns
152-
# and don't look at additionalProperties.
153-
return flattened_properties_schema
151+
key_schemas.append(pattern_schema)
152+
if key_schemas:
153+
composed_schema = {**schema for schema in key_schemas}
154+
# update matched key
155+
flattened_properties_schema[key] = composed_schema
156+
# don't overwrite matched key's schema with additionalProperties
157+
extra_keys.remove(key)
158+
159+
if not extra_keys:
160+
# nothing else to check. Don't look at additionalProperties.
161+
return flattened_properties_schema
154162

155163
# fill in any remaining keys with additionalProperties
156164
additional_properties = object_schema.get("additionalProperties", {})

0 commit comments

Comments
 (0)