ashb commented on code in PR #28239:
URL: https://github.com/apache/airflow/pull/28239#discussion_r1047671128


##########
airflow/utils/log/secrets_masker.py:
##########
@@ -240,17 +241,53 @@ def redact(self, item: Redactable, name: str | None = 
None) -> Redacted:
         """
         return self._redact(item, name, depth=0)
 
-    def add_mask(self, secret: str | dict | Iterable, name: str | None = None):
-        """Add a new secret to be masked to this filter instance."""
+    @cached_property
+    def _mask_adapter(self) -> None | Callable:
+        """Pulls the secret mask adapter from config.
+
+        This lives in a function here to be cached and only hit the config 
once.
+        """
         from airflow.configuration import conf
 
-        test_mode: bool = conf.getboolean("core", "unit_test_mode")
+        return conf.getimport("logging", "secret_mask_adapter", fallback=None)
+
+    @cached_property
+    def _test_mode(self) -> bool:
+        """Pulls the unit test mode flag from config.
+
+        This lives in a function here to be cached and only hit the config 
once.
+        """
+        from airflow.configuration import conf
+
+        return conf.getboolean("core", "unit_test_mode")
+
+    def _add_adaptations(self, secret: str | dict | Iterable, name: str | None 
= None):
+        """Adds any adaptations to the secret that should be masked."""
+        if self._mask_adapter:
+            # This can return an iterable of secrets to mask OR a single 
secret as a string
+            secret_or_secrets = self._mask_adapter(secret)
+
+            if not isinstance(secret_or_secrets, str):
+                # if its not a string, it must be an iterable
+                for secret in secret_or_secrets:
+                    self.add_mask(secret, name, add_adaptations=False)
+            else:
+                self.add_mask(secret_or_secrets, name, add_adaptations=False)

Review Comment:
   ```suggestion
       def _adaptations(self, secret: str):
           """Adds any adaptations to the secret that should be masked."""
           if not self._mask_adapter:
               return [secret]
           # This can return an iterable of secrets to mask OR a single secret 
as a string
           secret_or_secrets = self._mask_adapter(secret)
   
           if not isinstance(secret_or_secrets, str):
               # if its not a string, it must be an iterable
               return secret_or_secrets
          else:
                return [secret]
   ```



##########
airflow/utils/log/secrets_masker.py:
##########
@@ -240,17 +241,53 @@ def redact(self, item: Redactable, name: str | None = 
None) -> Redacted:
         """
         return self._redact(item, name, depth=0)
 
-    def add_mask(self, secret: str | dict | Iterable, name: str | None = None):
-        """Add a new secret to be masked to this filter instance."""
+    @cached_property
+    def _mask_adapter(self) -> None | Callable:
+        """Pulls the secret mask adapter from config.
+
+        This lives in a function here to be cached and only hit the config 
once.
+        """
         from airflow.configuration import conf
 
-        test_mode: bool = conf.getboolean("core", "unit_test_mode")
+        return conf.getimport("logging", "secret_mask_adapter", fallback=None)
+
+    @cached_property
+    def _test_mode(self) -> bool:
+        """Pulls the unit test mode flag from config.
+
+        This lives in a function here to be cached and only hit the config 
once.
+        """
+        from airflow.configuration import conf
+
+        return conf.getboolean("core", "unit_test_mode")
+
+    def _add_adaptations(self, secret: str | dict | Iterable, name: str | None 
= None):
+        """Adds any adaptations to the secret that should be masked."""
+        if self._mask_adapter:
+            # This can return an iterable of secrets to mask OR a single 
secret as a string
+            secret_or_secrets = self._mask_adapter(secret)
+
+            if not isinstance(secret_or_secrets, str):
+                # if its not a string, it must be an iterable
+                for secret in secret_or_secrets:
+                    self.add_mask(secret, name, add_adaptations=False)
+            else:
+                self.add_mask(secret_or_secrets, name, add_adaptations=False)
+
+    def add_mask(self, secret: str | dict | Iterable, name: str | None = None, 
add_adaptations: bool = True):
+        """Add a new secret to be masked to this filter instance.
+
+        If add_adaptations is True, the secret mask adapter will be used to 
add adaptations for the secret
+        as well.
+        """
         if isinstance(secret, dict):
             for k, v in secret.items():
                 self.add_mask(v, k)
         elif isinstance(secret, str):
-            if not secret or (test_mode and secret in 
SECRETS_TO_SKIP_MASKING_FOR_TESTS):
+            if not secret or (self._test_mode and secret in 
SECRETS_TO_SKIP_MASKING_FOR_TESTS):
                 return
+            if add_adaptations:
+                self._add_adaptations(secret, name)
             pattern = re.escape(secret)
             if pattern not in self.patterns and (not name or 
should_hide_value_for_key(name)):
                 self.patterns.add(pattern)

Review Comment:
   This suggestion won't blindly apply, but we should remove the current 
`self.replacer = re.compile("|".join(self.patterns))` line
   
   ```suggestion
               new_mask = False
               for s in self._adaptation(secret):
                   pattern = re.escape(secret)
                   if pattern not in self.patterns and (not name or 
should_hide_value_for_key(name)):
                       self.patterns.add(pattern)
                       new_mask = True
           if new_mask:
               self.replacer = re.compile("|".join(self.patterns))              
      
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to