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 f2ac1f7a9403a..fee330e1fd1d6 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 @@ -17,12 +17,15 @@ from __future__ import annotations +import json from collections import abc from typing import Annotated -from pydantic import Field +from pydantic import Field, field_validator +from pydantic_core.core_schema import ValidationInfo from airflow.api_fastapi.core_api.base import BaseModel, StrictBaseModel +from airflow.sdk.execution_time.secrets_masker import redact # Response Models @@ -39,6 +42,26 @@ class ConnectionResponse(BaseModel): password: str | None extra: str | None + @field_validator("password", mode="after") + @classmethod + def redact_password(cls, v: str | None, field_info: ValidationInfo) -> str | None: + if v is None: + return None + return redact(v, field_info.field_name) + + @field_validator("extra", mode="before") + @classmethod + def redact_extra(cls, v: str | None) -> str | None: + if v is None: + return None + try: + extra_dict = json.loads(v) + redacted_dict = redact(extra_dict) + return json.dumps(redacted_dict) + except json.JSONDecodeError: + # we can't redact fields in an unstructured `extra` + return v + class ConnectionCollectionResponse(BaseModel): """Connection Collection serializer for responses.""" diff --git a/airflow-core/src/airflow/ui/src/pages/Connections/ConnectionForm.tsx b/airflow-core/src/airflow/ui/src/pages/Connections/ConnectionForm.tsx index 8452e738445e4..866d555c06857 100644 --- a/airflow-core/src/airflow/ui/src/pages/Connections/ConnectionForm.tsx +++ b/airflow-core/src/airflow/ui/src/pages/Connections/ConnectionForm.tsx @@ -56,7 +56,7 @@ const ConnectionForm = ({ const { conf: extra, setConf } = useParamStore(); const { control, - formState: { isDirty, isValid }, + formState: { isValid }, handleSubmit, reset, watch, @@ -92,14 +92,6 @@ const ConnectionForm = ({ mutateConnection(data); }; - const hasChanges = () => { - if (isDirty) { - return true; - } - - return JSON.stringify(JSON.parse(extra)) !== JSON.stringify(JSON.parse(initialConnection.extra)); - }; - const validateAndPrettifyJson = (value: string) => { try { const parsedJson = JSON.parse(value) as JSON; @@ -240,7 +232,7 @@ const ConnectionForm = ({