Skip to content

fix: disable automatic type conversion for env vars in apisix.yaml#13078

Open
lxbme wants to merge 2 commits intoapache:masterfrom
lxbme:fix/issue-12932
Open

fix: disable automatic type conversion for env vars in apisix.yaml#13078
lxbme wants to merge 2 commits intoapache:masterfrom
lxbme:fix/issue-12932

Conversation

@lxbme
Copy link

@lxbme lxbme commented Mar 6, 2026

  • Add optional parameter 'enable_type_conversion' to resolve_conf_var function
  • Disable type conversion when processing apisix.yaml in standalone mode
  • Keep type conversion enabled for config.yaml to maintain backward compatibility
  • Add test cases for large numeric strings and type preservation

This fixes the issue where environment variables containing large numbers (exceeding Lua's double precision) were automatically converted to scientific notation in standalone mode, causing validation errors in plugins like openid-connect.

Fixes #12932

Description

This PR fixes the automatic type conversion issue for environment variables in standalone mode apisix.yaml.

When using environment variables in apisix.yaml (standalone mode), numeric string values were automatically converted to numbers. This caused issues when:

  1. The numeric value exceeds Lua's double precision (e.g., 356002209726529540)
  2. The value is converted to scientific notation (e.g., 3.5600220972653e+17)
  3. Plugins requiring string types fail validation (e.g., openid-connect plugin's client_id)

Which issue(s) this PR fixes:

Fixes #12932

Checklist

  • [ x ] I have explained the need for this PR and the problem it solves
  • [ x ] I have explained the changes or the new features added to this PR
  • [ x ] I have added tests corresponding to this change
  • [ x ] I have updated the documentation to reflect this change
    (No documentation update needed - this is an internal bug fix with no user-facing configuration changes)
  • [ x ] I have verified that this change is backward compatible (If not, please discuss on the APISIX mailing list first)

- Add optional parameter 'enable_type_conversion' to resolve_conf_var function
- Disable type conversion when processing apisix.yaml in standalone mode
- Keep type conversion enabled for config.yaml to maintain backward compatibility
- Add test cases for large numeric strings and type preservation

This fixes the issue where environment variables containing large numbers
(exceeding Lua's double precision) were automatically converted to scientific
notation in standalone mode, causing validation errors in plugins like
openid-connect.

Fixes apache#12932
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. bug Something isn't working labels Mar 6, 2026
@Baoyuantop Baoyuantop requested a review from Copilot March 6, 2026 10:37
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses an issue in standalone mode where environment-variable substitutions in apisix.yaml were automatically type-converted (e.g., large numeric strings becoming scientific-notation numbers), leading to schema validation failures in plugins like openid-connect.

Changes:

  • Added an enable_type_conversion parameter to resolve_conf_var to control env-var type casting.
  • Disabled type conversion when parsing apisix.yaml via the CLI path, while keeping it enabled for config.yaml.
  • Added standalone-mode CLI tests intended to cover large numeric strings and type preservation.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
apisix/cli/file.lua Adds a flag to control env-var type conversion and disables conversion for CLI parsing of apisix.yaml.
t/cli/test_standalone.sh Adds regression tests for large numeric env var handling and attempts to ensure config.yaml conversion remains enabled.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +257 to +272
node_listen: ${{NODE_PORT}}
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
' > conf/config.yaml

NODE_PORT=9080 make init

if ! grep "listen 0.0.0.0:9080" conf/nginx.conf > /dev/null; then
echo "failed: numeric env var in config.yaml should be converted to number"
exit 1
fi

echo "passed: config.yaml still converts numeric env vars correctly"

Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grepping for listen 0.0.0.0:9080 doesn't prove type conversion is still happening, since both a string and a number can render identically in nginx.conf. To validate conversion is preserved for config.yaml, assert a type-sensitive field (e.g., apisix.enable_admin: ${{ENABLE_ADMIN}} with ENABLE_ADMIN=false and verify the admin API is disabled) or otherwise check a value that would fail schema validation if left as a string.

Suggested change
node_listen: ${{NODE_PORT}}
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
' > conf/config.yaml
NODE_PORT=9080 make init
if ! grep "listen 0.0.0.0:9080" conf/nginx.conf > /dev/null; then
echo "failed: numeric env var in config.yaml should be converted to number"
exit 1
fi
echo "passed: config.yaml still converts numeric env vars correctly"
enable_admin: ${{ENABLE_ADMIN}}
deployment:
role: data_plane
role_data_plane:
config_provider: yaml
' > conf/config.yaml
ENABLE_ADMIN=false make init
ENABLE_ADMIN=false make run
sleep 1
if curl -s -o /dev/null http://127.0.0.1:9180/apisix/admin/routes; then
echo "failed: admin API should be disabled when ENABLE_ADMIN=false in config.yaml"
make stop
exit 1
fi
make stop
echo "passed: config.yaml still converts boolean env vars correctly"

Copilot uses AI. Check for mistakes.
local function resolve_conf_var(conf)
local function resolve_conf_var(conf, enable_type_conversion)
if enable_type_conversion == nil then
enable_type_conversion = true
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolve_conf_var now defaults enable_type_conversion to true, but apisix/core/config_yaml.lua calls file.resolve_conf_var(table) when reloading apisix.yaml in standalone mode. That means type conversion is still enabled at runtime for apisix.yaml, so the large-number/scientific-notation issue will persist unless that call site is updated to pass false (or otherwise disable conversion for apisix.yaml).

Suggested change
enable_type_conversion = true
enable_type_conversion = false

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer keeping the default enable_type_conversion = true to ensure backward compatibility. Since _M.resolve_conf_var is a public function, changing the global default would silently break existing callers (like config.yaml processing) that rely on type conversion.
Because this fix is specific to apisix.yaml in standalone mode, it's safer for those specific call sites to explicitly opt out by passing false. I'll also add file.resolve_conf_var(table, false) to update_config() in apisix/core/config_yaml.lua to handle runtime reloads.

Comment on lines +175 to +178
openid-connect:
client_id: "${{APISIX_CLIENT_ID}}"
client_secret: "secret"
discovery: "http://example.com/.well-known/openid-configuration"
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test uses openid-connect with a placeholder discovery URL and then treats an HTTP 500 as evidence of type conversion. That can be flaky because 500s may come from plugin runtime behavior (failed discovery fetch, etc.) rather than config type conversion. Consider switching to a plugin with no external dependencies (e.g., response-rewrite with body: ${{APISIX_CLIENT_ID}}) and assert the response body matches the exact large numeric string (not scientific notation).

Suggested change
openid-connect:
client_id: "${{APISIX_CLIENT_ID}}"
client_secret: "secret"
discovery: "http://example.com/.well-known/openid-configuration"
response-rewrite:
body: "${{APISIX_CLIENT_ID}}"

Copilot uses AI. Check for mistakes.
Comment on lines +199 to +200
if [ $code -eq 500 ]; then
echo "failed: large number env var was converted to scientific notation"
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The curl assertion only fails on status 500, so it will still pass if APISIX isn't reachable (000) or if the route wasn't loaded due to schema validation (404). To make the test reliable, assert a known-success status (typically 200) and/or explicitly fail if curl returns 000/404.

Suggested change
if [ $code -eq 500 ]; then
echo "failed: large number env var was converted to scientific notation"
if [ "$code" != "200" ]; then
echo "failed: expected 200 from /test-large-number, got $code (large number env var may have caused an error)"

Copilot uses AI. Check for mistakes.
sleep 0.1

code=$(curl -s -H "Host: test.com" http://127.0.0.1:9080/test-quoted -o /dev/null -w %{http_code})
if [ ! $code -eq 404 ] && [ ! $code -eq 200 ]; then
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check allows 404, which can mask a failure to load the route (e.g., schema validation failing because the env var was converted to a number). To actually validate behavior, assert 200 for a known-working upstream, or check the error log for the absence of schema/type-validation errors.

Suggested change
if [ ! $code -eq 404 ] && [ ! $code -eq 200 ]; then
if [ "$code" -ne 200 ]; then

Copilot uses AI. Check for mistakes.
- Pass false to resolve_conf_var in config_yaml.lua update_config()
  to disable type conversion at runtime for apisix.yaml
- Improve test cases: use response-rewrite plugin for deterministic
  body assertions, use boolean type conversion test for config.yaml
@lxbme
Copy link
Author

lxbme commented Mar 6, 2026

Here's a summary of the changes I have pushed in the newest commit:

Code fix:

  • Updated apisix/core/config_yaml.lua: update_config() now calls file.resolve_conf_var(table, false) to disable type conversion when reloading apisix.yaml at runtime. This was the missing call site that Copilot correctly identified.
  • Kept the default value of enable_type_conversion as true in resolve_conf_var() to maintain backward compatibility.

Test improvements:

  • Replaced openid-connect plugin with response-rewrite to eliminate external dependencies and enable deterministic assertions.
  • Changed assertions from HTTP status code checks to exact response body matching (e.g., verifying 356002209726529540 is not converted to 3.5600220972653e+17).
  • Replaced the node_listen / nginx.conf grep test with a type-sensitive boolean test: enable_admin: ${{ENABLE_ADMIN}} with ENABLE_ADMIN=false, verifying the admin API is actually disabled (proves string to boolean conversion works in config.yaml).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: String environment variable value is casted tonumber if contains a number in standalone mode

2 participants