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

AlinsRan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git


The following commit(s) were added to refs/heads/master by this push:
     new a4c4832a9 fix(cli): quote nginx_config.envs entries so values with 
spaces work (#13713)
a4c4832a9 is described below

commit a4c4832a9f459e21d7e035f0c90522f8696758de
Author: AlinsRan <[email protected]>
AuthorDate: Wed Jul 22 12:08:23 2026 +0800

    fix(cli): quote nginx_config.envs entries so values with spaces work 
(#13713)
---
 apisix/cli/ngx_tpl.lua   |  2 +-
 apisix/cli/ops.lua       | 17 +++++++++
 apisix/cli/schema.lua    |  4 +++
 t/cli/test_kubernetes.sh | 18 +++++-----
 t/cli/test_main.sh       | 91 ++++++++++++++++++++++++++++++++++++++++++------
 t/cli/test_standalone.sh |  2 +-
 6 files changed, 112 insertions(+), 22 deletions(-)

diff --git a/apisix/cli/ngx_tpl.lua b/apisix/cli/ngx_tpl.lua
index 2ec477943..4fa56d57a 100644
--- a/apisix/cli/ngx_tpl.lua
+++ b/apisix/cli/ngx_tpl.lua
@@ -57,7 +57,7 @@ env GCP_SERVICE_ACCOUNT;
 
 {% if envs then %}
 {% for _, name in ipairs(envs) do %}
-env {*name*};
+env "{*name*}";
 {% end %}
 {% end %}
 
diff --git a/apisix/cli/ops.lua b/apisix/cli/ops.lua
index d514de4a8..0f6a4fae6 100644
--- a/apisix/cli/ops.lua
+++ b/apisix/cli/ops.lua
@@ -911,6 +911,23 @@ Please modify "admin_key" in conf/config.yaml .
         sys_conf["discovery_shared_dicts"]["consul"] = consul_conf.shared_size 
or "64m"
     end
 
+    -- env entries are rendered as double-quoted nginx directive parameters
+    -- (`env "{*name*}";` in ngx_tpl.lua), so embedded `\` and `"` must be
+    -- escaped; nginx unescapes them when reading the quoted token
+    -- entries synthesized after schema validation (kubernetes discovery copies
+    -- whatever sits between `${` and `}`) never went through the schema
+    -- pattern, so re-check them here rather than emitting a conf that nginx
+    -- rejects with an error pointing at a line the user never wrote
+    if sys_conf["envs"] then
+        for i, cfg_env in ipairs(sys_conf["envs"]) do
+            if cfg_env:find("%c") then
+                util.die("invalid environment variable entry: ",
+                         "control characters are not allowed\n")
+            end
+            sys_conf["envs"][i] = cfg_env:gsub('[\\"]', '\\%0')
+        end
+    end
+
     -- fix up lua path
     sys_conf["extra_lua_path"] = get_lua_path(yaml_conf.apisix.extra_lua_path)
     sys_conf["extra_lua_cpath"] = 
get_lua_path(yaml_conf.apisix.extra_lua_cpath)
diff --git a/apisix/cli/schema.lua b/apisix/cli/schema.lua
index b57b30fed..3e3e85510 100644
--- a/apisix/cli/schema.lua
+++ b/apisix/cli/schema.lua
@@ -291,6 +291,10 @@ local config_schema = {
                     minItems = 1,
                     items = {
                         type = "string",
+                        -- NUL can never be carried through the C environ and
+                        -- other control chars (newline etc.) have no sane
+                        -- config source; reject early with a clear error
+                        pattern = [[\A[^\x00-\x1f]*\z]],
                     }
                 }
             },
diff --git a/t/cli/test_kubernetes.sh b/t/cli/test_kubernetes.sh
index c74718409..5734bcc47 100755
--- a/t/cli/test_kubernetes.sh
+++ b/t/cli/test_kubernetes.sh
@@ -30,17 +30,17 @@ discovery:
 
 make init
 
-if ! grep "env HOST_ENV" conf/nginx.conf; then
+if ! grep 'env "HOST_ENV"' conf/nginx.conf; then
   echo "kubernetes discovery env inject failed"
   exit 1
 fi
 
-if ! grep "env KUBERNETES_SERVICE_PORT" conf/nginx.conf; then
+if ! grep 'env "KUBERNETES_SERVICE_PORT"' conf/nginx.conf; then
   echo "kubernetes discovery env inject failed"
   exit 1
 fi
 
-if ! grep "env TOKEN_ENV" conf/nginx.conf; then
+if ! grep 'env "TOKEN_ENV"' conf/nginx.conf; then
   echo "kubernetes discovery env inject failed"
   exit 1
 fi
@@ -70,32 +70,32 @@ discovery:
 
 make init
 
-if ! grep "env DEV_HOST" conf/nginx.conf; then
+if ! grep 'env "DEV_HOST"' conf/nginx.conf; then
   echo "kubernetes discovery env inject failed"
   exit 1
 fi
 
-if ! grep "env DEV_PORT" conf/nginx.conf; then
+if ! grep 'env "DEV_PORT"' conf/nginx.conf; then
   echo "kubernetes discovery env inject failed"
   exit 1
 fi
 
-if ! grep "env DEV_TOKEN" conf/nginx.conf; then
+if ! grep 'env "DEV_TOKEN"' conf/nginx.conf; then
   echo "kubernetes discovery env inject failed"
   exit 1
 fi
 
-if ! grep "env PRO_HOST" conf/nginx.conf; then
+if ! grep 'env "PRO_HOST"' conf/nginx.conf; then
   echo "kubernetes discovery env inject failed"
   exit 1
 fi
 
-if ! grep "env PRO_PORT" conf/nginx.conf; then
+if ! grep 'env "PRO_PORT"' conf/nginx.conf; then
   echo "kubernetes discovery env inject failed"
   exit 1
 fi
 
-if ! grep "env PRO_TOKEN" conf/nginx.conf; then
+if ! grep 'env "PRO_TOKEN"' conf/nginx.conf; then
   echo "kubernetes discovery env inject failed"
   exit 1
 fi
diff --git a/t/cli/test_main.sh b/t/cli/test_main.sh
index 4dbd96ae5..c0e7d90c0 100755
--- a/t/cli/test_main.sh
+++ b/t/cli/test_main.sh
@@ -226,7 +226,7 @@ nginx_config:
 
 make init
 
-grep "env TEST;" conf/nginx.conf > /dev/null
+grep 'env "TEST";' conf/nginx.conf > /dev/null
 if [ ! $? -eq 0 ]; then
     echo "failed: failed to update env"
     exit 1
@@ -234,6 +234,75 @@ fi
 
 echo "passed: change default env"
 
+# env value with spaces must be rendered as a quoted directive (#11467)
+echo '
+nginx_config:
+    envs:
+        - TEST=a b
+' > conf/config.yaml
+
+make init
+
+if ! grep 'env "TEST=a b";' conf/nginx.conf > /dev/null; then
+    echo "failed: env value with spaces should be quoted"
+    exit 1
+fi
+
+mkdir -p logs
+if ! openresty -p "$PWD" -c "$PWD/conf/nginx.conf" -t; then
+    echo "failed: nginx rejects generated conf with quoted env"
+    exit 1
+fi
+
+# embedded quote / backslash are escaped
+cat > conf/config.yaml <<'EOF'
+nginx_config:
+    envs:
+        - "TEST=a\"b\\c"
+EOF
+
+make init
+
+if ! grep -F 'env "TEST=a\"b\\c";' conf/nginx.conf > /dev/null; then
+    echo "failed: quote/backslash in env value should be escaped"
+    exit 1
+fi
+
+if ! openresty -p "$PWD" -c "$PWD/conf/nginx.conf" -t; then
+    echo "failed: nginx rejects generated conf with escaped env"
+    exit 1
+fi
+
+# control characters are rejected at schema level
+cat > conf/config.yaml <<'EOF'
+nginx_config:
+    envs:
+        - "TEST=a\nb"
+EOF
+
+out=$(make init 2>&1 || true)
+if ! echo "$out" | grep "failed to validate config"; then
+    echo "failed: env value with control chars should be rejected"
+    exit 1
+fi
+
+# entries synthesized by kubernetes discovery bypass the config schema, so the
+# control-character check must also run on the final list
+cat > conf/config.yaml <<'EOF'
+discovery:
+    kubernetes:
+        client:
+            token_file: "${A\nB}"
+EOF
+
+out=$(make init 2>&1 || true)
+if ! echo "$out" | grep "control characters are not allowed"; then
+    echo "failed: synthesized env entry with control chars should be rejected"
+    exit 1
+fi
+
+echo "passed: env value quoting (#11467)"
+
 # support environment variables
 echo '
 nginx_config:
@@ -243,7 +312,7 @@ nginx_config:
 
 var_test=TEST FOO=bar make init
 
-if ! grep "env TEST_bar;" conf/nginx.conf > /dev/null; then
+if ! grep 'env "TEST_bar";' conf/nginx.conf > /dev/null; then
     echo "failed: failed to resolve variables"
     exit 1
 fi
@@ -328,7 +397,7 @@ nginx_config:
 
 var_test=TEST FOO=bar make init
 
-if ! grep "env TEST_bar;" conf/nginx.conf > /dev/null; then
+if ! grep 'env "TEST_bar";' conf/nginx.conf > /dev/null; then
     echo "failed: failed to resolve variables wrapped with whitespace"
     exit 1
 fi
@@ -348,7 +417,7 @@ deployment:
 
 ETCD_HOST=127.0.0.1 ETCD_PORT=2379 make init
 
-if ! grep "env ETCD_HOST;" conf/nginx.conf > /dev/null; then
+if ! grep 'env "ETCD_HOST";' conf/nginx.conf > /dev/null; then
     echo "failed: support environment variables in local_conf"
     exit 1
 fi
@@ -369,12 +438,12 @@ nginx_config:
 
 ETCD_HOST=127.0.0.1 ETCD_PORT=2379 make init
 
-if grep "env ETCD_HOST=.*;" conf/nginx.conf > /dev/null; then
+if grep 'env "ETCD_HOST=.*";' conf/nginx.conf > /dev/null; then
     echo "failed: support environment variables in local_conf"
     exit 1
 fi
 
-if ! grep "env ETCD_HOST;" conf/nginx.conf > /dev/null; then
+if ! grep 'env "ETCD_HOST";' conf/nginx.conf > /dev/null; then
     echo "failed: support environment variables in local_conf"
     exit 1
 fi
@@ -394,12 +463,12 @@ nginx_config:
 
 ETCD_HOST=127.0.0.1 ETCD_PORT=2379 make init
 
-if grep "env ETCD_HOST;" conf/nginx.conf > /dev/null; then
+if grep 'env "ETCD_HOST";' conf/nginx.conf > /dev/null; then
     echo "failed: support environment variables in local_conf"
     exit 1
 fi
 
-if ! grep "env ETCD_HOST=1.1.1.1;" conf/nginx.conf > /dev/null; then
+if ! grep 'env "ETCD_HOST=1.1.1.1";' conf/nginx.conf > /dev/null; then
     echo "failed: support environment variables in local_conf"
     exit 1
 fi
@@ -414,7 +483,7 @@ tests:
 
 make init
 
-if ! grep "env TEST_ENV;" conf/nginx.conf > /dev/null; then
+if ! grep 'env "TEST_ENV";' conf/nginx.conf > /dev/null; then
     echo "failed: should use default value when environment not set"
     exit 1
 fi
@@ -426,7 +495,7 @@ tests:
 
 make init
 
-if ! grep "env TEST_ENV;" conf/nginx.conf > /dev/null; then
+if ! grep 'env "TEST_ENV";' conf/nginx.conf > /dev/null; then
     echo "failed: should use default value when environment not set"
     exit 1
 fi
@@ -438,7 +507,7 @@ tests:
 
 TEST_ENV=127.0.0.1 make init
 
-if ! grep "env TEST_ENV;" conf/nginx.conf > /dev/null; then
+if ! grep 'env "TEST_ENV";' conf/nginx.conf > /dev/null; then
     echo "failed: should use environment variable when environment is set"
     exit 1
 fi
diff --git a/t/cli/test_standalone.sh b/t/cli/test_standalone.sh
index c1e728d7a..e366182b1 100755
--- a/t/cli/test_standalone.sh
+++ b/t/cli/test_standalone.sh
@@ -54,7 +54,7 @@ routes:
 # check for resolve variables
 var_test_path=/test make init
 
-if ! grep "env var_test_path;" conf/nginx.conf > /dev/null; then
+if ! grep 'env "var_test_path";' conf/nginx.conf > /dev/null; then
     echo "failed: failed to resolve variables"
     exit 1
 fi

Reply via email to