1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Fix --label being env var expanded.

Signed-off-by: Daniel Nephin <dnephin@docker.com>
This commit is contained in:
Daniel Nephin 2017-03-13 17:25:37 -04:00
parent 726fb269cf
commit 434d77bc0e
5 changed files with 62 additions and 73 deletions

View file

@ -129,47 +129,18 @@ func (b *Builder) dispatch(stepN int, stepTotal int, ast *parser.Node) error {
} }
// count the number of nodes that we are going to traverse first msgList := initMsgList(ast)
// so we can pre-create the argument and message array. This speeds up the
// allocation of those list a lot when they have a lot of arguments
cursor := ast
var n int
for cursor.Next != nil {
cursor = cursor.Next
n++
}
msgList := make([]string, n)
var i int
// Append build args to runConfig environment variables // Append build args to runConfig environment variables
envs := append(b.runConfig.Env, b.buildArgsWithoutConfigEnv()...) envs := append(b.runConfig.Env, b.buildArgsWithoutConfigEnv()...)
for ast.Next != nil { for i := 0; ast.Next != nil; i++ {
ast = ast.Next ast = ast.Next
var str string words, err := b.evaluateEnv(cmd, ast.Value, envs)
str = ast.Value if err != nil {
if replaceEnvAllowed[cmd] { return err
var err error
var words []string
if allowWordExpansion[cmd] {
words, err = ProcessWords(str, envs, b.directive.EscapeToken)
if err != nil {
return err
}
strList = append(strList, words...)
} else {
str, err = ProcessWord(str, envs, b.directive.EscapeToken)
if err != nil {
return err
}
strList = append(strList, str)
}
} else {
strList = append(strList, str)
} }
strList = append(strList, words...)
msgList[i] = ast.Value msgList[i] = ast.Value
i++
} }
msg += " " + strings.Join(msgList, " ") msg += " " + strings.Join(msgList, " ")
@ -186,6 +157,29 @@ func (b *Builder) dispatch(stepN int, stepTotal int, ast *parser.Node) error {
return fmt.Errorf("Unknown instruction: %s", upperCasedCmd) return fmt.Errorf("Unknown instruction: %s", upperCasedCmd)
} }
// count the number of nodes that we are going to traverse first
// allocation of those list a lot when they have a lot of arguments
func initMsgList(cursor *parser.Node) []string {
var n int
for ; cursor.Next != nil; n++ {
cursor = cursor.Next
}
return make([]string, n)
}
func (b *Builder) evaluateEnv(cmd string, str string, envs []string) ([]string, error) {
if !replaceEnvAllowed[cmd] {
return []string{str}, nil
}
var processFunc func(string, []string, rune) ([]string, error)
if allowWordExpansion[cmd] {
processFunc = ProcessWords
} else {
processFunc = ProcessWord
}
return processFunc(str, envs, b.directive.EscapeToken)
}
// buildArgsWithoutConfigEnv returns a list of key=value pairs for all the build // buildArgsWithoutConfigEnv returns a list of key=value pairs for all the build
// args that are not overriden by runConfig environment variables. // args that are not overriden by runConfig environment variables.
func (b *Builder) buildArgsWithoutConfigEnv() []string { func (b *Builder) buildArgsWithoutConfigEnv() []string {

View file

@ -220,7 +220,9 @@ func NodeFromLabels(labels map[string]string) *Node {
for _, key := range keys { for _, key := range keys {
value := labels[key] value := labels[key]
labelPairs = append(labelPairs, fmt.Sprintf("%q='%s'", key, value)) labelPairs = append(labelPairs, fmt.Sprintf("%q='%s'", key, value))
node := newKeyValueNode(key, value) // Value must be single quoted to prevent env variable expansion
// See https://github.com/docker/docker/issues/26027
node := newKeyValueNode(key, "'"+value+"'")
rootNode, prevNode = appendKeyValueNode(node, rootNode, prevNode) rootNode, prevNode = appendKeyValueNode(node, rootNode, prevNode)
} }

View file

@ -40,19 +40,19 @@ func TestParseNameValNewFormat(t *testing.T) {
func TestNodeFromLabels(t *testing.T) { func TestNodeFromLabels(t *testing.T) {
labels := map[string]string{ labels := map[string]string{
"foo": "bar", "foo": "bar",
"weird": "'first second'", "weird": "first' second",
} }
expected := &Node{ expected := &Node{
Value: "label", Value: "label",
Original: `LABEL "foo"='bar' "weird"=''first second''`, Original: `LABEL "foo"='bar' "weird"='first' second'`,
Next: &Node{ Next: &Node{
Value: "foo", Value: "foo",
Next: &Node{ Next: &Node{
Value: "bar", Value: "'bar'",
Next: &Node{ Next: &Node{
Value: "weird", Value: "weird",
Next: &Node{ Next: &Node{
Value: "'first second'", Value: "'first' second'",
}, },
}, },
}, },

View file

@ -24,16 +24,9 @@ type shellWord struct {
// ProcessWord will use the 'env' list of environment variables, // ProcessWord will use the 'env' list of environment variables,
// and replace any env var references in 'word'. // and replace any env var references in 'word'.
func ProcessWord(word string, env []string, escapeToken rune) (string, error) { func ProcessWord(word string, env []string, escapeToken rune) ([]string, error) {
sw := &shellWord{ word, _, err := process(word, env, escapeToken)
word: word, return []string{word}, err
envs: env,
pos: 0,
escapeToken: escapeToken,
}
sw.scanner.Init(strings.NewReader(word))
word, _, err := sw.process()
return word, err
} }
// ProcessWords will use the 'env' list of environment variables, // ProcessWords will use the 'env' list of environment variables,
@ -44,6 +37,11 @@ func ProcessWord(word string, env []string, escapeToken rune) (string, error) {
// Note, each one is trimmed to remove leading and trailing spaces (unless // Note, each one is trimmed to remove leading and trailing spaces (unless
// they are quoted", but ProcessWord retains spaces between words. // they are quoted", but ProcessWord retains spaces between words.
func ProcessWords(word string, env []string, escapeToken rune) ([]string, error) { func ProcessWords(word string, env []string, escapeToken rune) ([]string, error) {
_, words, err := process(word, env, escapeToken)
return words, err
}
func process(word string, env []string, escapeToken rune) (string, []string, error) {
sw := &shellWord{ sw := &shellWord{
word: word, word: word,
envs: env, envs: env,
@ -51,8 +49,7 @@ func ProcessWords(word string, env []string, escapeToken rune) ([]string, error)
escapeToken: escapeToken, escapeToken: escapeToken,
} }
sw.scanner.Init(strings.NewReader(word)) sw.scanner.Init(strings.NewReader(word))
_, words, err := sw.process() return sw.process()
return words, err
} }
func (sw *shellWord) process() (string, []string, error) { func (sw *shellWord) process() (string, []string, error) {

View file

@ -6,6 +6,8 @@ import (
"runtime" "runtime"
"strings" "strings"
"testing" "testing"
"github.com/docker/docker/pkg/testutil/assert"
) )
func TestShellParser4EnvVars(t *testing.T) { func TestShellParser4EnvVars(t *testing.T) {
@ -13,9 +15,7 @@ func TestShellParser4EnvVars(t *testing.T) {
lineCount := 0 lineCount := 0
file, err := os.Open(fn) file, err := os.Open(fn)
if err != nil { assert.NilError(t, err)
t.Fatalf("Can't open '%s': %s", err, fn)
}
defer file.Close() defer file.Close()
scanner := bufio.NewScanner(file) scanner := bufio.NewScanner(file)
@ -36,29 +36,25 @@ func TestShellParser4EnvVars(t *testing.T) {
} }
words := strings.Split(line, "|") words := strings.Split(line, "|")
if len(words) != 3 { assert.Equal(t, len(words), 3)
t.Fatalf("Error in '%s' - should be exactly one | in:%q", fn, line)
}
words[0] = strings.TrimSpace(words[0]) platform := strings.TrimSpace(words[0])
words[1] = strings.TrimSpace(words[1]) source := strings.TrimSpace(words[1])
words[2] = strings.TrimSpace(words[2]) expected := strings.TrimSpace(words[2])
// Key W=Windows; A=All; U=Unix // Key W=Windows; A=All; U=Unix
if (words[0] != "W") && (words[0] != "A") && (words[0] != "U") { if platform != "W" && platform != "A" && platform != "U" {
t.Fatalf("Invalid tag %s at line %d of %s. Must be W, A or U", words[0], lineCount, fn) t.Fatalf("Invalid tag %s at line %d of %s. Must be W, A or U", platform, lineCount, fn)
} }
if ((words[0] == "W" || words[0] == "A") && runtime.GOOS == "windows") || if ((platform == "W" || platform == "A") && runtime.GOOS == "windows") ||
((words[0] == "U" || words[0] == "A") && runtime.GOOS != "windows") { ((platform == "U" || platform == "A") && runtime.GOOS != "windows") {
newWord, err := ProcessWord(words[1], envs, '\\') newWord, err := ProcessWord(source, envs, '\\')
if expected == "error" {
if err != nil { assert.Error(t, err, "")
newWord = "error" } else {
} assert.NilError(t, err)
assert.DeepEqual(t, newWord, []string{expected})
if newWord != words[2] {
t.Fatalf("Error. Src: %s Calc: %s Expected: %s at line %d", words[1], newWord, words[2], lineCount)
} }
} }
} }