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

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


The following commit(s) were added to refs/heads/v3-3-test by this push:
     new 3e38a189e1b [v3-3-test] Allow slashes in connection IDs fetched via 
the Execution API (#69228) (#73700)
3e38a189e1b is described below

commit 3e38a189e1b1dc91542017c6c57e63f4b4af65f8
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Fri Sep 25 11:14:49 2026 +0800

    [v3-3-test] Allow slashes in connection IDs fetched via the Execution API 
(#69228) (#73700)
    
    * Allow slashes in connection IDs fetched via the Execution API
    
    * Add client side encoding
    
    * Fix required fields in test
    (cherry picked from commit 0142b0443a2ca149cdb0a14895ccbb2178a6219d)
    
    Co-authored-by: Justin Pakzad 
<[email protected]>
---
 .../execution_api/routes/connections.py            |  2 +-
 .../versions/head/test_connections.py              | 32 ++++++++++++++++++++++
 task-sdk/src/airflow/sdk/api/client.py             |  2 +-
 task-sdk/tests/task_sdk/api/test_client.py         | 25 +++++++++++++++++
 4 files changed, 59 insertions(+), 2 deletions(-)

diff --git 
a/airflow-core/src/airflow/api_fastapi/execution_api/routes/connections.py 
b/airflow-core/src/airflow/api_fastapi/execution_api/routes/connections.py
index 8289dcf97fb..d7bc9d634cf 100644
--- a/airflow-core/src/airflow/api_fastapi/execution_api/routes/connections.py
+++ b/airflow-core/src/airflow/api_fastapi/execution_api/routes/connections.py
@@ -57,7 +57,7 @@ log = logging.getLogger(__name__)
 
 
 @router.get(
-    "/{connection_id}",
+    "/{connection_id:path}",
     responses={
         status.HTTP_401_UNAUTHORIZED: {"description": "Unauthorized"},
         status.HTTP_403_FORBIDDEN: {"description": "Task does not have access 
to the connection"},
diff --git 
a/airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_connections.py
 
b/airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_connections.py
index a2e3cb51fab..8d5da4fa3ae 100644
--- 
a/airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_connections.py
+++ 
b/airflow-core/tests/unit/api_fastapi/execution_api/versions/head/test_connections.py
@@ -86,6 +86,38 @@ class TestGetConnection:
         session.delete(connection)
         session.commit()
 
+    def test_connection_get_with_slash(self, client, session):
+        connection = Connection(
+            conn_id="dev/test_conn",
+            conn_type="http",
+            description="description",
+            host="localhost",
+            login="root",
+            password="admin",
+            schema="http",
+            port=8080,
+            extra='{"x_secret": "testsecret", "y_secret": "test"}',
+        )
+        session.add(connection)
+        session.commit()
+
+        response = client.get("/execution/connections/dev/test_conn")
+
+        assert response.status_code == 200
+        assert response.json() == {
+            "conn_id": "dev/test_conn",
+            "conn_type": "http",
+            "host": "localhost",
+            "login": "root",
+            "password": "admin",
+            "schema": "http",
+            "port": 8080,
+            "extra": '{"x_secret": "testsecret", "y_secret": "test"}',
+        }
+
+        session.delete(connection)
+        session.commit()
+
     @mock.patch.dict(
         "os.environ",
         {"AIRFLOW_CONN_TEST_CONN2": '{"uri": 
"http://root:admin@localhost:8080/https?headers=header"}'},
diff --git a/task-sdk/src/airflow/sdk/api/client.py 
b/task-sdk/src/airflow/sdk/api/client.py
index 4353802c61c..9c67f905a23 100644
--- a/task-sdk/src/airflow/sdk/api/client.py
+++ b/task-sdk/src/airflow/sdk/api/client.py
@@ -467,7 +467,7 @@ class ConnectionOperations:
     def get(self, conn_id: str) -> ConnectionResponse | ErrorResponse:
         """Get a connection from the API server."""
         try:
-            resp = self.client.get(f"connections/{conn_id}")
+            resp = self.client.get(f"connections/{quote(conn_id, safe='')}")
         except ServerResponseError as e:
             if e.response.status_code == HTTPStatus.NOT_FOUND:
                 log.debug(
diff --git a/task-sdk/tests/task_sdk/api/test_client.py 
b/task-sdk/tests/task_sdk/api/test_client.py
index 532589dfc2e..f683fa1753a 100644
--- a/task-sdk/tests/task_sdk/api/test_client.py
+++ b/task-sdk/tests/task_sdk/api/test_client.py
@@ -1180,6 +1180,31 @@ class TestConnectionOperations:
         assert isinstance(result, ErrorResponse)
         assert result.error == ErrorType.CONNECTION_NOT_FOUND
 
+    def test_connection_get_url_encodes_conn_id(self):
+        requests_seen = []
+
+        def handle_request(request: httpx.Request) -> httpx.Response:
+            requests_seen.append(request)
+            return httpx.Response(
+                status_code=200,
+                json={
+                    "conn_id": "dev/my_conn",
+                    "conn_type": "http",
+                    "host": None,
+                    "schema": None,
+                    "login": None,
+                    "password": None,
+                    "port": None,
+                    "extra": None,
+                },
+            )
+
+        client = make_client(transport=httpx.MockTransport(handle_request))
+        result = client.connections.get(conn_id="dev/my_conn")
+
+        assert isinstance(result, ConnectionResponse)
+        assert requests_seen[0].url.raw_path == b"/connections/dev%2Fmy_conn"
+
     @pytest.mark.parametrize("status_code", [401, 403])
     def test_connection_get_authz_returns_permission_denied(self, status_code):
         """401/403 from the API server is reported as PERMISSION_DENIED, not 
raised."""

Reply via email to