From 4756b7a9890d87ac08e0095d447b0c128a86524a Mon Sep 17 00:00:00 2001 From: Kevin DeJong Date: Thu, 5 Sep 2024 17:52:50 -0700 Subject: [PATCH] Prevent infinite loops in keyword building (#3665) * Prevent infinite loops in keyword building * More fixes --- .../all/aws_quicksight_dashboard/yaxis.json | 20 +++++++++++ .../all/aws_quicksight_template/yaxis.json | 20 +++++++++++ .../us_east_1/aws-quicksight-dashboard.json | 6 +++- .../us_east_1/aws-quicksight-template.json | 6 +++- src/cfnlint/jsonschema/validators.py | 4 ++- test/integration/test_schema_files.py | 33 +++++++++---------- 6 files changed, 68 insertions(+), 21 deletions(-) create mode 100644 src/cfnlint/data/schemas/patches/providers/all/aws_quicksight_dashboard/yaxis.json create mode 100644 src/cfnlint/data/schemas/patches/providers/all/aws_quicksight_template/yaxis.json diff --git a/src/cfnlint/data/schemas/patches/providers/all/aws_quicksight_dashboard/yaxis.json b/src/cfnlint/data/schemas/patches/providers/all/aws_quicksight_dashboard/yaxis.json new file mode 100644 index 0000000000..ce723281d8 --- /dev/null +++ b/src/cfnlint/data/schemas/patches/providers/all/aws_quicksight_dashboard/yaxis.json @@ -0,0 +1,20 @@ +[ + { + "op": "test", + "path": "/definitions/SingleAxisOptions/properties/YAxisOptions", + "value": { + "$ref": "#/definitions/YAxisOptions" + } + }, + { + "op": "replace", + "path": "/definitions/SingleAxisOptions/properties/YAxisOptions", + "value": { + "properties": { + "YAxis": { + "$ref": "#/definitions/SingleYAxisOption" + } + } + } + } +] diff --git a/src/cfnlint/data/schemas/patches/providers/all/aws_quicksight_template/yaxis.json b/src/cfnlint/data/schemas/patches/providers/all/aws_quicksight_template/yaxis.json new file mode 100644 index 0000000000..ce723281d8 --- /dev/null +++ b/src/cfnlint/data/schemas/patches/providers/all/aws_quicksight_template/yaxis.json @@ -0,0 +1,20 @@ +[ + { + "op": "test", + "path": "/definitions/SingleAxisOptions/properties/YAxisOptions", + "value": { + "$ref": "#/definitions/YAxisOptions" + } + }, + { + "op": "replace", + "path": "/definitions/SingleAxisOptions/properties/YAxisOptions", + "value": { + "properties": { + "YAxis": { + "$ref": "#/definitions/SingleYAxisOption" + } + } + } + } +] diff --git a/src/cfnlint/data/schemas/providers/us_east_1/aws-quicksight-dashboard.json b/src/cfnlint/data/schemas/providers/us_east_1/aws-quicksight-dashboard.json index 2b4e64c415..2a37d3ff6f 100644 --- a/src/cfnlint/data/schemas/providers/us_east_1/aws-quicksight-dashboard.json +++ b/src/cfnlint/data/schemas/providers/us_east_1/aws-quicksight-dashboard.json @@ -9314,7 +9314,11 @@ "additionalProperties": false, "properties": { "YAxisOptions": { - "$ref": "#/definitions/YAxisOptions" + "properties": { + "YAxis": { + "$ref": "#/definitions/SingleYAxisOption" + } + } } }, "type": "object" diff --git a/src/cfnlint/data/schemas/providers/us_east_1/aws-quicksight-template.json b/src/cfnlint/data/schemas/providers/us_east_1/aws-quicksight-template.json index ac09fd2fbe..e0ac9b6494 100644 --- a/src/cfnlint/data/schemas/providers/us_east_1/aws-quicksight-template.json +++ b/src/cfnlint/data/schemas/providers/us_east_1/aws-quicksight-template.json @@ -8932,7 +8932,11 @@ "additionalProperties": false, "properties": { "YAxisOptions": { - "$ref": "#/definitions/YAxisOptions" + "properties": { + "YAxis": { + "$ref": "#/definitions/SingleYAxisOption" + } + } } }, "type": "object" diff --git a/src/cfnlint/jsonschema/validators.py b/src/cfnlint/jsonschema/validators.py index 98263ca8a5..ca6e16eefc 100644 --- a/src/cfnlint/jsonschema/validators.py +++ b/src/cfnlint/jsonschema/validators.py @@ -413,5 +413,7 @@ def extend( StandardValidator = create( validators=_standard_validators, - function_filter=FunctionFilter(), + function_filter=FunctionFilter( + add_cfn_lint_keyword=False, + ), ) diff --git a/test/integration/test_schema_files.py b/test/integration/test_schema_files.py index a46e42ec04..e3c097daa0 100644 --- a/test/integration/test_schema_files.py +++ b/test/integration/test_schema_files.py @@ -112,15 +112,21 @@ def validate_basic_schema_details( except RefResolutionError: self.fail(f"Can't find prop {prop} for {section} in {filepath}") - def _build_keywords( - self, obj: Any, schema_resolver: RefResolver, refs: list[str] | None = None - ): - if refs is None: - refs = [] + def _build_keywords(self, obj: Any, schema_resolver: RefResolver, refs: list[str]): if not isinstance(obj, dict): yield [] return + if "$ref" in obj: + ref = obj["$ref"] + if ref in refs: + yield [] + return + _, resolved_schema = schema_resolver.resolve(ref) + yield from self._build_keywords( + resolved_schema, schema_resolver, refs + [ref] + ) + if "type" in obj: if "object" in ensure_list(obj["type"]): if "properties" in obj: @@ -134,17 +140,6 @@ def _build_keywords( ): yield ["*"] + item - if "$ref" in obj: - ref = obj["$ref"] - if ref in refs: - yield [] - return - _, resolved_schema = schema_resolver.resolve(ref) - for item in self._build_keywords( - resolved_schema, schema_resolver, refs + [ref] - ): - yield item - yield [] def build_keywords(self, schema_resolver): @@ -152,7 +147,7 @@ def build_keywords(self, schema_resolver): "/".join(["Resources", schema_resolver.referrer["typeName"], "Properties"]) ) for k, v in schema_resolver.referrer.get("properties").items(): - for item in self._build_keywords(v, schema_resolver): + for item in self._build_keywords(v, schema_resolver, []): self._found_keywords.append( "/".join( [ @@ -214,7 +209,9 @@ def test_data_module_specs(self): self.validate_basic_schema_details( schema_resolver, f"{dirpath}/{filename}" ) - self.build_keywords(schema_resolver) + + if region == "us-east-1": + self.build_keywords(schema_resolver) def cfn_lint(self, validator, _, keywords, schema): keywords = ensure_list(keywords)