Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion checkov/cloudformation/context_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,12 @@ def search_deep_keys(
return keys

def _set_in_dict(self, data_dict: dict[str, Any], map_list: list[Any], value: str) -> None:
v = self._get_from_dict(data_dict, map_list[:-1])
try:
v = self._get_from_dict(data_dict, map_list[:-1])
except TypeError:
# A previous substitution replaced a dict in this path with a scalar value,
# so this path is no longer traversable. Skip this substitution.
return
# save the original marks so that we do not copy in the line numbers of the parameter element
# but not all ref types will have these attributes
start = None
Expand Down
24 changes: 24 additions & 0 deletions tests/cloudformation/parser/cfn_nested_findinmap_ref.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
LambdaMemorySize:
Type: Number
Default: 1024
CacheSizeLimit:
Type: Number
Default: 100
Mappings:
MemoryMap:
us-east-1:
size: 512
Resources:
MyFunction:
Type: AWS::Lambda::Function
Properties:
Runtime: python3.12
Handler: index.handler
MemorySize:
Ref: LambdaMemorySize
Fn::FindInMap:
- MemoryMap
- Ref: CacheSizeLimit
- size
20 changes: 20 additions & 0 deletions tests/cloudformation/parser/test_cfn_yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,26 @@ def test_parsing_error(self):
self.assertEqual(summary['skipped'], 0)
self.assertEqual(summary['parsing_errors'], 2)

def test_set_in_dict_skips_when_path_replaced_by_scalar(self):
"""_set_in_dict should not crash when a prior ref substitution replaced a dict with a scalar."""
current_dir = os.path.dirname(os.path.realpath(__file__))
file = f'{current_dir}/cfn_nested_findinmap_ref.yaml'
definitions, definitions_raw = parse(file)
cf_context_parser = ContextParser(file, definitions, definitions_raw)

# Simulate the state after graph conversion injects a phantom Ref as a sibling
# to Fn::FindInMap, and a prior substitution replaces the parent dict with a scalar.
# evaluate_default_refs finds all Ref paths upfront, then iterates. If an earlier
# substitution replaces a dict with a scalar (e.g., Number default), later paths
# through that dict become invalid.
cf_context_parser.cf_template["Resources"]["MyFunction"]["Properties"]["MemorySize"] = 1024
# This path would have been valid before the substitution above
cf_context_parser._set_in_dict(
cf_context_parser.cf_template,
["Resources", "MyFunction", "Properties", "MemorySize", "Fn::FindInMap", 1],
"100"
)


if __name__ == '__main__':
unittest.main()
Loading