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

vatsrahul1001 pushed a commit to branch v3-4-test
in repository https://gitbox.apache.org/repos/asf/airflow.git

commit d98fca04d3f05aa611d5a6e14c804d401ac7aae2
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Tue Nov 3 16:17:50 2026 +0000

    [v3-4-test] Inline the masked Variable merge and drop unused merge depth 
args (#76306) (#76378)
    
    * Simplify the masked Variable merge and drop unused merge depth arguments
    
    The restore runs from a single place, so keeping it inline mirrors the
    Connection update it is modelled on. Merging now walks every depth like
    redaction does, so the depth arguments threaded through _merge no longer
    bound anything and only suggested a cutoff that does not exist.
    
    * Read the stored Variable value once and clarify the merge max_depth 
docstring
    (cherry picked from commit 9a6ef0a4217c23cfe360fd1d26a6ecf6366166b0)
    
    Co-authored-by: Pierre Jeambrun <[email protected]>
---
 .../core_api/services/public/variables.py          | 33 ++++++++--------------
 .../secrets_masker/secrets_masker.py               | 11 ++------
 2 files changed, 15 insertions(+), 29 deletions(-)

diff --git 
a/airflow-core/src/airflow/api_fastapi/core_api/services/public/variables.py 
b/airflow-core/src/airflow/api_fastapi/core_api/services/public/variables.py
index 7b9e91a70fb..790aa1c1125 100644
--- a/airflow-core/src/airflow/api_fastapi/core_api/services/public/variables.py
+++ b/airflow-core/src/airflow/api_fastapi/core_api/services/public/variables.py
@@ -42,24 +42,6 @@ from airflow.api_fastapi.core_api.services.public.common 
import BulkService
 from airflow.models.variable import Variable
 
 
-def _restore_redacted_value(new_value: str, old_value: str | None, key: str) 
-> str:
-    """
-    Put the stored secret back wherever ``new_value`` still holds the mask 
``VariableResponse`` sent out.
-
-    The UI edit form is filled from the redacted response, so saving it 
unchanged would otherwise
-    write ``***`` over every sensitive field.
-    """
-    if old_value is None:
-        return new_value
-    try:
-        new_obj, old_obj = json.loads(new_value), json.loads(old_value)
-    except json.JSONDecodeError:
-        return merge(new_value, old_value, key)
-    merged = merge(new_obj, old_obj, key)
-    # Keep the caller's formatting when there was nothing to restore. indent=2 
matches VariableBody.
-    return new_value if merged == new_obj else json.dumps(merged, indent=2)
-
-
 def update_orm_from_pydantic(
     old_variable: Variable, patch_body: VariableBody, update_mask: list[str] | 
None
 ) -> Variable:
@@ -85,14 +67,23 @@ def update_orm_from_pydantic(
             raise RequestValidationError(errors=e.errors())
     non_update_fields = {"key"}
 
+    # The UI edit form is filled from the redacted response, so saving it 
unchanged would otherwise
+    # write ``***`` over every sensitive field.
     if (
         "value" in patch_body.model_fields_set
         and (not update_mask or "value" in update_mask)
         and isinstance(patch_body.value, str)
+        and (old_value := old_variable.val) is not None
     ):
-        patch_body = patch_body.model_copy(
-            update={"value": _restore_redacted_value(patch_body.value, 
old_variable.val, old_variable.key)}
-        )
+        try:
+            new_obj, old_obj = json.loads(patch_body.value), 
json.loads(old_value)
+        except json.JSONDecodeError:
+            merged_value = merge(patch_body.value, old_value, old_variable.key)
+        else:
+            merged = merge(new_obj, old_obj, old_variable.key)
+            # Keep the caller's formatting when there was nothing to restore. 
indent=2 matches VariableBody.
+            merged_value = patch_body.value if merged == new_obj else 
json.dumps(merged, indent=2)
+        patch_body = patch_body.model_copy(update={"value": merged_value})
 
     # Apply patch via utility
     return cast(
diff --git 
a/shared/secrets_masker/src/airflow_shared/secrets_masker/secrets_masker.py 
b/shared/secrets_masker/src/airflow_shared/secrets_masker/secrets_masker.py
index 497e8f1ebcf..d802ea6bcb6 100644
--- a/shared/secrets_masker/src/airflow_shared/secrets_masker/secrets_masker.py
+++ b/shared/secrets_masker/src/airflow_shared/secrets_masker/secrets_masker.py
@@ -446,8 +446,6 @@ class SecretsMasker(logging.Filter):
         old_item: Redactable,
         *,
         name: str | None,
-        depth: int,
-        max_depth: int,
         force_sensitive: bool = False,
         replacement: str,
     ) -> Redacted:
@@ -477,8 +475,6 @@ class SecretsMasker(logging.Filter):
                             new_item[key],
                             old_item[key],
                             name=child_name,
-                            depth=depth + 1,
-                            max_depth=max_depth,
                             force_sensitive=is_sensitive,
                             replacement=replacement,
                         )
@@ -499,8 +495,6 @@ class SecretsMasker(logging.Filter):
                                     new_item[i],
                                     old_item[i],
                                     name=None,
-                                    depth=depth + 1,
-                                    max_depth=max_depth,
                                     force_sensitive=is_sensitive,
                                     replacement=replacement,
                                 )
@@ -559,13 +553,14 @@ class SecretsMasker(logging.Filter):
         Takes a user-modified redacted item and merges it with the original 
unredacted item.
         For sensitive fields that still contain "***" (or whatever the 
``replacement`` is specified as), the
         original value is restored. For fields that have been updated, the new 
value is preserved.
+
+        ``max_depth`` is ignored and kept for backward compatibility. 
Containers are walked at any
+        depth; a sensitive subtree that ``redact`` collapsed at its 
``max_depth`` is restored whole.
         """
         return self._merge(
             new_item,
             old_item,
             name=name,
-            depth=0,
-            max_depth=max_depth or self.MAX_RECURSION_DEPTH,
             force_sensitive=False,
             replacement=replacement,
         )

Reply via email to