Skip to content

Commit 49b935f

Browse files
authored
Merge pull request moby#5001 from jsternberg/legacy-env-lint-dispatch-only
dockerfile: only report legacy key/value format when stage is reachable
2 parents 0435475 + c4c2dbf commit 49b935f

File tree

4 files changed

+57
-20
lines changed

4 files changed

+57
-20
lines changed

frontend/dockerfile/dockerfile2llb/convert.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -881,7 +881,7 @@ func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
881881
case *instructions.MaintainerCommand:
882882
err = dispatchMaintainer(d, c)
883883
case *instructions.EnvCommand:
884-
err = dispatchEnv(d, c)
884+
err = dispatchEnv(d, c, opt.lint)
885885
case *instructions.RunCommand:
886886
err = dispatchRun(d, c, opt.proxyEnv, cmd.sources, opt)
887887
case *instructions.WorkdirCommand:
@@ -915,7 +915,7 @@ func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
915915
}
916916
}
917917
case *instructions.LabelCommand:
918-
err = dispatchLabel(d, c)
918+
err = dispatchLabel(d, c, opt.lint)
919919
case *instructions.OnbuildCommand:
920920
err = dispatchOnbuild(d, c)
921921
case *instructions.CmdCommand:
@@ -1104,9 +1104,13 @@ func dispatchOnBuildTriggers(d *dispatchState, triggers []string, opt dispatchOp
11041104
return nil
11051105
}
11061106

1107-
func dispatchEnv(d *dispatchState, c *instructions.EnvCommand) error {
1107+
func dispatchEnv(d *dispatchState, c *instructions.EnvCommand, lint *linter.Linter) error {
11081108
commitMessage := bytes.NewBufferString("ENV")
11091109
for _, e := range c.Env {
1110+
if e.NoDelim {
1111+
msg := linter.RuleLegacyKeyValueFormat.Format(c.Name())
1112+
lint.Run(&linter.RuleLegacyKeyValueFormat, c.Location(), msg)
1113+
}
11101114
commitMessage.WriteString(" " + e.String())
11111115
d.state = d.state.AddEnv(e.Key, e.Value)
11121116
d.image.Config.Env = addEnv(d.image.Config.Env, e.Key, e.Value)
@@ -1562,12 +1566,16 @@ func dispatchMaintainer(d *dispatchState, c *instructions.MaintainerCommand) err
15621566
return commitToHistory(&d.image, fmt.Sprintf("MAINTAINER %v", c.Maintainer), false, nil, d.epoch)
15631567
}
15641568

1565-
func dispatchLabel(d *dispatchState, c *instructions.LabelCommand) error {
1569+
func dispatchLabel(d *dispatchState, c *instructions.LabelCommand, lint *linter.Linter) error {
15661570
commitMessage := bytes.NewBufferString("LABEL")
15671571
if d.image.Config.Labels == nil {
15681572
d.image.Config.Labels = make(map[string]string, len(c.Labels))
15691573
}
15701574
for _, v := range c.Labels {
1575+
if v.NoDelim {
1576+
msg := linter.RuleLegacyKeyValueFormat.Format(c.Name())
1577+
lint.Run(&linter.RuleLegacyKeyValueFormat, c.Location(), msg)
1578+
}
15711579
d.image.Config.Labels[v.Key] = v.Value
15721580
commitMessage.WriteString(" " + v.String())
15731581
}

frontend/dockerfile/dockerfile_lint_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,37 @@ ENV key=value
858858
LABEL key=value
859859
`)
860860
checkLinterWarnings(t, sb, &lintTestParams{Dockerfile: dockerfile})
861+
862+
// Warnings only happen in unmarshal if the lint happens in a
863+
// stage that's not reachable.
864+
dockerfile = []byte(`
865+
FROM scratch AS a
866+
867+
FROM a AS b
868+
ENV key value
869+
LABEL key value
870+
871+
FROM a AS c
872+
`)
873+
checkLinterWarnings(t, sb, &lintTestParams{
874+
Dockerfile: dockerfile,
875+
UnmarshalWarnings: []expectedLintWarning{
876+
{
877+
RuleName: "LegacyKeyValueFormat",
878+
Description: "Legacy key/value format with whitespace separator should not be used",
879+
Detail: "\"ENV key=value\" should be used instead of legacy \"ENV key value\" format",
880+
Line: 3,
881+
Level: 1,
882+
},
883+
{
884+
RuleName: "LegacyKeyValueFormat",
885+
Description: "Legacy key/value format with whitespace separator should not be used",
886+
Detail: "\"LABEL key=value\" should be used instead of legacy \"LABEL key value\" format",
887+
Line: 4,
888+
Level: 1,
889+
},
890+
},
891+
})
861892
}
862893

863894
func checkUnmarshal(t *testing.T, sb integration.Sandbox, lintTest *lintTestParams) {

frontend/dockerfile/instructions/commands.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ import (
1313
// This is useful for commands containing key-value maps that want to preserve
1414
// the order of insertion, instead of map[string]string which does not.
1515
type KeyValuePair struct {
16-
Key string
17-
Value string
16+
Key string
17+
Value string
18+
NoDelim bool
1819
}
1920

2021
func (kvp *KeyValuePair) String() string {
@@ -108,8 +109,9 @@ func expandKvp(kvp KeyValuePair, expander SingleWordExpander) (KeyValuePair, err
108109
if err != nil {
109110
return KeyValuePair{}, err
110111
}
111-
return KeyValuePair{Key: key, Value: value}, nil
112+
return KeyValuePair{Key: key, Value: value, NoDelim: kvp.NoDelim}, nil
112113
}
114+
113115
func expandKvpsInPlace(kvps KeyValuePairs, expander SingleWordExpander) error {
114116
for i, kvp := range kvps {
115117
newKvp, err := expandKvp(kvp, expander)

frontend/dockerfile/instructions/parse.go

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,13 @@ func ParseInstructionWithLinter(node *parser.Node, lint *linter.Linter) (v inter
7878
req := newParseRequestFromNode(node)
7979
switch strings.ToLower(node.Value) {
8080
case command.Env:
81-
return parseEnv(req, lint)
81+
return parseEnv(req)
8282
case command.Maintainer:
8383
msg := linter.RuleMaintainerDeprecated.Format()
8484
lint.Run(&linter.RuleMaintainerDeprecated, node.Location(), msg)
8585
return parseMaintainer(req)
8686
case command.Label:
87-
return parseLabel(req, lint)
87+
return parseLabel(req)
8888
case command.Add:
8989
return parseAdd(req)
9090
case command.Copy:
@@ -193,7 +193,7 @@ func Parse(ast *parser.Node, lint *linter.Linter) (stages []Stage, metaArgs []Ar
193193
return stages, metaArgs, nil
194194
}
195195

196-
func parseKvps(args []string, cmdName string, location []parser.Range, lint *linter.Linter) (KeyValuePairs, error) {
196+
func parseKvps(args []string, cmdName string) (KeyValuePairs, error) {
197197
if len(args) == 0 {
198198
return nil, errAtLeastOneArgument(cmdName)
199199
}
@@ -206,21 +206,17 @@ func parseKvps(args []string, cmdName string, location []parser.Range, lint *lin
206206
if len(args[j]) == 0 {
207207
return nil, errBlankCommandNames(cmdName)
208208
}
209-
name, value, sep := args[j], args[j+1], args[j+2]
210-
if sep == "" {
211-
msg := linter.RuleLegacyKeyValueFormat.Format(cmdName)
212-
lint.Run(&linter.RuleLegacyKeyValueFormat, location, msg)
213-
}
214-
res = append(res, KeyValuePair{Key: name, Value: value})
209+
name, value, delim := args[j], args[j+1], args[j+2]
210+
res = append(res, KeyValuePair{Key: name, Value: value, NoDelim: delim == ""})
215211
}
216212
return res, nil
217213
}
218214

219-
func parseEnv(req parseRequest, lint *linter.Linter) (*EnvCommand, error) {
215+
func parseEnv(req parseRequest) (*EnvCommand, error) {
220216
if err := req.flags.Parse(); err != nil {
221217
return nil, err
222218
}
223-
envs, err := parseKvps(req.args, "ENV", req.location, lint)
219+
envs, err := parseKvps(req.args, "ENV")
224220
if err != nil {
225221
return nil, err
226222
}
@@ -244,12 +240,12 @@ func parseMaintainer(req parseRequest) (*MaintainerCommand, error) {
244240
}, nil
245241
}
246242

247-
func parseLabel(req parseRequest, lint *linter.Linter) (*LabelCommand, error) {
243+
func parseLabel(req parseRequest) (*LabelCommand, error) {
248244
if err := req.flags.Parse(); err != nil {
249245
return nil, err
250246
}
251247

252-
labels, err := parseKvps(req.args, "LABEL", req.location, lint)
248+
labels, err := parseKvps(req.args, "LABEL")
253249
if err != nil {
254250
return nil, err
255251
}

0 commit comments

Comments
 (0)