This is an automated email from the ASF dual-hosted git repository.
amoghdesai pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new afa5bff62a7 Add secret masking for Jinja template rendering exceptions
(#57467)
afa5bff62a7 is described below
commit afa5bff62a77f217aeebdf492b6745e36bc5b6ad
Author: Ankit Chaurasia <[email protected]>
AuthorDate: Thu Nov 6 17:43:25 2025 +0545
Add secret masking for Jinja template rendering exceptions (#57467)
---
.../sdk/definitions/_internal/abstractoperator.py | 7 ++++--
task-sdk/tests/task_sdk/bases/test_operator.py | 25 ++++++++++++++++++++++
2 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/task-sdk/src/airflow/sdk/definitions/_internal/abstractoperator.py
b/task-sdk/src/airflow/sdk/definitions/_internal/abstractoperator.py
index ac93e51e8bc..56a50159f14 100644
--- a/task-sdk/src/airflow/sdk/definitions/_internal/abstractoperator.py
+++ b/task-sdk/src/airflow/sdk/definitions/_internal/abstractoperator.py
@@ -304,12 +304,15 @@ class AbstractOperator(Templater, DAGNode):
else:
rendered_content = self.render_template(value, context,
jinja_env, seen_oids)
except Exception:
- # TODO: Mask the value. Depends on
https://github.com/apache/airflow/issues/45438
+ # Mask sensitive values in the template before logging
+ from airflow.sdk._shared.secrets_masker import redact
+
+ masked_value = redact(value)
log.exception(
"Exception rendering Jinja template for task '%s', field
'%s'. Template: %r",
self.task_id,
attr_name,
- value,
+ masked_value,
)
raise
else:
diff --git a/task-sdk/tests/task_sdk/bases/test_operator.py
b/task-sdk/tests/task_sdk/bases/test_operator.py
index c08c6fd0760..d5bd22a5a95 100644
--- a/task-sdk/tests/task_sdk/bases/test_operator.py
+++ b/task-sdk/tests/task_sdk/bases/test_operator.py
@@ -30,6 +30,7 @@ import pytest
import structlog
from airflow.sdk import task as task_decorator
+from airflow.sdk._shared.secrets_masker import _secrets_masker, mask_secret
from airflow.sdk.bases.operator import (
BaseOperator,
BaseOperatorMeta,
@@ -923,6 +924,30 @@ def test_render_template_fields_logging(
assert not_expected_log not in caplog.text
[email protected]_redact
+def test_render_template_fields_secret_masking(caplog):
+ """Test that sensitive values are masked in Jinja template rendering
exceptions."""
+ masker = _secrets_masker()
+ masker.reset_masker()
+
+ masker.sensitive_variables_fields = ["password", "secret", "token"]
+
+ mask_secret("mysecretpassword", "password")
+
+ task = MockOperator(task_id="op1", arg1="{{ password + 1 }}")
+ context = {"password": "mysecretpassword"}
+
+ with (
+ pytest.raises(TypeError),
+ caplog.at_level(logging.ERROR,
logger="airflow.sdk.definitions.templater"),
+ ):
+ task.render_template_fields(context=context)
+
+ assert "mysecretpassword" not in caplog.text
+ assert "Template: '{{ password + 1 }}'" in caplog.text
+ assert "Exception rendering Jinja template for task 'op1', field 'arg1'"
in caplog.text
+
+
class HelloWorldOperator(BaseOperator):
log = structlog.get_logger(__name__)