fix(dotenv): unknown vars should expand to empty

This commit is contained in:
Carlo Sala 2026-04-16 20:09:26 +02:00
commit 9b19287c88
No known key found for this signature in database
GPG key ID: DA6FB450C1A4FE9A
2 changed files with 55 additions and 7 deletions

View file

@ -97,6 +97,7 @@ _parse_dotenv_content() {
key="${match[1]}" key="${match[1]}"
value="${match[2]}" value="${match[2]}"
local raw_value="$value"
# Filter out variables to be ignored for security reasons (best effort) # Filter out variables to be ignored for security reasons (best effort)
if [[ "$key" == (${~forbidden}) ]]; then if [[ "$key" == (${~forbidden}) ]]; then
@ -145,14 +146,39 @@ _parse_dotenv_content() {
# Unquote the value to handle special characters and multiline values # Unquote the value to handle special characters and multiline values
value="${(Q)value}" value="${(Q)value}"
# Expand variables from in-file parsed vars (same as double-quoted) # Single-quoted values are fully literal and must not participate in expansion.
local expanded="$value" if [[ "$raw_value" == \'*\' ]]; then
for var_name in "${(@k)parsed_vars}"; do parsed_vars[$key]="$value"
local var_value="${parsed_vars[$var_name]}" if [[ "$mode" == "export" ]]; then
expanded="${expanded//\$\{${var_name}\}/${var_value}}" typeset -x "$key"="$value"
expanded="${expanded//\$${var_name}/${var_value}}" fi
continue
fi
# Expand previously parsed in-file variables without partial name matches.
local expanded="" prefix remainder="$value" var_name
while [[ "$remainder" == *'$'* ]]; do
prefix="${remainder%%\$*}"
expanded+="$prefix"
remainder="${remainder#$prefix}"
if [[ "$remainder" =~ '^\$\{([a-zA-Z_][a-zA-Z0-9_]*)\}(.*)$' ]]; then
var_name="${match[1]}"
remainder="${match[2]}"
elif [[ "$remainder" =~ '^\$([a-zA-Z_][a-zA-Z0-9_]*)(.*)$' ]]; then
var_name="${match[1]}"
remainder="${match[2]}"
else
expanded+='$'
remainder="${remainder#?}"
continue
fi
if [[ -v "parsed_vars[$var_name]" ]]; then
expanded+="${parsed_vars[$var_name]}"
fi
done done
value="$expanded" value="${expanded}${remainder}"
# Store in parsed vars (for in-file expansion) # Store in parsed vars (for in-file expansion)
parsed_vars[$key]="$value" parsed_vars[$key]="$value"

View file

@ -305,3 +305,25 @@ EOF
assert "DOTENV_TEST_VARS" var_same_as "expected_vars" assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
} }
@test 'parse in-file variable expansion prefers the longest matching variable name' {
> "$fixture" <<'EOF'
A=1
ABC=2
X=$ABC
Y=${ABC}
Z=$ABCD
EOF
expected_vars=(
A '1'
ABC '2'
X '2'
Y '2'
Z ''
)
_parse_dotenv_test "$fixture"
assert "DOTENV_TEST_VARS" var_same_as "expected_vars"
}