Skip to content

Commit

Permalink
[Resolve #937] Reset Jinja2 variable cache between config files (#1472)
Browse files Browse the repository at this point in the history
From https://github.com/NathanWilliams

I am adopting this stale PR:
#938

---

Fix for: #937

This resets the Jinja2 templating_vars in config/reader.py to prevent variables leaking across StackGroups.

Without this patch applied, the test case added would fail and show param1 from stack_group_config1 has leaked into stack_group2:

```
E             Full diff:
E               {
E                'j2_environment': {},
E             -  'param1': 'value1',
E                'param2': 'value2',
E                'var': 'initial_value',
E               }
```

Nathan's fix is shown to prevent this unintended behaviour.
  • Loading branch information
alex-harvey-z3q authored Jun 20, 2024
1 parent 0adec0b commit 20801f8
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 0 deletions.
8 changes: 8 additions & 0 deletions sceptre/config/reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,14 @@ def _render(self, directory_path, basename, stack_group_config):
f"{Path(directory_path, basename).as_posix()} - {err}"
) from err

# Reset the template cache to avoid leakage between StackGroups (#937)
template_vars = {"var": self.templating_vars["var"]}
if "stack_group_config" in self.templating_vars:
template_vars["stack_group_config"] = self.templating_vars[
"stack_group_config"
]
self.templating_vars = template_vars

self.templating_vars.update(stack_group_config)

try:
Expand Down
59 changes: 59 additions & 0 deletions tests/test_config_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,65 @@ def test_render__existing_config_file__returns_dict(self):

assert result == {"key": "value"}

def test_render__existing_config_file__no_leak_between_multiple_stack_group_configs(
self,
):
"""A test for bug #937"""
with self.runner.isolated_filesystem():
project_path = os.path.abspath("./example")

self.context.project_path = project_path

config_dir = os.path.join(project_path, "config")

stack_group_config_1 = {"j2_environment": {}, "param1": "value1"}
stack_group_config_2 = {"j2_environment": {}, "param2": "value2"}

directory_path_1 = os.path.join(config_dir, "dir1")
directory_path_2 = os.path.join(config_dir, "dir2")
os.makedirs(directory_path_1)
os.makedirs(directory_path_2)

config_reader = ConfigReader(self.context)

# First config file
basename_1 = "file1.yaml"
test_config_path_1 = os.path.join(directory_path_1, basename_1)
test_config_content_1 = "var: initial_value\nparam1: value1"
with open(test_config_path_1, "w") as file:
file.write(test_config_content_1)

# Second config file
basename_2 = "file2.yaml"
test_config_path_2 = os.path.join(directory_path_2, basename_2)
test_config_content_2 = "var: initial_value\nparam2: value2"
with open(test_config_path_2, "w") as file:
file.write(test_config_content_2)

config_reader.full_config_path = project_path
config_reader.templating_vars = {"var": "initial_value"}

# Run _render for the first stack group
result_1 = config_reader._render(
"config/dir1", basename_1, stack_group_config_1
)
expected_result_1 = {"var": "initial_value", "param1": "value1"}
assert expected_result_1 == result_1

# Run _render for the second stack group
result_2 = config_reader._render(
"config/dir2", basename_2, stack_group_config_2
)
expected_result_2 = {"var": "initial_value", "param2": "value2"}
assert expected_result_2 == result_2

# Ensure the templating_vars is not leaking
assert {
"var": "initial_value",
"j2_environment": {},
"param2": "value2",
} == config_reader.templating_vars

def test_render__invalid_jinja_template__raises_and_creates_debug_file(self):
with self.runner.isolated_filesystem():
project_path = os.path.abspath("./example")
Expand Down

0 comments on commit 20801f8

Please sign in to comment.