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

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


The following commit(s) were added to refs/heads/v3-0-test by this push:
     new 4ba884a1e7d [v3-0-test] Add cert used for apiserver to client (fix for 
self-signed) (#53574) (#53793)
4ba884a1e7d is described below

commit 4ba884a1e7dc89d5eaae821d572ac6be45faf481
Author: Jarek Potiuk <[email protected]>
AuthorDate: Sun Jul 27 12:43:48 2025 +0200

    [v3-0-test] Add cert used for apiserver to client (fix for self-signed) 
(#53574) (#53793)
    
    * Add cert used for apiserver to client (fix for self-signed)
    
    * Correct indentation, run pre-commit checks
    
    * Add test for cert load
    
    * Update config description for api ssl_cert
    
    * Use mock instead and check error when non-existant CA is not found
    (cherry picked from commit 6dba10134a0beff4656b344652d9a6f09d0648fd)
    
    Co-authored-by: Daniel Dean <[email protected]>
---
 airflow-core/src/airflow/config_templates/config.yml |  2 ++
 task-sdk/src/airflow/sdk/api/client.py               |  7 +++++++
 task-sdk/tests/task_sdk/api/test_client.py           | 10 ++++++++++
 3 files changed, 19 insertions(+)

diff --git a/airflow-core/src/airflow/config_templates/config.yml 
b/airflow-core/src/airflow/config_templates/config.yml
index 33d52dfe75a..b718e36e723 100644
--- a/airflow-core/src/airflow/config_templates/config.yml
+++ b/airflow-core/src/airflow/config_templates/config.yml
@@ -1403,6 +1403,8 @@ api:
       description: |
         Paths to the SSL certificate and key for the api server. When both are
         provided SSL will be enabled. This does not change the api server port.
+        The same SSL certificate will also be loaded into the worker to enable
+        it to be trusted when a self-signed certificate is used.
       version_added: ~
       type: string
       example: ~
diff --git a/task-sdk/src/airflow/sdk/api/client.py 
b/task-sdk/src/airflow/sdk/api/client.py
index 36489d3d79d..3413e98189c 100644
--- a/task-sdk/src/airflow/sdk/api/client.py
+++ b/task-sdk/src/airflow/sdk/api/client.py
@@ -18,11 +18,13 @@
 from __future__ import annotations
 
 import logging
+import ssl
 import sys
 import uuid
 from http import HTTPStatus
 from typing import TYPE_CHECKING, Any, TypeVar
 
+import certifi
 import httpx
 import msgspec
 import structlog
@@ -660,6 +662,7 @@ def noop_handler(request: httpx.Request) -> httpx.Response:
 API_RETRIES = conf.getint("workers", "execution_api_retries")
 API_RETRY_WAIT_MIN = conf.getfloat("workers", "execution_api_retry_wait_min")
 API_RETRY_WAIT_MAX = conf.getfloat("workers", "execution_api_retry_wait_max")
+API_SSL_CERT_PATH = conf.get("api", "ssl_cert")
 
 
 class Client(httpx.Client):
@@ -675,6 +678,10 @@ class Client(httpx.Client):
             kwargs.setdefault("base_url", "dry-run://server")
         else:
             kwargs["base_url"] = base_url
+            ctx = ssl.create_default_context(cafile=certifi.where())
+            if API_SSL_CERT_PATH:
+                ctx.load_verify_locations(API_SSL_CERT_PATH)
+            kwargs["verify"] = ctx
         pyver = f"{'.'.join(map(str, sys.version_info[:3]))}"
         super().__init__(
             auth=auth,
diff --git a/task-sdk/tests/task_sdk/api/test_client.py 
b/task-sdk/tests/task_sdk/api/test_client.py
index 7fa17ba1c4d..caa515de09a 100644
--- a/task-sdk/tests/task_sdk/api/test_client.py
+++ b/task-sdk/tests/task_sdk/api/test_client.py
@@ -79,6 +79,16 @@ class TestClient:
         assert resp.status_code == 200
         assert resp.json() == json_response
 
+    @mock.patch("airflow.sdk.api.client.API_SSL_CERT_PATH", 
"/capath/does/not/exist/")
+    def test_add_capath(self):
+        def handle_request(request: httpx.Request) -> httpx.Response:
+            return httpx.Response(status_code=200)
+
+        with pytest.raises(FileNotFoundError) as err:
+            make_client(httpx.MockTransport(handle_request))
+
+        assert isinstance(err.value, FileNotFoundError)
+
     def test_error_parsing(self):
         responses = [
             httpx.Response(422, json={"detail": [{"loc": ["#0"], "msg": "err", 
"type": "required"}]})

Reply via email to