Skip to content

Commit

Permalink
Merge pull request moby#4889 from jsternberg/lint-json-args-required-…
Browse files Browse the repository at this point in the history
…sans-shell

linter: add lint rule for required json arguments
  • Loading branch information
tonistiigi authored May 7, 2024
2 parents b3cee61 + 79b0c96 commit 59adccf
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 4 deletions.
20 changes: 16 additions & 4 deletions frontend/dockerfile/dockerfile2llb/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,7 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS
cgroupParent: opt.CgroupParent,
llbCaps: opt.LLBCaps,
sourceMap: opt.SourceMap,
lintWarn: opt.Warn,
}

if err = dispatchOnBuildTriggers(d, d.image.Config.OnBuild, opt); err != nil {
Expand Down Expand Up @@ -746,6 +747,7 @@ type dispatchOpt struct {
cgroupParent string
llbCaps *apicaps.CapSet
sourceMap *llb.SourceMap
lintWarn linter.LintWarnFunc
}

func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
Expand Down Expand Up @@ -820,9 +822,9 @@ func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
case *instructions.OnbuildCommand:
err = dispatchOnbuild(d, c)
case *instructions.CmdCommand:
err = dispatchCmd(d, c)
err = dispatchCmd(d, c, opt.lintWarn)
case *instructions.EntrypointCommand:
err = dispatchEntrypoint(d, c)
err = dispatchEntrypoint(d, c, opt.lintWarn)
case *instructions.HealthCheckCommand:
err = dispatchHealthcheck(d, c)
case *instructions.ExposeCommand:
Expand Down Expand Up @@ -1051,6 +1053,8 @@ func dispatchRun(d *dispatchState, c *instructions.RunCommand, proxy *llb.ProxyE
}
}
if c.PrependShell {
// Don't pass the linter function because we do not report a warning for
// shell usage on run commands.
args = withShell(d.image, args)
}

Expand Down Expand Up @@ -1435,9 +1439,13 @@ func dispatchOnbuild(d *dispatchState, c *instructions.OnbuildCommand) error {
return nil
}

func dispatchCmd(d *dispatchState, c *instructions.CmdCommand) error {
func dispatchCmd(d *dispatchState, c *instructions.CmdCommand, warn linter.LintWarnFunc) error {
var args []string = c.CmdLine
if c.PrependShell {
if len(d.image.Config.Shell) == 0 {
msg := linter.RuleJSONArgsRecommended.Format(c.Name())
linter.RuleJSONArgsRecommended.Run(warn, c.Location(), msg)
}
args = withShell(d.image, args)
}
d.image.Config.Cmd = args
Expand All @@ -1446,9 +1454,13 @@ func dispatchCmd(d *dispatchState, c *instructions.CmdCommand) error {
return commitToHistory(&d.image, fmt.Sprintf("CMD %q", args), false, nil, d.epoch)
}

func dispatchEntrypoint(d *dispatchState, c *instructions.EntrypointCommand) error {
func dispatchEntrypoint(d *dispatchState, c *instructions.EntrypointCommand, warn linter.LintWarnFunc) error {
var args []string = c.CmdLine
if c.PrependShell {
if len(d.image.Config.Shell) == 0 {
msg := linter.RuleJSONArgsRecommended.Format(c.Name())
linter.RuleJSONArgsRecommended.Run(warn, c.Location(), msg)
}
args = withShell(d.image, args)
}
d.image.Config.Entrypoint = args
Expand Down
69 changes: 69 additions & 0 deletions frontend/dockerfile/dockerfile_lint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var lintTests = integration.TestFuncs(
testFileConsistentCommandCasing,
testDuplicateStageName,
testReservedStageName,
testJSONArgsRecommended,
testMaintainerDeprecated,
testWarningsBeforeError,
testUndeclaredArg,
Expand Down Expand Up @@ -302,6 +303,74 @@ FROM scratch AS a
checkLinterWarnings(t, sb, &lintTestParams{Dockerfile: dockerfile})
}

func testJSONArgsRecommended(t *testing.T, sb integration.Sandbox) {
dockerfile := []byte(`
FROM scratch
CMD mycommand
`)
checkLinterWarnings(t, sb, &lintTestParams{
Dockerfile: dockerfile,
Warnings: []expectedLintWarning{
{
RuleName: "JSONArgsRecommended",
Description: "JSON arguments recommended for ENTRYPOINT/CMD to prevent unintended behavior related to OS signals",
Detail: "JSON arguments recommended for CMD to prevent unintended behavior related to OS signals",
Level: 1,
Line: 3,
},
},
})

dockerfile = []byte(`
FROM scratch
ENTRYPOINT mycommand
`)
checkLinterWarnings(t, sb, &lintTestParams{
Dockerfile: dockerfile,
Warnings: []expectedLintWarning{
{
RuleName: "JSONArgsRecommended",
Description: "JSON arguments recommended for ENTRYPOINT/CMD to prevent unintended behavior related to OS signals",
Detail: "JSON arguments recommended for ENTRYPOINT to prevent unintended behavior related to OS signals",
Level: 1,
Line: 3,
},
},
})

dockerfile = []byte(`
FROM scratch
SHELL ["/usr/bin/customshell"]
CMD mycommand
`)
checkLinterWarnings(t, sb, &lintTestParams{Dockerfile: dockerfile})

dockerfile = []byte(`
FROM scratch
SHELL ["/usr/bin/customshell"]
ENTRYPOINT mycommand
`)
checkLinterWarnings(t, sb, &lintTestParams{Dockerfile: dockerfile})

dockerfile = []byte(`
FROM scratch AS base
SHELL ["/usr/bin/customshell"]
FROM base
CMD mycommand
`)
checkLinterWarnings(t, sb, &lintTestParams{Dockerfile: dockerfile})

dockerfile = []byte(`
FROM scratch AS base
SHELL ["/usr/bin/customshell"]
FROM base
ENTRYPOINT mycommand
`)
checkLinterWarnings(t, sb, &lintTestParams{Dockerfile: dockerfile})
}

func testMaintainerDeprecated(t *testing.T, sb integration.Sandbox) {
dockerfile := []byte(`
FROM scratch
Expand Down
7 changes: 7 additions & 0 deletions frontend/dockerfile/linter/ruleset.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ var (
return fmt.Sprintf("Stage name should not use the same name as reserved stage %q", reservedStageName)
},
}
RuleJSONArgsRecommended = LinterRule[func(instructionName string) string]{
Name: "JSONArgsRecommended",
Description: "JSON arguments recommended for ENTRYPOINT/CMD to prevent unintended behavior related to OS signals",
Format: func(instructionName string) string {
return fmt.Sprintf("JSON arguments recommended for %s to prevent unintended behavior related to OS signals", instructionName)
},
}
RuleMaintainerDeprecated = LinterRule[func() string]{
Name: "MaintainerDeprecated",
Description: "The maintainer instruction is deprecated, use a label instead to define an image author",
Expand Down

0 comments on commit 59adccf

Please sign in to comment.