Skip to content

Commit 19e2f2e

Browse files
Profile Jinja Rendering, 1.5 Backport (#7653)
* Exclude some profile fields from Jinja rendering when they are not valid Jinja. (#7630) * CT-2583: Exclude some profile fields from Jinja rendering. * CT-2583: Add functional test. * CT-2583: Change approach to password jinja detection * CT-2583: Extract string constant and add additional checks * CT-2583: Improve unit test coverage * CT-2583: Update changelog entry to reflect new approach
1 parent 9804e67 commit 19e2f2e

File tree

3 files changed

+81
-1
lines changed

3 files changed

+81
-1
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
kind: Fixes
2+
body: Fall back if rendering the password field fails.
3+
time: 2023-05-15T14:28:51.400321-04:00
4+
custom:
5+
Author: peterallenwebb
6+
Issue: "7629"

core/dbt/config/renderer.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,17 @@ def render_value(self, value: Any, keypath: Optional[Keypath] = None) -> Any:
182182
# First, standard Jinja rendering, with special handling for 'secret' environment variables
183183
# "{{ env_var('DBT_SECRET_ENV_VAR') }}" -> "$$$DBT_SECRET_START$$$DBT_SECRET_ENV_{VARIABLE_NAME}$$$DBT_SECRET_END$$$"
184184
# This prevents Jinja manipulation of secrets via macros/filters that might leak partial/modified values in logs
185-
rendered = super().render_value(value, keypath)
185+
186+
try:
187+
rendered = super().render_value(value, keypath)
188+
except Exception as ex:
189+
if keypath and "password" in keypath:
190+
# Passwords sometimes contain jinja-esque characters, but we
191+
# don't want to render them if they aren't valid jinja.
192+
rendered = value
193+
else:
194+
raise ex
195+
186196
# Now, detect instances of the placeholder value ($$$DBT_SECRET_START...DBT_SECRET_END$$$)
187197
# and replace them with the actual secret value
188198
if SECRET_ENV_PREFIX in str(rendered):
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import pathlib
2+
from test_profile_dir import environ
3+
4+
from dbt.cli.main import dbtRunner
5+
6+
jinjaesque_password = "no{{jinja{%re{#ndering"
7+
8+
profile_with_jinjaesque_password = f"""test:
9+
outputs:
10+
default:
11+
dbname: my_db
12+
host: localhost
13+
password: {jinjaesque_password}
14+
port: 12345
15+
schema: dummy
16+
threads: 4
17+
type: postgres
18+
user: peter.webb
19+
target: default
20+
"""
21+
22+
profile_with_env_password = """test:
23+
outputs:
24+
default:
25+
dbname: my_db
26+
host: localhost
27+
password: "{{ env_var('DBT_PASSWORD') }}"
28+
port: 12345
29+
schema: dummy
30+
threads: 4
31+
type: postgres
32+
user: peter.webb
33+
target: default
34+
"""
35+
36+
37+
class TestProfileParsing:
38+
def write_profiles_yml(self, profiles_root, content) -> None:
39+
with open(pathlib.Path(profiles_root, "profiles.yml"), "w") as profiles_yml:
40+
profiles_yml.write(content)
41+
42+
def test_password_not_jinja_rendered_when_invalid(self, project, profiles_root) -> None:
43+
"""Verifies that passwords that contain Jinja control characters, but which are
44+
not valid Jinja, do not cause errors."""
45+
self.write_profiles_yml(profiles_root, profile_with_jinjaesque_password)
46+
47+
events = []
48+
result = dbtRunner(callbacks=[events.append]).invoke(["parse"])
49+
assert result.success
50+
51+
for e in events:
52+
assert "no{{jinja{%re{#ndering" not in e.info.msg
53+
54+
def test_password_jinja_rendered_when_valid(self, project, profiles_root) -> None:
55+
"""Verifies that a password value that is valid Jinja is rendered as such,
56+
and that it doesn't cause problems if the resulting value looks like Jinja"""
57+
self.write_profiles_yml(profiles_root, profile_with_env_password)
58+
59+
events = []
60+
with environ({"DBT_PASSWORD": jinjaesque_password}):
61+
result = dbtRunner(callbacks=[events.append]).invoke(["parse"])
62+
63+
assert result.success
64+
assert project.adapter.config.credentials.password == jinjaesque_password

0 commit comments

Comments
 (0)