Skip to content

Commit c7febb4

Browse files
potiukshubhamraj-git
authored andcommitted
Better handling masking of values of set variable (#43123) (#43278)
(cherry picked from commit 1260d9c) Co-authored-by: Shubham Raj <[email protected]>
1 parent 1939daa commit c7febb4

File tree

2 files changed

+51
-2
lines changed

2 files changed

+51
-2
lines changed

airflow/utils/cli.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
from airflow.exceptions import AirflowException, RemovedInAirflow3Warning
4040
from airflow.utils import cli_action_loggers, timezone
4141
from airflow.utils.log.non_caching_file_handler import NonCachingFileHandler
42+
from airflow.utils.log.secrets_masker import should_hide_value_for_key
4243
from airflow.utils.platform import getuser, is_terminal_support_colors
4344
from airflow.utils.session import NEW_SESSION, provide_session
4445

@@ -139,11 +140,18 @@ def _build_metrics(func_name, namespace):
139140
:param namespace: Namespace instance from argparse
140141
:return: dict with metrics
141142
"""
142-
sub_commands_to_check = {"users", "connections"}
143+
sub_commands_to_check_for_sensitive_fields = {"users", "connections"}
144+
sub_commands_to_check_for_sensitive_key = {"variables"}
143145
sensitive_fields = {"-p", "--password", "--conn-password"}
144146
full_command = list(sys.argv)
145147
sub_command = full_command[1] if len(full_command) > 1 else None
146-
if sub_command in sub_commands_to_check:
148+
# For cases when value under sub_commands_to_check_for_sensitive_key have sensitive info
149+
if sub_command in sub_commands_to_check_for_sensitive_key:
150+
key = full_command[-2] if len(full_command) > 3 else None
151+
if key and should_hide_value_for_key(key):
152+
# Mask the sensitive value since key contain sensitive keyword
153+
full_command[-1] = "*" * 8
154+
elif sub_command in sub_commands_to_check_for_sensitive_fields:
147155
for idx, command in enumerate(full_command):
148156
if command in sensitive_fields:
149157
# For cases when password is passed as "--password xyz" (with space between key and value)

tests/utils/test_cli_util.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,47 @@ def test_get_dag_by_pickle(self, session, dag_maker):
188188
with pytest.raises(AirflowException, match="pickle_id could not be found .* -42"):
189189
get_dag_by_pickle(pickle_id=-42, session=session)
190190

191+
@pytest.mark.parametrize(
192+
["given_command", "expected_masked_command"],
193+
[
194+
(
195+
"airflow variables set --description 'needed for dag 4' client_secret_234 7fh4375f5gy353wdf",
196+
"airflow variables set --description 'needed for dag 4' client_secret_234 ********",
197+
),
198+
(
199+
"airflow variables set cust_secret_234 7fh4375f5gy353wdf",
200+
"airflow variables set cust_secret_234 ********",
201+
),
202+
],
203+
)
204+
def test_cli_set_variable_supplied_sensitive_value_is_masked(
205+
self, given_command, expected_masked_command, session
206+
):
207+
args = given_command.split()
208+
209+
expected_command = expected_masked_command.split()
210+
211+
exec_date = timezone.utcnow()
212+
namespace = Namespace(dag_id="foo", task_id="bar", subcommand="test", execution_date=exec_date)
213+
with mock.patch.object(sys, "argv", args), mock.patch(
214+
"airflow.utils.session.create_session"
215+
) as mock_create_session:
216+
metrics = cli._build_metrics(args[1], namespace)
217+
# Make it so the default_action_log doesn't actually commit the txn, by giving it a next txn
218+
# instead
219+
mock_create_session.return_value = session.begin_nested()
220+
mock_create_session.return_value.bulk_insert_mappings = session.bulk_insert_mappings
221+
cli_action_loggers.default_action_log(**metrics)
222+
223+
log = session.query(Log).order_by(Log.dttm.desc()).first()
224+
225+
assert metrics.get("start_datetime") <= timezone.utcnow()
226+
227+
command: str = json.loads(log.extra).get("full_command")
228+
# Replace single quotes to double quotes to avoid json decode error
229+
command = ast.literal_eval(command)
230+
assert command == expected_command
231+
191232

192233
@contextmanager
193234
def fail_action_logger_callback():

0 commit comments

Comments
 (0)