← Back to Dashboard
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 →