Verified Production Fix
[docker/cli] Expand environment variables in docker plugin config string
GH-docker/cli#6486 • Mar 07, 2026
### ROOT CAUSE
The Docker CLI does not currently support expanding environment variables within configuration strings. Environment variables enclosed in `${}` or `$$` are not parsed or replaced with their corresponding values from the system's environment.
### CODE FIX
To enable environment variable expansion in Docker CLI configuration strings, we'll modify the configuration parsing logic to replace these variables with their actual values.
**Step-by-step Explanation:**
1. **Create a function to expand variables in strings:**
- This function will recursively expand variables until all variables are resolved.
- It will handle both `${VAR}` and `$VAR` syntax.
- If a variable is not found, it will return the original string with the variable left intact.
2. **Modify the configuration parsing logic:**
- After loading the configuration, apply the variable expansion function to all relevant configuration strings.
3. **Update the test cases:**
- Add tests to ensure environment variables in configuration strings are correctly expanded.
**Implementing the Fix:**
// In config.go, add the following function to expand environment variables in strings.
func expandEnvVariables(s string) string {
// Split the string into segments to handle multiple variables
segments := make([]string, 0)
scanner := bufio.NewScanner(strings.NewReader(s))
var varName strings.Builder
inVar := false
for scanner.Scan() {
c := scanner.Text()
if c == '$' {
inVar = true
varName.Reset()
} else if c == ' ' && inVar {
inVar = false
segments = append(segments, varName.String())
segments = append(segments, " ")
} else if c == '}' && inVar {
inVar = false
segments = append(segments, varName.String())
} else if inVar {
varName.WriteString(c)
} else {
segments = append(segments, c)
}
}
if inVar {
segments = append(segments, varName.String())
}
// Now join the segments and expand variables
var expanded strings.Builder
for _, segment := range segments {
if strings.HasPrefix(segment, "${") || strings.HasPrefix(segment, "$") {
varNameStr := strings.TrimPrefix(segment, "$")
varNameStr = strings.TrimSuffix(varNameStr, "}")
value, err := os.LookupEnv(varNameStr)
if err != nil {
// Variable not found, append the original string
expanded.WriteString(segment)
} else {
expanded.WriteString(value)
}
} else {
expanded.WriteString(segment)
}
}
return expanded.String()
}
**Update the configuration loading logic:**
// In config.go, modify the Load method to expand variables.
func (c *Config) Load(file string) error {
// ... existing code to load config ...
// After loading the config, expand environment variables in the necessary fields
c.Daemon.Address = expandEnvVariables(c.Daemon.Address)
c.Plugins.Path = expandEnvVariables(c.Plugins.Path)
// ... expand other necessary fields ...
return nil
}
**Add test cases:**
// In config_test.go, add the following test cases.
func TestExpandEnvVariables(t *testing.T) {
testCases := []struct {
input string
output string
}{
{
input: "${HOMEBREW_PREFIX}/lib/docker/cli-plugins",
output: os.Getenv("HOMEBREW_PREFIX") + "/lib/docker/cli-plugins",
},
{
input: "$PATH",
output: os.Getenv("PATH"),
},
{
input: "No variable here",
output: "No variable here",
},
{
input: "Hello ${USER}, welcome to $GOPATH",
output: "Hello " + os.Getenv("USER") + ", welcome to " + os.Getenv("GOPATH"),
},
}
for _, tc := range testCases {
t.Run(tc.input, func(t *testing.T) {
result := expandEnvVariables(tc.input)
if result != tc.output {
t.Errorf("Expected: %s, Got: %s", tc.output, result)
}
})
}
}
This fix introduces environment variable expansion in Docker CLI configuration strings, allowing users to define paths and other values using system environment variables.
Deploy with DigitalOcean
Use this fix in production instantly. Claim your $200 developer credit.
Get Started →
digital