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

github-merge-queue[bot] pushed a commit to branch 
gh-readonly-queue/dev/pr-12843-93cd2407a32de85833f91fab88416ebce5d6a348
in repository https://gitbox.apache.org/repos/asf/seatunnel.git

commit 924810d8730a3619cf478bb96ddc6217ed0be7ec
Author: Goutam Adwant <[email protected]>
AuthorDate: Sun Oct 18 05:47:11 2026 +0000

    [Fix][Connector-V2] Apply Qdrant API key to source and sink clients (#12843)
---
 docs/en/connectors/sink/Qdrant.md                  |  1 +
 docs/en/connectors/source/Qdrant.md                |  1 +
 docs/zh/connectors/sink/Qdrant.md                  |  1 +
 docs/zh/connectors/source/Qdrant.md                |  1 +
 .../seatunnel/qdrant/config/QdrantParameters.java  |  6 ++-
 .../e2e/connector/v2/qdrant/QdrantIT.java          | 42 +++++++++++++----
 .../src/test/resources/qdrant-auth-to-qdrant.conf  | 53 ++++++++++++++++++++++
 7 files changed, 95 insertions(+), 10 deletions(-)

diff --git a/docs/en/connectors/sink/Qdrant.md 
b/docs/en/connectors/sink/Qdrant.md
index 9f4b36d2fa..67ac73a637 100644
--- a/docs/en/connectors/sink/Qdrant.md
+++ b/docs/en/connectors/sink/Qdrant.md
@@ -50,6 +50,7 @@ The gRPC port of the Qdrant instance.
 ### api_key [string]
 
 The API key used to connect to authenticated Qdrant deployments. Leave it 
empty when the Qdrant service does not require authentication.
+Set `use_tls = true` when sending an API key over an untrusted network; 
otherwise the key is sent over an unencrypted gRPC connection.
 
 ### use_tls [bool]
 
diff --git a/docs/en/connectors/source/Qdrant.md 
b/docs/en/connectors/source/Qdrant.md
index 5599cd801e..20a469340f 100644
--- a/docs/en/connectors/source/Qdrant.md
+++ b/docs/en/connectors/source/Qdrant.md
@@ -86,6 +86,7 @@ The gRPC port of the Qdrant instance.
 ### api_key [string]
 
 The API key used to connect to authenticated Qdrant deployments. Leave it 
empty when the Qdrant service does not require authentication.
+Set `use_tls = true` when sending an API key over an untrusted network; 
otherwise the key is sent over an unencrypted gRPC connection.
 
 ### use_tls [bool]
 
diff --git a/docs/zh/connectors/sink/Qdrant.md 
b/docs/zh/connectors/sink/Qdrant.md
index 37eb4affc2..047e088582 100644
--- a/docs/zh/connectors/sink/Qdrant.md
+++ b/docs/zh/connectors/sink/Qdrant.md
@@ -50,6 +50,7 @@ Qdrant 实例的 gRPC 端口。
 ### api_key [string]
 
 连接需要认证的 Qdrant 部署时使用的 API key。如果 Qdrant 服务不需要认证,可以保持为空。
+通过不可信网络传输 API key 时,请设置 `use_tls = true`;否则密钥会通过未加密的 gRPC 连接发送。
 
 ### use_tls [bool]
 
diff --git a/docs/zh/connectors/source/Qdrant.md 
b/docs/zh/connectors/source/Qdrant.md
index 5bfdb02c1d..7c60422be6 100644
--- a/docs/zh/connectors/source/Qdrant.md
+++ b/docs/zh/connectors/source/Qdrant.md
@@ -86,6 +86,7 @@ Qdrant 实例的 gRPC 端口。
 ### api_key [string]
 
 连接需要认证的 Qdrant 部署时使用的 API key。如果 Qdrant 服务不需要认证,可以保持为空。
+通过不可信网络传输 API key 时,请设置 `use_tls = true`;否则密钥会通过未加密的 gRPC 连接发送。
 
 ### use_tls [bool]
 
diff --git 
a/seatunnel-connectors-v2/connector-qdrant/src/main/java/org/apache/seatunnel/connectors/seatunnel/qdrant/config/QdrantParameters.java
 
b/seatunnel-connectors-v2/connector-qdrant/src/main/java/org/apache/seatunnel/connectors/seatunnel/qdrant/config/QdrantParameters.java
index a4b8940cec..4095e5dc4c 100644
--- 
a/seatunnel-connectors-v2/connector-qdrant/src/main/java/org/apache/seatunnel/connectors/seatunnel/qdrant/config/QdrantParameters.java
+++ 
b/seatunnel-connectors-v2/connector-qdrant/src/main/java/org/apache/seatunnel/connectors/seatunnel/qdrant/config/QdrantParameters.java
@@ -42,6 +42,10 @@ public class QdrantParameters implements Serializable {
     }
 
     public QdrantClient buildQdrantClient() {
-        return new QdrantClient(QdrantGrpcClient.newBuilder(host, port, 
useTls).build());
+        QdrantGrpcClient.Builder builder = QdrantGrpcClient.newBuilder(host, 
port, useTls);
+        if (apiKey != null && !apiKey.isEmpty()) {
+            builder.withApiKey(apiKey);
+        }
+        return new QdrantClient(builder.build());
     }
 }
diff --git 
a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-qdrant-e2e/src/test/java/org/apache/seatunnel/e2e/connector/v2/qdrant/QdrantIT.java
 
b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-qdrant-e2e/src/test/java/org/apache/seatunnel/e2e/connector/v2/qdrant/QdrantIT.java
index ae883b2ab2..879038a247 100644
--- 
a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-qdrant-e2e/src/test/java/org/apache/seatunnel/e2e/connector/v2/qdrant/QdrantIT.java
+++ 
b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-qdrant-e2e/src/test/java/org/apache/seatunnel/e2e/connector/v2/qdrant/QdrantIT.java
@@ -60,6 +60,8 @@ import static io.qdrant.client.VectorsFactory.namedVectors;
 public class QdrantIT extends TestSuiteBase implements TestResource {
 
     private static final String ALIAS = "qdrante2e";
+    private static final String AUTH_ALIAS = "qdrantauthe2e";
+    private static final String AUTH_API_KEY = "seatunnel-test-key";
     private static final String SOURCE_COLLECTION = "source_collection";
     private static final String SINK_COLLECTION = "sink_collection";
     /**
@@ -69,16 +71,24 @@ public class QdrantIT extends TestSuiteBase implements 
TestResource {
     private static final String IMAGE = "qdrant/qdrant:v1.15.0";
 
     private QdrantContainer container;
+    private QdrantContainer authenticatedContainer;
     private QdrantClient qdrantClient;
+    private QdrantClient authenticatedClient;
 
     @BeforeAll
     @Override
     public void startUp() throws Exception {
         this.container = new 
QdrantContainer(IMAGE).withNetwork(NETWORK).withNetworkAliases(ALIAS);
-        Startables.deepStart(Stream.of(this.container)).join();
+        this.authenticatedContainer =
+                new QdrantContainer(IMAGE)
+                        .withNetwork(NETWORK)
+                        .withNetworkAliases(AUTH_ALIAS)
+                        .withEnv("QDRANT__SERVICE__API_KEY", AUTH_API_KEY);
+        Startables.deepStart(Stream.of(this.container, 
this.authenticatedContainer)).join();
         Awaitility.given().ignoreExceptions().await().atMost(10L, 
TimeUnit.SECONDS);
         this.initQdrant();
-        this.initSourceData();
+        this.initSourceData(qdrantClient);
+        this.initSourceData(authenticatedClient);
     }
 
     private void initQdrant() {
@@ -87,11 +97,18 @@ public class QdrantIT extends TestSuiteBase implements 
TestResource {
                         QdrantGrpcClient.newBuilder(
                                         container.getHost(), 
container.getGrpcPort(), false)
                                 .build());
+        authenticatedClient =
+                new QdrantClient(
+                        QdrantGrpcClient.newBuilder(
+                                        authenticatedContainer.getHost(),
+                                        authenticatedContainer.getGrpcPort(),
+                                        false)
+                                .withApiKey(AUTH_API_KEY)
+                                .build());
     }
 
-    private void initSourceData() throws Exception {
-        qdrantClient
-                .createCollectionAsync(
+    private void initSourceData(QdrantClient client) throws Exception {
+        client.createCollectionAsync(
                         SOURCE_COLLECTION,
                         ImmutableMap.of(
                                 "my_vector",
@@ -101,8 +118,7 @@ public class QdrantIT extends TestSuiteBase implements 
TestResource {
                                         .build()))
                 .get();
 
-        qdrantClient
-                .createCollectionAsync(
+        client.createCollectionAsync(
                         SINK_COLLECTION,
                         ImmutableMap.of(
                                 "my_vector",
@@ -125,8 +141,7 @@ public class QdrantIT extends TestSuiteBase implements 
TestResource {
             points.add(pointStruct.build());
         }
 
-        qdrantClient
-                .upsertAsync(
+        client.upsertAsync(
                         Points.UpsertPoints.newBuilder()
                                 .setCollectionName(SOURCE_COLLECTION)
                                 .addAllPoints(points)
@@ -138,6 +153,7 @@ public class QdrantIT extends TestSuiteBase implements 
TestResource {
     @Override
     public void tearDown() {
         this.qdrantClient.close();
+        this.authenticatedClient.close();
     }
 
     @TestTemplate
@@ -147,4 +163,12 @@ public class QdrantIT extends TestSuiteBase implements 
TestResource {
         Assertions.assertEquals(0, execResult.getExitCode());
         Assertions.assertEquals(10, 
qdrantClient.countAsync(SINK_COLLECTION).get());
     }
+
+    @TestTemplate
+    public void testQdrantWithApiKey(TestContainer container)
+            throws IOException, InterruptedException, ExecutionException {
+        Container.ExecResult execResult = 
container.executeJob("/qdrant-auth-to-qdrant.conf");
+        Assertions.assertEquals(0, execResult.getExitCode());
+        Assertions.assertEquals(10, 
authenticatedClient.countAsync(SINK_COLLECTION).get());
+    }
 }
diff --git 
a/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-qdrant-e2e/src/test/resources/qdrant-auth-to-qdrant.conf
 
b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-qdrant-e2e/src/test/resources/qdrant-auth-to-qdrant.conf
new file mode 100644
index 0000000000..f0a623bfc6
--- /dev/null
+++ 
b/seatunnel-e2e/seatunnel-connector-v2-e2e/connector-qdrant-e2e/src/test/resources/qdrant-auth-to-qdrant.conf
@@ -0,0 +1,53 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+env {
+  parallelism = 1
+  job.mode = "BATCH"
+}
+
+source {
+  Qdrant {
+    collection_name = "source_collection"
+    host = "qdrantauthe2e"
+    api_key = "seatunnel-test-key"
+    schema = {
+      columns = [
+        {
+          name = file_name
+          type = string
+        }
+        {
+          name = file_size
+          type = int
+        }
+        {
+          name = my_vector
+          type = float_vector
+        }
+      ]
+    }
+  }
+}
+
+sink {
+  Qdrant {
+    collection_name = "sink_collection"
+    host = "qdrantauthe2e"
+    api_key = "seatunnel-test-key"
+  }
+}

Reply via email to