Skip to content

Commit

Permalink
Allow Transform section to have the full transform def (#3470)
Browse files Browse the repository at this point in the history
* Allow Transform section to have the full transform def
* Switch transform validation to rule E1005
  • Loading branch information
kddejong authored Jul 7, 2024
1 parent d598742 commit 78e9fa9
Show file tree
Hide file tree
Showing 12 changed files with 177 additions and 25 deletions.
2 changes: 1 addition & 1 deletion src/cfnlint/context/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def __post_init__(self, transforms) -> None:

for transform in transforms:
if not isinstance(transform, str):
raise ValueError("Transform must be a string")
continue
self._transforms.append(transform)

def has_language_extensions_transform(self):
Expand Down
10 changes: 1 addition & 9 deletions src/cfnlint/data/schemas/other/template/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,7 @@
"Rules": {
"type": "object"
},
"Transform": {
"items": {
"type": "string"
},
"type": [
"string",
"array"
]
}
"Transform": {}
},
"required": [
"Resources"
Expand Down
Empty file.
38 changes: 38 additions & 0 deletions src/cfnlint/data/schemas/other/transforms/configuration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"additionalProperties": false,
"items": {
"$ref": "#/",
"type": [
"string",
"object"
]
},
"properties": {
"Name": {
"type": "string"
},
"Parameters": {
"patternProperties": {
".*": {
"type": [
"string",
"array",
"boolean",
"object",
"number",
"integer"
]
}
},
"type": "object"
}
},
"required": [
"Name"
],
"type": [
"string",
"array",
"object"
]
}
31 changes: 31 additions & 0 deletions src/cfnlint/rules/transforms/Configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: MIT-0
"""

from __future__ import annotations

import cfnlint.data.schemas.other.transforms
from cfnlint.rules.jsonschema.CfnLintJsonSchema import CfnLintJsonSchema, SchemaDetails


class Configuration(CfnLintJsonSchema):
"""Check if Parameters are configured correctly"""

id = "E1005"
shortdesc = "Validate Transform configuration"
description = (
"Validate that the transforms section of a template is properly configured"
)
source_url = "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/transform-section-structure.html"
tags = ["transform"]

def __init__(self):
"""Init"""
super().__init__(
keywords=["Transform"],
schema_details=SchemaDetails(
cfnlint.data.schemas.other.transforms, "configuration.json"
),
all_matches=True,
)
Empty file.
1 change: 1 addition & 0 deletions test/integration/test_schema_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class TestSchemaFiles(TestCase):
"Resources/*/Type",
"Resources/*/UpdatePolicy",
"Resources/*/UpdateReplacePolicy",
"Transform",
]

def setUp(self) -> None:
Expand Down
17 changes: 5 additions & 12 deletions test/unit/module/context/test_transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@
"name,instance,expected",
[
("Valid transforms", "AWS::LanguageExtensions", True),
("Valid transforms lists", ["AWS::LanguageExtensions"], True),
(
"Valid transforms lists",
["AWS::LanguageExtensions", {"Name": "Include"}],
True,
),
("Valid transforms lists", None, False),
("Valid transforms lists", "", False),
],
Expand All @@ -23,14 +27,3 @@ def test_transforms(name, instance, expected):
assert (
expected == transforms.has_language_extensions_transform()
), f"{name!r} test got {transforms.has_language_extensions_transform()}"


@pytest.mark.parametrize(
"name,instance",
[
("Invalid Type", {}),
],
)
def test_errors(name, instance):
with pytest.raises(ValueError):
Transforms(instance)
4 changes: 3 additions & 1 deletion test/unit/rules/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,7 @@ def helper_file_negative(self, filename, err_count, config=None):
self.assertEqual(
err_count,
len(failures),
"Expected {} failures but got {} on {}".format(0, failures, filename),
"Expected {} failures but got {} on {}".format(
err_count, failures, filename
),
)
4 changes: 2 additions & 2 deletions test/unit/rules/templates/test_base_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def test_file_negative(self):

def test_file_base(self):
"""Test failure"""
self.helper_file_negative("test/fixtures/templates/bad/templates/base.yaml", 2)
self.helper_file_negative("test/fixtures/templates/bad/templates/base.yaml", 1)

def test_file_base_date(self):
"""Test failure"""
Expand All @@ -51,5 +51,5 @@ def test_file_base_date(self):
def test_file_base_null(self):
"""Test failure"""
self.helper_file_negative(
"test/fixtures/templates/bad/templates/base_null.yaml", 3
"test/fixtures/templates/bad/templates/base_null.yaml", 2
)
Empty file.
95 changes: 95 additions & 0 deletions test/unit/rules/transforms/test_configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"""
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: MIT-0
"""

from collections import deque

import pytest

from cfnlint.jsonschema import ValidationError
from cfnlint.rules.transforms.Configuration import Configuration


@pytest.fixture(scope="module")
def rule():
rule = Configuration()
yield rule


@pytest.mark.parametrize(
"name,instance,expected",
[
(
"Empty list is ok",
[],
[],
),
(
"String is ok",
"Foo",
[],
),
(
"List is ok",
["Foo", "Bar"],
[],
),
(
"Object is ok",
{"Name": "Foo", "Parameters": {"Bar": "Test"}},
[],
),
(
"Array of objects is ok",
[
{"Name": "Foo", "Parameters": {"Bar": "Test"}},
"Foo",
],
[],
),
(
"Missing required Name",
{"Parameters": {"Bar": "Test"}},
[
ValidationError(
"'Name' is a required property",
validator="required",
rule=Configuration(),
path=deque([]),
schema_path=deque(["required"]),
)
],
),
(
"No additional property names are allowed",
{"Name": "Foo", "Foo": "Bar", "Parameters": {"Bar": "Test"}},
[
ValidationError(
"Additional properties are not allowed ('Foo' was unexpected)",
validator="additionalProperties",
rule=Configuration(),
path=deque(["Foo"]),
schema_path=deque(["additionalProperties"]),
)
],
),
(
"Null is not ok",
None,
[
ValidationError(
"None is not of type 'string', 'array', 'object'",
validator="type",
rule=Configuration(),
path=deque([]),
schema_path=deque(["type"]),
)
],
),
],
)
def test_validate(name, instance, expected, rule, validator):
errs = list(rule.validate(validator, {}, instance, {}))

assert errs == expected, f"Test {name!r} got {errs!r}"

0 comments on commit 78e9fa9

Please sign in to comment.