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-12536-584a25a6e44ea443d8d5e78784dbf75556b2997c
in repository https://gitbox.apache.org/repos/asf/seatunnel.git

commit 40d7fef09d203e2b4b1b8a3c5bdfd09ed0b87e58
Author: SEZ <[email protected]>
AuthorDate: Thu Oct 1 15:05:40 2026 +0000

    [Fix][seatunnel-cli] Treat an exported empty value as a resolved 
placeholder (#12536)
---
 seatunnel-cli/benchmark/runner.py             |  7 ++-
 seatunnel-cli/seatunnel_cli/agents.py         |  7 ++-
 seatunnel-cli/tests/test_config_validation.py | 78 +++++++++++++++++++++++++++
 3 files changed, 89 insertions(+), 3 deletions(-)

diff --git a/seatunnel-cli/benchmark/runner.py 
b/seatunnel-cli/benchmark/runner.py
index 811602b203..1fa154b5ba 100644
--- a/seatunnel-cli/benchmark/runner.py
+++ b/seatunnel-cli/benchmark/runner.py
@@ -624,8 +624,11 @@ def main() -> None:
     # where the user exports them before running seatunnel.sh).
     from benchmark.execution import CREDENTIALS
     for key, value in CREDENTIALS.items():
-        if value:
-            os.environ.setdefault(key, value)
+        # Export empty values too: the benchmark Doris, StarRocks and
+        # Elasticsearch services genuinely have no password, and skipping
+        # them left ${DORIS_PASSWORD} looking unresolved, so those tasks
+        # failed on validation rather than on anything the model produced.
+        os.environ.setdefault(key, value)
 
     results = run_benchmark(models, tasks, levels, args.max_repairs,
                             args.trials, Path(args.out), suite=args.suite)
diff --git a/seatunnel-cli/seatunnel_cli/agents.py 
b/seatunnel-cli/seatunnel_cli/agents.py
index 1a5085c7b5..68d519f9cf 100644
--- a/seatunnel-cli/seatunnel_cli/agents.py
+++ b/seatunnel-cli/seatunnel_cli/agents.py
@@ -553,7 +553,12 @@ def validate_hocon(config_str: str) -> str:
             var_name = m.group(1)
             if allowed and allowed.fullmatch(var_name):
                 continue
-            if not os.environ.get(var_name):
+            # Test that the variable is set, not that it is non-empty: an
+            # empty value is a resolved value. Passwordless accounts are
+            # normal (Doris and StarRocks default to root with no password,
+            # Elasticsearch to no auth), and `export DORIS_PASSWORD=` must
+            # not be reported as something still to be exported.
+            if os.environ.get(var_name) is None:
                 unresolved_vars.add(var_name)
     if unresolved_vars:
         var_list = ", ".join(sorted(unresolved_vars))
diff --git a/seatunnel-cli/tests/test_config_validation.py 
b/seatunnel-cli/tests/test_config_validation.py
new file mode 100644
index 0000000000..9067a2a88b
--- /dev/null
+++ b/seatunnel-cli/tests/test_config_validation.py
@@ -0,0 +1,78 @@
+#
+# 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.
+#
+
+"""Tests for environment-variable placeholder validation."""
+
+import os
+
+from seatunnel_cli.agents import validate_hocon
+
+
+CONFIG = """
+env {
+  job.mode = "BATCH"
+}
+source {
+  Jdbc {
+    url = "jdbc:mysql://localhost:3306/shop"
+    driver = "com.mysql.cj.jdbc.Driver"
+    user = "root"
+    password = "${ST_TEST_PASSWORD}"
+    query = "SELECT * FROM users"
+    plugin_output = "rows"
+  }
+}
+sink {
+  Console {
+    plugin_input = "rows"
+  }
+}
+"""
+
+VAR = "ST_TEST_PASSWORD"
+
+
+def _validate_with(value):
+    """Run validation with VAR set to value, or removed when value is None."""
+    previous = os.environ.get(VAR)
+    had_previous = VAR in os.environ
+    try:
+        if value is None:
+            os.environ.pop(VAR, None)
+        else:
+            os.environ[VAR] = value
+        return validate_hocon(CONFIG)
+    finally:
+        if had_previous:
+            os.environ[VAR] = previous
+        else:
+            os.environ.pop(VAR, None)
+
+
+def test_unset_variable_is_reported():
+    assert VAR in _validate_with(None)
+
+
+def test_set_variable_is_accepted():
+    assert VAR not in _validate_with("Test@123")
+
+
+def test_empty_variable_counts_as_resolved():
+    # A passwordless account is normal: Doris and StarRocks default to root
+    # with no password, Elasticsearch to no auth. `export VAR=` is a resolved
+    # value, so it must not be reported as still needing an export.
+    assert VAR not in _validate_with("")

Reply via email to