This is an automated email from the ASF dual-hosted git repository.
potiuk 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 4eb6170143d [api] Add logic redacted sensitive fields via the Public
API and UI (#59873)
4eb6170143d is described below
commit 4eb6170143d566920b8db508fc1fa50a9db18755
Author: nhuantho <[email protected]>
AuthorDate: Tue Jan 6 06:41:47 2026 +0700
[api] Add logic redacted sensitive fields via the Public API and UI (#59873)
* Marked sensitive value in config API
* Ignore tuple type
* Marked sensitive value in Connection UI API
* Fix mypy
* Fix ruff check
* fix redact_value of ConfigOption
* Fix mypy
* Add a test with dict value inclue sensitive and normal fields
* Fix logic after pr 59880
* Remove print in test_connections.py
---------
Co-authored-by: nhuan.bc <[email protected]>
Co-authored-by: Jason(Zhe-You) Liu
<[email protected]>
---
.../api_fastapi/core_api/datamodels/connections.py | 8 ++++
.../core_api/routes/ui/test_connections.py | 50 ++++++++++++++++++++++
2 files changed, 58 insertions(+)
diff --git
a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/connections.py
b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/connections.py
index ee22c09d116..dcb8be63a87 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/datamodels/connections.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/datamodels/connections.py
@@ -123,6 +123,14 @@ class ConnectionHookMetaData(BaseModel):
standard_fields: StandardHookFields | None
extra_fields: Mapping | None
+ @field_validator("extra_fields", mode="after")
+ @classmethod
+ def redact_extra_fields(cls, v: Mapping | None):
+ if v is None:
+ return None
+
+ return redact(v)
+
# Request Models
class ConnectionBody(StrictBaseModel):
diff --git
a/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_connections.py
b/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_connections.py
index 52b624108eb..f354e172137 100644
--- a/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_connections.py
+++ b/airflow-core/tests/unit/api_fastapi/core_api/routes/ui/test_connections.py
@@ -16,8 +16,16 @@
# under the License.
from __future__ import annotations
+from unittest import mock
+
import pytest
+from airflow.api_fastapi.core_api.datamodels.connections import (
+ ConnectionHookFieldBehavior,
+ ConnectionHookMetaData,
+ StandardHookFields,
+)
+
from tests_common.test_utils.asserts import assert_queries_count
from tests_common.test_utils.markers import
skip_if_force_lowest_dependencies_marker
@@ -37,6 +45,48 @@ class TestHookMetaData:
if hook_data["connection_type"] == "fs":
assert hook_data["hook_name"] == "File (path)"
+ @pytest.mark.parametrize(
+ ("extra_fields", "expected_response"),
+ [
+ ({"secret_key": "test-secret_key"}, {"secret_key": "***"}),
+ ({"extra_fields": "test-extra_fields"}, {"extra_fields":
"test-extra_fields"}),
+ (
+ {
+ "secret_key": "test-secret_key",
+ "extra_fields": "test-extra_fields",
+ "password": "test-password",
+ },
+ {"secret_key": "***", "extra_fields": "test-extra_fields",
"password": "***"},
+ ),
+ ],
+ )
+ @pytest.mark.enable_redact
+
@mock.patch("airflow.api_fastapi.core_api.routes.ui.connections.HookMetaService")
+ def test_get_should_respond_200_with_extra_fields(
+ self, hook_meta_service, test_client, extra_fields, expected_response
+ ):
+ hook_meta_service.hook_meta_data.return_value = [
+ ConnectionHookMetaData(
+ connection_type="smtp",
+ hook_class_name="airflow.providers.sftp.hooks.sftp.SFTPHook",
+ default_conn_name=None,
+ hook_name="Simple Mail Transfer Protocol (SMTP)",
+ standard_fields=StandardHookFields(
+ description=ConnectionHookFieldBehavior(),
+ url_schema=ConnectionHookFieldBehavior(),
+ host=ConnectionHookFieldBehavior(),
+ port=ConnectionHookFieldBehavior(),
+ login=ConnectionHookFieldBehavior(),
+ password=ConnectionHookFieldBehavior(),
+ ),
+ extra_fields=extra_fields,
+ )
+ ]
+ response = test_client.get("/connections/hook_meta")
+ assert response.status_code == 200
+ body = response.json()
+ assert body[0]["extra_fields"] == expected_response
+
def test_should_respond_401(self, unauthenticated_test_client):
response = unauthenticated_test_client.get("/connections/hook_meta")
assert response.status_code == 401