Skip to content

Commit 743f4b9

Browse files
tirkarthiephraimbuddy
authored andcommitted
Fix secrets rendered in UI when task is not executed. (#22754)
(cherry picked from commit ce8ea66)
1 parent 54e5ce2 commit 743f4b9

File tree

2 files changed

+53
-4
lines changed

2 files changed

+53
-4
lines changed

airflow/models/taskinstance.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2162,15 +2162,27 @@ def get_rendered_template_fields(self, session: Session = NEW_SESSION) -> None:
21622162
for field_name, rendered_value in rendered_task_instance_fields.items():
21632163
setattr(self.task, field_name, rendered_value)
21642164
return
2165+
21652166
try:
2166-
self.render_templates()
2167+
# Task was never executed. Initialize RenderedTaskInstanceFields
2168+
# to render template and mask secrets. Set MASK_SECRETS_IN_LOGS
2169+
# to True to enable masking similar to task run.
2170+
original_value = settings.MASK_SECRETS_IN_LOGS
2171+
settings.MASK_SECRETS_IN_LOGS = True
2172+
rendered_task_instance = RenderedTaskInstanceFields(self)
2173+
rendered_fields = rendered_task_instance.rendered_fields
2174+
if rendered_fields:
2175+
for field_name, rendered_value in rendered_fields.items():
2176+
setattr(self.task, field_name, rendered_value)
21672177
except (TemplateAssertionError, UndefinedError) as e:
21682178
raise AirflowException(
21692179
"Webserver does not have access to User-defined Macros or Filters "
21702180
"when Dag Serialization is enabled. Hence for the task that have not yet "
21712181
"started running, please use 'airflow tasks render' for debugging the "
21722182
"rendering of template_fields."
21732183
) from e
2184+
finally:
2185+
settings.MASK_SECRETS_IN_LOGS = original_value
21742186

21752187
@provide_session
21762188
def get_rendered_k8s_spec(self, session=NEW_SESSION):

tests/www/views/test_views_rendered.py

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
import pytest
2222

23-
from airflow.models import DAG, RenderedTaskInstanceFields
23+
from airflow.models import DAG, RenderedTaskInstanceFields, Variable
2424
from airflow.operators.bash import BashOperator
2525
from airflow.serialization.serialized_objects import SerializedDAG
2626
from airflow.utils import timezone
@@ -61,6 +61,15 @@ def task2(dag):
6161
)
6262

6363

64+
@pytest.fixture()
65+
def task_secret(dag):
66+
return BashOperator(
67+
task_id='task_secret',
68+
bash_command='echo {{ var.value.my_secret }} && echo {{ var.value.spam }}',
69+
dag=dag,
70+
)
71+
72+
6473
@pytest.fixture(scope="module", autouse=True)
6574
def init_blank_db():
6675
"""Make sure there are no runs before we test anything.
@@ -73,15 +82,15 @@ def init_blank_db():
7382

7483

7584
@pytest.fixture(autouse=True)
76-
def reset_db(dag, task1, task2):
85+
def reset_db(dag, task1, task2, task_secret):
7786
yield
7887
clear_db_dags()
7988
clear_db_runs()
8089
clear_rendered_ti_fields()
8190

8291

8392
@pytest.fixture()
84-
def create_dag_run(dag, task1, task2):
93+
def create_dag_run(dag, task1, task2, task_secret):
8594
def _create_dag_run(*, execution_date, session):
8695
dag_run = dag.create_dagrun(
8796
state=DagRunState.RUNNING,
@@ -94,6 +103,8 @@ def _create_dag_run(*, execution_date, session):
94103
ti1.state = TaskInstanceState.SUCCESS
95104
ti2 = dag_run.get_task_instance(task2.task_id, session=session)
96105
ti2.state = TaskInstanceState.SCHEDULED
106+
ti3 = dag_run.get_task_instance(task_secret.task_id, session=session)
107+
ti3.state = TaskInstanceState.QUEUED
97108
session.flush()
98109
return dag_run
99110

@@ -168,3 +179,29 @@ def test_user_defined_filter_and_macros_raise_error(admin_client, create_dag_run
168179
# MarkupSafe changed the exception detail from 'no filter named' to
169180
# 'No filter named' in 2.0 (I think), so we normalize for comparison.
170181
assert "originalerror: no filter named 'hello'" in resp_html.lower()
182+
183+
184+
@pytest.mark.usefixtures("patch_app")
185+
def test_rendered_template_secret(admin_client, create_dag_run, task_secret):
186+
"""Test that the Rendered View masks values retrieved from secret variables."""
187+
Variable.set("my_secret", "foo")
188+
Variable.set("spam", "egg")
189+
190+
assert task_secret.bash_command == 'echo {{ var.value.my_secret }} && echo {{ var.value.spam }}'
191+
192+
with create_session() as session:
193+
dag_run = create_dag_run(execution_date=DEFAULT_DATE, session=session)
194+
ti = dag_run.get_task_instance(task_secret.task_id, session=session)
195+
assert ti is not None, "task instance not found"
196+
ti.refresh_from_task(task_secret)
197+
assert ti.state == TaskInstanceState.QUEUED
198+
199+
date = quote_plus(str(DEFAULT_DATE))
200+
url = f'rendered-templates?task_id=task_secret&dag_id=testdag&execution_date={date}'
201+
202+
resp = admin_client.get(url, follow_redirects=True)
203+
check_content_in_response(
204+
'echo</span> *** <span class="o">&amp;&amp;</span> <span class="nb">echo</span> egg', resp
205+
)
206+
ti.refresh_from_task(task_secret)
207+
assert ti.state == TaskInstanceState.QUEUED

0 commit comments

Comments
 (0)