Copilot commented on code in PR #65212:
URL: https://github.com/apache/airflow/pull/65212#discussion_r3081674884


##########
providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/hooks/kubernetes.py:
##########
@@ -818,6 +818,31 @@ def __init__(
         self._event_polling_fallback = False
         self._config_loaded = False
 
+    def _uses_exec_auth(self, kubeconfig_data: dict, context: str | None = 
None) -> bool:
+        """
+        Detect if the active kubeconfig context uses exec-based authentication.
+
+        Exec plugins return short-lived tokens (EKS, GKE, etc). Only the user
+        tied to the active context is checked.
+        """
+        active_context = context or kubeconfig_data.get("current-context")
+
+        active_user: str | None = None
+        for ctx in kubeconfig_data.get("contexts", []):
+            if ctx.get("name") == active_context:
+                active_user = ctx.get("context", {}).get("user")
+                break
+
+        users = kubeconfig_data.get("users", [])
+        if active_user is not None:
+            for user in users:
+                if user.get("name") == active_user:
+                    return "exec" in user.get("user", {})
+            return False
+
+        # fallback to check all users if active context user cannot be 
resolved; this is a safe fallback since it errs on the side of not caching
+        return any("exec" in u.get("user", {}) for u in users)
+
     async def _load_config(self):
         """Load Kubernetes configuration once per hook instance."""

Review Comment:
   The `_load_config()` docstring says the config is loaded "once per hook 
instance", but with the new exec-auth behavior the config may intentionally be 
reloaded on every call (since `_config_loaded` stays `False`). Please update 
the docstring to reflect the new semantics so callers aren’t misled when 
debugging repeated config loads.
   



##########
providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/hooks/kubernetes.py:
##########
@@ -846,50 +871,76 @@ async def _load_config(self):
             self._config_loaded = True
             return
 
-        # If above block does not return, we are not in a cluster.
         self._is_in_cluster = False
-
         if self.config_dict:
             self.log.debug(LOADING_KUBE_CONFIG_FILE_RESOURCE.format("config 
dictionary"))
-            await async_config.load_kube_config_from_dict(self.config_dict, 
context=cluster_context)
-            self._config_loaded = True
-            return
 
+            await async_config.load_kube_config_from_dict(
+                self.config_dict,
+                context=cluster_context,
+            )
+
+            if not self._uses_exec_auth(self.config_dict, 
context=cluster_context):
+                self._config_loaded = True
+
+            return
         if kubeconfig_path is not None:
             self.log.debug("loading kube_config from: %s", kubeconfig_path)
+
             await async_config.load_kube_config(
                 config_file=kubeconfig_path,
                 client_configuration=self.client_configuration,
                 context=cluster_context,
             )
-            self._config_loaded = True
-            return
 
+            try:
+                async with aiofiles.open(kubeconfig_path) as f:
+                    content = await f.read()
+                    data = yaml.safe_load(content)
+
+                if not self._uses_exec_auth(data, context=cluster_context):
+                    self._config_loaded = True
+            except Exception as exc:
+                self.log.warning(
+                    "Error while parsing kube_config from %s to detect exec 
auth; "
+                    "continuing without caching the config: %s",
+                    kubeconfig_path,
+                    exc,
+                )
+
+            return

Review Comment:
   New exec-auth detection for `kube_config_path` isn’t covered by tests. There 
are existing tests for loading from `kube_config_path`, but none assert the new 
caching behavior (`_config_loaded` stays `False` when the active context uses 
exec, and `True` otherwise). Adding a unit test that writes an exec-based 
kubeconfig to `tmp_path` and asserts the resulting `_config_loaded` value would 
prevent regressions.



##########
providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/hooks/kubernetes.py:
##########
@@ -818,6 +818,31 @@ def __init__(
         self._event_polling_fallback = False
         self._config_loaded = False
 
+    def _uses_exec_auth(self, kubeconfig_data: dict, context: str | None = 
None) -> bool:
+        """
+        Detect if the active kubeconfig context uses exec-based authentication.
+
+        Exec plugins return short-lived tokens (EKS, GKE, etc). Only the user
+        tied to the active context is checked.

Review Comment:
   `_uses_exec_auth()` docstring says "Only the user tied to the active context 
is checked", but the implementation falls back to scanning *all* users when the 
active context/user can’t be resolved. Please document this fallback behavior 
(and its intent to err on the side of not caching) to keep the docstring 
accurate.
   



##########
providers/cncf/kubernetes/src/airflow/providers/cncf/kubernetes/hooks/kubernetes.py:
##########
@@ -818,6 +818,31 @@ def __init__(
         self._event_polling_fallback = False
         self._config_loaded = False
 
+    def _uses_exec_auth(self, kubeconfig_data: dict, context: str | None = 
None) -> bool:
+        """
+        Detect if the active kubeconfig context uses exec-based authentication.
+
+        Exec plugins return short-lived tokens (EKS, GKE, etc). Only the user
+        tied to the active context is checked.
+        """
+        active_context = context or kubeconfig_data.get("current-context")
+
+        active_user: str | None = None
+        for ctx in kubeconfig_data.get("contexts", []):
+            if ctx.get("name") == active_context:
+                active_user = ctx.get("context", {}).get("user")
+                break
+
+        users = kubeconfig_data.get("users", [])
+        if active_user is not None:
+            for user in users:
+                if user.get("name") == active_user:
+                    return "exec" in user.get("user", {})
+            return False
+
+        # fallback to check all users if active context user cannot be 
resolved; this is a safe fallback since it errs on the side of not caching
+        return any("exec" in u.get("user", {}) for u in users)

Review Comment:
   `_uses_exec_auth()` assumes `ctx["context"]` and `user["user"]` are dicts, 
but kubeconfig YAML can legally contain empty mappings like `context:` / 
`user:` which `yaml.safe_load` parses as `None`. In that case, 
`ctx.get("context", {}).get(...)` or `'exec' in user.get('user', {})` will 
raise (AttributeError/TypeError) and can fail `_load_config()` for exec 
detection. Consider normalizing with `ctx_context = ctx.get("context") or {}` 
and `user_spec = user.get("user") or {}` (and similarly in the fallback 
`any(...)`) so detection is best-effort and never breaks config loading.
   



-- 
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