Skip to content

Commit 19df57b

Browse files
amoghrajeshYour Name
authored and
Your Name
committed
[v3-0-test] Mask variable values in task logs only if the variable key is sensitive (#50775)
(cherry picked from commit 4f94f22) Co-authored-by: Amogh Desai <amoghrajesh1999@gmail.com>
1 parent 1cc5870 commit 19df57b

File tree

2 files changed

+62
-6
lines changed

2 files changed

+62
-6
lines changed

task-sdk/src/airflow/sdk/execution_time/supervisor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,7 @@ def _handle_request(self, msg: ToSupervisor, log: FilteringBoundLogger):
10341034
var = self.client.variables.get(msg.key)
10351035
if isinstance(var, VariableResponse):
10361036
if var.value:
1037-
mask_secret(var.value)
1037+
mask_secret(var.value, var.key)
10381038
var_result = VariableResult.from_variable_response(var)
10391039
resp = var_result
10401040
dump_opts = {"exclude_unset": True}

task-sdk/tests/task_sdk/execution_time/test_supervisor.py

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@
9292
VariableResult,
9393
XComResult,
9494
)
95-
from airflow.sdk.execution_time.secrets_masker import SecretsMasker
9695
from airflow.sdk.execution_time.supervisor import (
9796
BUFFER_SIZE,
9897
ActivitySubprocess,
@@ -977,9 +976,17 @@ def watched_subprocess(self, mocker):
977976

978977
return subprocess, read_end
979978

980-
@patch("airflow.sdk.execution_time.secrets_masker._secrets_masker")
979+
@patch("airflow.sdk.execution_time.supervisor.mask_secret")
981980
@pytest.mark.parametrize(
982-
["message", "expected_buffer", "client_attr_path", "method_arg", "method_kwarg", "mock_response"],
981+
[
982+
"message",
983+
"expected_buffer",
984+
"client_attr_path",
985+
"method_arg",
986+
"method_kwarg",
987+
"mock_response",
988+
"mask_secret_args",
989+
],
983990
[
984991
pytest.param(
985992
GetConnection(conn_id="test_conn"),
@@ -988,15 +995,27 @@ def watched_subprocess(self, mocker):
988995
("test_conn",),
989996
{},
990997
ConnectionResult(conn_id="test_conn", conn_type="mysql"),
998+
None,
991999
id="get_connection",
9921000
),
1001+
pytest.param(
1002+
GetConnection(conn_id="test_conn"),
1003+
b'{"conn_id":"test_conn","conn_type":"mysql","password":"password","type":"ConnectionResult"}\n',
1004+
"connections.get",
1005+
("test_conn",),
1006+
{},
1007+
ConnectionResult(conn_id="test_conn", conn_type="mysql", password="password"),
1008+
["password"],
1009+
id="get_connection_with_password",
1010+
),
9931011
pytest.param(
9941012
GetConnection(conn_id="test_conn"),
9951013
b'{"conn_id":"test_conn","conn_type":"mysql","schema":"mysql","type":"ConnectionResult"}\n',
9961014
"connections.get",
9971015
("test_conn",),
9981016
{},
9991017
ConnectionResult(conn_id="test_conn", conn_type="mysql", schema="mysql"), # type: ignore[call-arg]
1018+
None,
10001019
id="get_connection_with_alias",
10011020
),
10021021
pytest.param(
@@ -1006,6 +1025,7 @@ def watched_subprocess(self, mocker):
10061025
("test_key",),
10071026
{},
10081027
VariableResult(key="test_key", value="test_value"),
1028+
["test_value", "test_key"],
10091029
id="get_variable",
10101030
),
10111031
pytest.param(
@@ -1015,6 +1035,7 @@ def watched_subprocess(self, mocker):
10151035
("test_key", "test_value", "test_description"),
10161036
{},
10171037
OKResponse(ok=True),
1038+
None,
10181039
id="set_variable",
10191040
),
10201041
pytest.param(
@@ -1024,6 +1045,7 @@ def watched_subprocess(self, mocker):
10241045
("test_key",),
10251046
{},
10261047
OKResponse(ok=True),
1048+
None,
10271049
id="delete_variable",
10281050
),
10291051
pytest.param(
@@ -1033,6 +1055,7 @@ def watched_subprocess(self, mocker):
10331055
(TI_ID, DeferTask(next_method="execute_callback", classpath="my-classpath")),
10341056
{},
10351057
"",
1058+
None,
10361059
id="patch_task_instance_to_deferred",
10371060
),
10381061
pytest.param(
@@ -1051,6 +1074,7 @@ def watched_subprocess(self, mocker):
10511074
),
10521075
{},
10531076
"",
1077+
None,
10541078
id="patch_task_instance_to_up_for_reschedule",
10551079
),
10561080
pytest.param(
@@ -1060,6 +1084,7 @@ def watched_subprocess(self, mocker):
10601084
("test_dag", "test_run", "test_task", "test_key", None, False),
10611085
{},
10621086
XComResult(key="test_key", value="test_value"),
1087+
None,
10631088
id="get_xcom",
10641089
),
10651090
pytest.param(
@@ -1071,6 +1096,7 @@ def watched_subprocess(self, mocker):
10711096
("test_dag", "test_run", "test_task", "test_key", 2, False),
10721097
{},
10731098
XComResult(key="test_key", value="test_value"),
1099+
None,
10741100
id="get_xcom_map_index",
10751101
),
10761102
pytest.param(
@@ -1080,6 +1106,7 @@ def watched_subprocess(self, mocker):
10801106
("test_dag", "test_run", "test_task", "test_key", None, False),
10811107
{},
10821108
XComResult(key="test_key", value=None, type="XComResult"),
1109+
None,
10831110
id="get_xcom_not_found",
10841111
),
10851112
pytest.param(
@@ -1095,6 +1122,7 @@ def watched_subprocess(self, mocker):
10951122
("test_dag", "test_run", "test_task", "test_key", None, True),
10961123
{},
10971124
XComResult(key="test_key", value=None, type="XComResult"),
1125+
None,
10981126
id="get_xcom_include_prior_dates",
10991127
),
11001128
pytest.param(
@@ -1118,6 +1146,7 @@ def watched_subprocess(self, mocker):
11181146
),
11191147
{},
11201148
OKResponse(ok=True),
1149+
None,
11211150
id="set_xcom",
11221151
),
11231152
pytest.param(
@@ -1142,6 +1171,7 @@ def watched_subprocess(self, mocker):
11421171
),
11431172
{},
11441173
OKResponse(ok=True),
1174+
None,
11451175
id="set_xcom_with_map_index",
11461176
),
11471177
pytest.param(
@@ -1167,6 +1197,7 @@ def watched_subprocess(self, mocker):
11671197
),
11681198
{},
11691199
OKResponse(ok=True),
1200+
None,
11701201
id="set_xcom_with_map_index_and_mapped_length",
11711202
),
11721203
pytest.param(
@@ -1188,6 +1219,7 @@ def watched_subprocess(self, mocker):
11881219
),
11891220
{},
11901221
OKResponse(ok=True),
1222+
None,
11911223
id="delete_xcom",
11921224
),
11931225
# we aren't adding all states under TaskInstanceState here, because this test's scope is only to check
@@ -1199,6 +1231,7 @@ def watched_subprocess(self, mocker):
11991231
(),
12001232
{},
12011233
"",
1234+
None,
12021235
id="patch_task_instance_to_skipped",
12031236
),
12041237
pytest.param(
@@ -1214,6 +1247,7 @@ def watched_subprocess(self, mocker):
12141247
"rendered_map_index": "test retry task",
12151248
},
12161249
"",
1250+
None,
12171251
id="up_for_retry",
12181252
),
12191253
pytest.param(
@@ -1223,6 +1257,7 @@ def watched_subprocess(self, mocker):
12231257
(TI_ID, {"field1": "rendered_value1", "field2": "rendered_value2"}),
12241258
{},
12251259
OKResponse(ok=True),
1260+
None,
12261261
id="set_rtif",
12271262
),
12281263
pytest.param(
@@ -1232,6 +1267,7 @@ def watched_subprocess(self, mocker):
12321267
[],
12331268
{"name": "asset"},
12341269
AssetResult(name="asset", uri="s3://bucket/obj", group="asset"),
1270+
None,
12351271
id="get_asset_by_name",
12361272
),
12371273
pytest.param(
@@ -1241,6 +1277,7 @@ def watched_subprocess(self, mocker):
12411277
[],
12421278
{"uri": "s3://bucket/obj"},
12431279
AssetResult(name="asset", uri="s3://bucket/obj", group="asset"),
1280+
None,
12441281
id="get_asset_by_uri",
12451282
),
12461283
pytest.param(
@@ -1263,6 +1300,7 @@ def watched_subprocess(self, mocker):
12631300
)
12641301
]
12651302
),
1303+
None,
12661304
id="get_asset_events_by_uri_and_name",
12671305
),
12681306
pytest.param(
@@ -1285,6 +1323,7 @@ def watched_subprocess(self, mocker):
12851323
)
12861324
]
12871325
),
1326+
None,
12881327
id="get_asset_events_by_uri",
12891328
),
12901329
pytest.param(
@@ -1307,6 +1346,7 @@ def watched_subprocess(self, mocker):
13071346
)
13081347
]
13091348
),
1349+
None,
13101350
id="get_asset_events_by_name",
13111351
),
13121352
pytest.param(
@@ -1329,6 +1369,7 @@ def watched_subprocess(self, mocker):
13291369
)
13301370
]
13311371
),
1372+
None,
13321373
id="get_asset_events_by_asset_alias",
13331374
),
13341375
pytest.param(
@@ -1346,6 +1387,7 @@ def watched_subprocess(self, mocker):
13461387
"rendered_map_index": "test success task",
13471388
},
13481389
"",
1390+
None,
13491391
id="succeed_task",
13501392
),
13511393
pytest.param(
@@ -1364,6 +1406,7 @@ def watched_subprocess(self, mocker):
13641406
data_interval_start=timezone.parse("2025-01-10T12:00:00Z"),
13651407
data_interval_end=timezone.parse("2025-01-10T14:00:00Z"),
13661408
),
1409+
None,
13671410
id="get_prev_successful_dagrun",
13681411
),
13691412
pytest.param(
@@ -1379,6 +1422,7 @@ def watched_subprocess(self, mocker):
13791422
("test_dag", "test_run", {"key": "value"}, timezone.datetime(2025, 1, 1), True),
13801423
{},
13811424
OKResponse(ok=True),
1425+
None,
13821426
id="dag_run_trigger",
13831427
),
13841428
pytest.param(
@@ -1388,6 +1432,7 @@ def watched_subprocess(self, mocker):
13881432
("test_dag", "test_run", None, None, False),
13891433
{},
13901434
ErrorResponse(error=ErrorType.DAGRUN_ALREADY_EXISTS),
1435+
None,
13911436
id="dag_run_trigger_already_exists",
13921437
),
13931438
pytest.param(
@@ -1397,6 +1442,7 @@ def watched_subprocess(self, mocker):
13971442
("test_dag", "test_run"),
13981443
{},
13991444
DagRunStateResult(state=DagRunState.RUNNING),
1445+
None,
14001446
id="get_dag_run_state",
14011447
),
14021448
pytest.param(
@@ -1406,6 +1452,7 @@ def watched_subprocess(self, mocker):
14061452
(TI_ID, 1),
14071453
{},
14081454
TaskRescheduleStartDate(start_date=timezone.parse("2024-10-31T12:00:00Z")),
1455+
None,
14091456
id="get_task_reschedule_start_date",
14101457
),
14111458
pytest.param(
@@ -1423,6 +1470,7 @@ def watched_subprocess(self, mocker):
14231470
"task_ids": ["task1", "task2"],
14241471
},
14251472
TICount(count=2),
1473+
None,
14261474
id="get_ti_count",
14271475
),
14281476
pytest.param(
@@ -1437,6 +1485,7 @@ def watched_subprocess(self, mocker):
14371485
"states": ["success", "failed"],
14381486
},
14391487
DRCount(count=2),
1488+
None,
14401489
id="get_dr_count",
14411490
),
14421491
pytest.param(
@@ -1453,6 +1502,7 @@ def watched_subprocess(self, mocker):
14531502
"task_group_id": "test_group",
14541503
},
14551504
TaskStatesResult(task_states={"run_id": {"task1": "success", "task2": "failed"}}),
1505+
None,
14561506
id="get_task_states",
14571507
),
14581508
pytest.param(
@@ -1468,6 +1518,7 @@ def watched_subprocess(self, mocker):
14681518
("test_dag", "test_run", "test_task", "test_key", 0),
14691519
{},
14701520
XComResult(key="test_key", value="test_value"),
1521+
None,
14711522
id="get_xcom_seq_item",
14721523
),
14731524
pytest.param(
@@ -1483,13 +1534,14 @@ def watched_subprocess(self, mocker):
14831534
("test_dag", "test_run", "test_task", "test_key", 2),
14841535
{},
14851536
ErrorResponse(error=ErrorType.XCOM_NOT_FOUND),
1537+
None,
14861538
id="get_xcom_seq_item_not_found",
14871539
),
14881540
],
14891541
)
14901542
def test_handle_requests(
14911543
self,
1492-
mock_secrets_masker,
1544+
mock_mask_secret,
14931545
watched_subprocess,
14941546
mocker,
14951547
time_machine,
@@ -1499,6 +1551,7 @@ def test_handle_requests(
14991551
method_arg,
15001552
method_kwarg,
15011553
mock_response,
1554+
mask_secret_args,
15021555
):
15031556
"""
15041557
Test handling of different messages to the subprocess. For any new message type, add a
@@ -1511,7 +1564,6 @@ def test_handle_requests(
15111564
3. Checks that the buffer is updated with the expected response.
15121565
4. Verifies that the response is correctly decoded.
15131566
"""
1514-
mock_secrets_masker.return_value = SecretsMasker()
15151567
watched_subprocess, read_socket = watched_subprocess
15161568

15171569
# Mock the client method. E.g. `client.variables.get` or `client.connections.get`
@@ -1524,6 +1576,10 @@ def test_handle_requests(
15241576
next(generator)
15251577
msg = message.model_dump_json().encode() + b"\n"
15261578
generator.send(msg)
1579+
1580+
if mask_secret_args:
1581+
mock_mask_secret.assert_called_with(*mask_secret_args)
1582+
15271583
time_machine.move_to(timezone.datetime(2024, 10, 31), tick=False)
15281584

15291585
# Verify the correct client method was called

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy