Skip to content

Commit 88b2f70

Browse files
committed
dockerfile: detect base image with wrong platform being used
Signed-off-by: Tonis Tiigi <[email protected]>
1 parent 2de369c commit 88b2f70

File tree

4 files changed

+101
-3
lines changed

4 files changed

+101
-3
lines changed

frontend/dockerfile/dockerfile2llb/convert.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,7 @@ func toDispatchState(ctx context.Context, dt []byte, opt ConvertOpt) (*dispatchS
539539
llb.WithCustomName(prefixCommand(d, "FROM "+d.stage.BaseName, opt.MultiPlatformRequested, platform, nil)),
540540
location(opt.SourceMap, d.stage.Location),
541541
)
542+
validateBaseImagePlatform(origName, *platform, d.image.Platform, d.stage.Location, opt.Warn)
542543
}
543544
d.platform = platform
544545
return nil
@@ -2204,3 +2205,12 @@ func wrapSuggestAny(err error, keys map[string]struct{}, options []string) error
22042205
}
22052206
return err
22062207
}
2208+
2209+
func validateBaseImagePlatform(name string, expected, actual ocispecs.Platform, location []parser.Range, warn linter.LintWarnFunc) {
2210+
if expected.OS != actual.OS || expected.Architecture != actual.Architecture {
2211+
expectedStr := platforms.Format(platforms.Normalize(expected))
2212+
actualStr := platforms.Format(platforms.Normalize(actual))
2213+
msg := linter.RuleInvalidBaseImagePlatform.Format(name, expectedStr, actualStr)
2214+
linter.RuleInvalidBaseImagePlatform.Run(warn, location, msg)
2215+
}
2216+
}

frontend/dockerfile/dockerfile_lint_test.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ var lintTests = integration.TestFuncs(
3737
testUnmatchedVars,
3838
testMultipleInstructionsDisallowed,
3939
testLegacyKeyValueFormat,
40+
testBaseImagePlatformMismatch,
4041
)
4142

4243
func testStageName(t *testing.T, sb integration.Sandbox) {
@@ -800,10 +801,15 @@ func checkProgressStream(t *testing.T, sb integration.Sandbox, lintTest *lintTes
800801

801802
f := getFrontend(t, sb)
802803

803-
_, err := f.Solve(sb.Context(), lintTest.Client, client.SolveOpt{
804-
FrontendAttrs: map[string]string{
804+
attrs := lintTest.FrontendAttrs
805+
if attrs == nil {
806+
attrs = map[string]string{
805807
"platform": "linux/amd64,linux/arm64",
806-
},
808+
}
809+
}
810+
811+
_, err := f.Solve(sb.Context(), lintTest.Client, client.SolveOpt{
812+
FrontendAttrs: attrs,
807813
LocalMounts: map[string]fsutil.FS{
808814
dockerui.DefaultLocalNameDockerfile: lintTest.TmpDir,
809815
dockerui.DefaultLocalNameContext: lintTest.TmpDir,
@@ -915,4 +921,5 @@ type lintTestParams struct {
915921
StreamBuildErr string
916922
UnmarshalBuildErr string
917923
BuildErrLocation int32
924+
FrontendAttrs map[string]string
918925
}

frontend/dockerfile/dockerfile_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7073,6 +7073,80 @@ func testSourcePolicyWithNamedContext(t *testing.T, sb integration.Sandbox) {
70737073
require.Equal(t, "foo", string(dt))
70747074
}
70757075

7076+
func testBaseImagePlatformMismatch(t *testing.T, sb integration.Sandbox) {
7077+
integration.SkipOnPlatform(t, "windows")
7078+
workers.CheckFeatureCompat(t, sb, workers.FeatureDirectPush)
7079+
ctx := sb.Context()
7080+
7081+
c, err := client.New(ctx, sb.Address())
7082+
require.NoError(t, err)
7083+
defer c.Close()
7084+
7085+
registry, err := sb.NewRegistry()
7086+
if errors.Is(err, integration.ErrRequirements) {
7087+
t.Skip(err.Error())
7088+
}
7089+
require.NoError(t, err)
7090+
7091+
f := getFrontend(t, sb)
7092+
7093+
dockerfile := []byte(`
7094+
FROM scratch
7095+
COPY foo /foo
7096+
`)
7097+
dir := integration.Tmpdir(
7098+
t,
7099+
fstest.CreateFile("Dockerfile", dockerfile, 0600),
7100+
fstest.CreateFile("foo", []byte("test"), 0644),
7101+
)
7102+
7103+
// choose target platform that is different from the current platform
7104+
targetPlatform := runtime.GOOS + "/arm64"
7105+
if runtime.GOARCH == "arm64" {
7106+
targetPlatform = runtime.GOOS + "/amd64"
7107+
}
7108+
7109+
target := registry + "/buildkit/testbaseimageplatform:latest"
7110+
_, err = f.Solve(sb.Context(), c, client.SolveOpt{
7111+
LocalMounts: map[string]fsutil.FS{
7112+
dockerui.DefaultLocalNameDockerfile: dir,
7113+
dockerui.DefaultLocalNameContext: dir,
7114+
},
7115+
FrontendAttrs: map[string]string{
7116+
"platform": targetPlatform,
7117+
},
7118+
Exports: []client.ExportEntry{
7119+
{
7120+
Type: client.ExporterImage,
7121+
Attrs: map[string]string{
7122+
"name": target,
7123+
"push": "true",
7124+
},
7125+
},
7126+
},
7127+
}, nil)
7128+
require.NoError(t, err)
7129+
7130+
dockerfile = []byte(fmt.Sprintf(`
7131+
FROM %s
7132+
ENV foo=bar
7133+
`, target))
7134+
7135+
checkLinterWarnings(t, sb, &lintTestParams{
7136+
Dockerfile: dockerfile,
7137+
Warnings: []expectedLintWarning{
7138+
{
7139+
RuleName: "InvalidBaseImagePlatform",
7140+
Description: "Base image platform does not match expected target platform",
7141+
Detail: fmt.Sprintf("Base image %s was pulled with platform %q, expected %q for current build", target, targetPlatform, runtime.GOOS+"/"+runtime.GOARCH),
7142+
Level: 1,
7143+
Line: 2,
7144+
},
7145+
},
7146+
FrontendAttrs: map[string]string{},
7147+
})
7148+
}
7149+
70767150
func runShell(dir string, cmds ...string) error {
70777151
for _, args := range cmds {
70787152
var cmd *exec.Cmd

frontend/dockerfile/linter/ruleset.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,11 @@ var (
120120
return fmt.Sprintf("\"%s key=value\" should be used instead of legacy \"%s key value\" format", cmdName, cmdName)
121121
},
122122
}
123+
RuleInvalidBaseImagePlatform = LinterRule[func(string, string, string) string]{
124+
Name: "InvalidBaseImagePlatform",
125+
Description: "Base image platform does not match expected target platform",
126+
Format: func(image, expected, actual string) string {
127+
return fmt.Sprintf("Base image %s was pulled with platform %q, expected %q for current build", image, actual, expected)
128+
},
129+
}
123130
)

0 commit comments

Comments
 (0)