Skip to content

Commit

Permalink
call validateCommandVars from within the command.Expand call
Browse files Browse the repository at this point in the history
Signed-off-by: Talon Bowler <talon.bowler@docker.com>
  • Loading branch information
daghack committed May 11, 2024
1 parent 9de5b38 commit e58eee9
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 25 deletions.
52 changes: 29 additions & 23 deletions frontend/dockerfile/dockerfile2llb/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,6 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS
llbCaps: opt.LLBCaps,
sourceMap: opt.SourceMap,
lintWarn: opt.Warn,
argCmdVars: make(map[string]struct{}),
}

if err = dispatchOnBuildTriggers(d, d.image.Config.OnBuild, opt); err != nil {
Expand Down Expand Up @@ -749,17 +748,19 @@ type dispatchOpt struct {
llbCaps *apicaps.CapSet
sourceMap *llb.SourceMap
lintWarn linter.LintWarnFunc
argCmdVars map[string]struct{}
}

func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
env, err := d.state.Env(context.TODO())
if err != nil {
return err
}
var err error
if ex, ok := cmd.Command.(instructions.SupportsSingleWordExpansion); ok {
err := ex.Expand(func(word string) (string, error) {
newword, _, err := opt.shlex.ProcessWord(word, env)
env, err := d.state.Env(context.TODO())
if err != nil {
return "", err
}

newword, unmatched, err := opt.shlex.ProcessWord(word, env)
reportUnmatchedVariables(cmd, d.buildArgs, unmatched, &opt)
return newword, err
})
if err != nil {
Expand All @@ -768,16 +769,20 @@ func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
}
if ex, ok := cmd.Command.(instructions.SupportsSingleWordExpansionRaw); ok {
err := ex.ExpandRaw(func(word string) (string, error) {
env, err := d.state.Env(context.TODO())
if err != nil {
return "", err
}
lex := shell.NewLex('\\')
lex.SkipProcessQuotes = true
newword, _, err := lex.ProcessWord(word, env)
newword, unmatched, err := lex.ProcessWord(word, env)
reportUnmatchedVariables(cmd, d.buildArgs, unmatched, &opt)
return newword, err
})
if err != nil {
return err
}
}
validateCommandVar(cmd.Command, env, &opt)

switch c := cmd.Command.(type) {
case *instructions.MaintainerCommand:
Expand Down Expand Up @@ -837,7 +842,7 @@ func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
case *instructions.ShellCommand:
err = dispatchShell(d, c)
case *instructions.ArgCommand:
err = dispatchArg(d, c, opt.metaArgs, &opt)
err = dispatchArg(d, c, &opt)
case *instructions.CopyCommand:
l := opt.buildContext
if len(cmd.sources) != 0 {
Expand Down Expand Up @@ -1546,10 +1551,9 @@ func dispatchShell(d *dispatchState, c *instructions.ShellCommand) error {
return commitToHistory(&d.image, fmt.Sprintf("SHELL %v", c.Shell), false, nil, d.epoch)
}

func dispatchArg(d *dispatchState, c *instructions.ArgCommand, metaArgs []instructions.KeyValuePairOptional, opt *dispatchOpt) error {
func dispatchArg(d *dispatchState, c *instructions.ArgCommand, opt *dispatchOpt) error {
commitStrs := make([]string, 0, len(c.Args))
for _, arg := range c.Args {
opt.argCmdVars[arg.Key] = struct{}{}
buildArg := setKVValue(arg, opt.buildArgValues)

commitStr := arg.Key
Expand All @@ -1560,7 +1564,7 @@ func dispatchArg(d *dispatchState, c *instructions.ArgCommand, metaArgs []instru

skipArgInfo := false // skip the arg info if the arg is inherited from global scope
if buildArg.Value == nil {
for _, ma := range metaArgs {
for _, ma := range opt.metaArgs {
if ma.Key == buildArg.Key {
buildArg.Value = ma.Value
skipArgInfo = true
Expand Down Expand Up @@ -2046,16 +2050,18 @@ func validateStageNames(stages []instructions.Stage, warn linter.LintWarnFunc) {
}
}

func validateCommandVar(cmd instructions.Command, env []string, opt *dispatchOpt) {
if cmdstr, ok := cmd.(fmt.Stringer); ok {
_, unmatched, _ := opt.shlex.ProcessWord(cmdstr.String(), env)
for arg := range unmatched {
_, argCmdOk := opt.argCmdVars[arg]
_, nonEnvOk := nonEnvArgs[arg]
if !argCmdOk && !nonEnvOk {
msg := linter.RuleUndefinedVar.Format(arg)
linter.RuleUndefinedVar.Run(opt.warn, cmd.Location(), msg)
}
func reportUnmatchedVariables(cmd instructions.Command, buildArgs []instructions.KeyValuePairOptional, unmatched map[string]struct{}, opt *dispatchOpt) {
if len(unmatched) == 0 {
return
}
for _, buildArg := range buildArgs {
delete(unmatched, buildArg.Key)
}
for cmdVar := range unmatched {
_, nonEnvOk := nonEnvArgs[cmdVar]
if !nonEnvOk {
msg := linter.RuleUndefinedVar.Format(cmdVar)
linter.RuleUndefinedVar.Run(opt.lintWarn, cmd.Location(), msg)
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions frontend/dockerfile/dockerfile_lint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ var lintTests = integration.TestFuncs(
testMaintainerDeprecated,
testWarningsBeforeError,
testUndeclaredArg,
testUndefinedVars,
testUnmatchedVars,
)

func testStageName(t *testing.T, sb integration.Sandbox) {
Expand Down Expand Up @@ -488,7 +488,7 @@ COPY Dockerfile .
})
}

func testUndefinedVars(t *testing.T, sb integration.Sandbox) {
func testUnmatchedVars(t *testing.T, sb integration.Sandbox) {
dockerfile := []byte(`
FROM scratch
ARG foo
Expand Down

0 comments on commit e58eee9

Please sign in to comment.