This is an automated email from the ASF dual-hosted git repository.

bugraoz 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 9d83ec938c0 Add test for sensitive config masking in airflowctl 
(#60361)
9d83ec938c0 is described below

commit 9d83ec938c0cfea4b1ea2d39ff93f8722812e2f8
Author: Subham <[email protected]>
AuthorDate: Sat Jan 31 23:30:47 2026 +0530

    Add test for sensitive config masking in airflowctl (#60361)
    
    * Add unittest to add a mechanism if adding to airflowctl preserves the 
API's sensitive config masking
---
 .../tests/airflow_ctl/api/test_operations.py       | 26 +++++++++++
 .../ctl/commands/test_config_command.py            | 50 ++++++++++++++++++++++
 2 files changed, 76 insertions(+)

diff --git a/airflow-ctl/tests/airflow_ctl/api/test_operations.py 
b/airflow-ctl/tests/airflow_ctl/api/test_operations.py
index 4e8c0ab7590..bb473dbc7d1 100644
--- a/airflow-ctl/tests/airflow_ctl/api/test_operations.py
+++ b/airflow-ctl/tests/airflow_ctl/api/test_operations.py
@@ -522,6 +522,32 @@ class TestConfigOperations:
         response = client.configs.list()
         assert response == response_config
 
+    def test_get_masked_value(self):
+        """Verify that masked values from API are preserved in get() 
operation."""
+        response_config = Config(
+            sections=[
+                ConfigSection(
+                    name=self.section,
+                    options=[
+                        ConfigOption(
+                            key="sensitive_key",
+                            value="< hidden >",
+                        )
+                    ],
+                )
+            ]
+        )
+
+        def handle_request(request: httpx.Request) -> httpx.Response:
+            assert request.url.path == 
f"/api/v2/config/section/{self.section}/option/sensitive_key"
+            return httpx.Response(200, json=response_config.model_dump())
+
+        client = make_api_client(transport=httpx.MockTransport(handle_request))
+        response = client.configs.get(section=self.section, 
option="sensitive_key")
+
+        assert response == response_config
+        assert response.sections[0].options[0].value == "< hidden >"
+
 
 class TestConnectionsOperations:
     connection_id: str = "test_connection"
diff --git a/airflow-ctl/tests/airflow_ctl/ctl/commands/test_config_command.py 
b/airflow-ctl/tests/airflow_ctl/ctl/commands/test_config_command.py
index f87a9851a52..731e30137c7 100644
--- a/airflow-ctl/tests/airflow_ctl/ctl/commands/test_config_command.py
+++ b/airflow-ctl/tests/airflow_ctl/ctl/commands/test_config_command.py
@@ -361,3 +361,53 @@ class TestCliConfigCommands:
         calls = [call[0][0] for call in mock_rich_print.call_args_list]
         assert "[red]Found issues in your airflow.cfg:[/red]" in calls[0]
         assert "This is a test suggestion." in calls[1]
+
+    @patch("airflowctl.api.client.Credentials.load")
+    @patch.dict(os.environ, {"AIRFLOW_CLI_TOKEN": "TEST_TOKEN"})
+    @patch.dict(os.environ, {"AIRFLOW_CLI_ENVIRONMENT": "TEST_CONFIG"})
+    @patch("rich.print")
+    def test_config_list_masking_preservation(
+        self, mock_rich_print, _mock_credentials, api_client_maker, capsys
+    ):
+        """
+        Verify that sensitive values masked by the API (like '< hidden >') are 
preserved
+        and displayed correctly by the CLI list command.
+        """
+        response_config = Config(
+            sections=[
+                ConfigSection(
+                    name="core",
+                    options=[
+                        ConfigOption(key="parallelism", value="32"),
+                        ConfigOption(key="fernet_key", value="< hidden >"),
+                    ],
+                ),
+                ConfigSection(
+                    name="database",
+                    options=[
+                        ConfigOption(key="sql_alchemy_conn", value="< hidden 
>"),
+                    ],
+                ),
+            ]
+        )
+
+        api_client = api_client_maker(
+            path="/api/v2/config",
+            response_json=response_config.model_dump(),
+            expected_http_status_code=200,
+            kind=ClientKind.CLI,
+        )
+        args = self.parser.parse_args(["config", "list"])
+        args.func(
+            args,
+            api_client=api_client,
+        )
+
+        # Output is printed to stdout by AirflowConsole (using rich)
+        captured = capsys.readouterr()
+        output_str = captured.out
+
+        # Check output contains masked vales
+        assert "fernet_key" in output_str
+        assert "< hidden >" in output_str
+        assert "sql_alchemy_conn" in output_str

Reply via email to