diff --git a/components/engine/builder/remotecontext/detect.go b/components/engine/builder/remotecontext/detect.go index 144eb570ab..1becd0fd59 100644 --- a/components/engine/builder/remotecontext/detect.go +++ b/components/engine/builder/remotecontext/detect.go @@ -12,6 +12,7 @@ import ( "github.com/docker/docker/api/types/backend" "github.com/docker/docker/builder" "github.com/docker/docker/builder/dockerignore" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/fileutils" "github.com/docker/docker/pkg/urlutil" "github.com/moby/buildkit/frontend/dockerfile/parser" @@ -34,8 +35,9 @@ func Detect(config backend.BuildConfig) (remote builder.Source, dockerfile *pars case remoteURL == ClientSessionRemote: res, err := parser.Parse(config.Source) if err != nil { - return nil, nil, err + return nil, nil, errdefs.InvalidParameter(err) } + return nil, res, nil case urlutil.IsGitURL(remoteURL): remote, dockerfile, err = newGitRemote(remoteURL, dockerfilePath) @@ -106,7 +108,7 @@ func newURLRemote(url string, dockerfilePath string, progressReader func(in io.R switch contentType { case mimeTypes.TextPlain: res, err := parser.Parse(progressReader(content)) - return nil, res, err + return nil, res, errdefs.InvalidParameter(err) default: source, err := FromArchive(progressReader(content)) if err != nil { @@ -146,11 +148,17 @@ func readAndParseDockerfile(name string, rc io.Reader) (*parser.Result, error) { br := bufio.NewReader(rc) if _, err := br.Peek(1); err != nil { if err == io.EOF { - return nil, errors.Errorf("the Dockerfile (%s) cannot be empty", name) + return nil, errdefs.InvalidParameter(errors.Errorf("the Dockerfile (%s) cannot be empty", name)) } return nil, errors.Wrap(err, "unexpected error reading Dockerfile") } - return parser.Parse(br) + + dockerfile, err := parser.Parse(br) + if err != nil { + return nil, errdefs.InvalidParameter(errors.Wrapf(err, "failed to parse %s", name)) + } + + return dockerfile, nil } func openAt(remote builder.Source, path string) (driver.File, error) { diff --git a/components/engine/integration/build/build_test.go b/components/engine/integration/build/build_test.go index 6a2b1fda9f..6fe18fc5b1 100644 --- a/components/engine/integration/build/build_test.go +++ b/components/engine/integration/build/build_test.go @@ -474,6 +474,61 @@ RUN for g in $(seq 0 8); do dd if=/dev/urandom of=rnd bs=1K count=1 seek=$((1024 assert.Check(t, is.Contains(out.String(), "Successfully built")) } +func TestBuildWithEmptyDockerfile(t *testing.T) { + ctx := context.TODO() + defer setupTest(t)() + + tests := []struct { + name string + dockerfile string + expectedErr string + }{ + { + name: "empty-dockerfile", + dockerfile: "", + expectedErr: "cannot be empty", + }, + { + name: "empty-lines-dockerfile", + dockerfile: ` + + + + `, + expectedErr: "file with no instructions", + }, + { + name: "comment-only-dockerfile", + dockerfile: `# this is a comment`, + expectedErr: "file with no instructions", + }, + } + + apiclient := testEnv.APIClient() + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + buf := bytes.NewBuffer(nil) + w := tar.NewWriter(buf) + writeTarRecord(t, w, "Dockerfile", tc.dockerfile) + err := w.Close() + assert.NilError(t, err) + + _, err = apiclient.ImageBuild(ctx, + buf, + types.ImageBuildOptions{ + Remove: true, + ForceRemove: true, + }) + + assert.Check(t, is.Contains(err.Error(), tc.expectedErr)) + }) + } +} + func writeTarRecord(t *testing.T, w *tar.Writer, fn, contents string) { err := w.WriteHeader(&tar.Header{ Name: fn, diff --git a/components/engine/vendor.conf b/components/engine/vendor.conf index fac0ede8fb..95def4ba94 100644 --- a/components/engine/vendor.conf +++ b/components/engine/vendor.conf @@ -26,7 +26,7 @@ github.com/imdario/mergo v0.3.6 golang.org/x/sync 1d60e4601c6fd243af51cc01ddf169918a5407ca # buildkit -github.com/moby/buildkit ed4da8b4a9661f278ae8433056ca37d0727c408b # docker-18.09 branch +github.com/moby/buildkit 05766c5c21a1e528eeb1c3522b2f05493fe9ac47 # docker-18.09 branch github.com/tonistiigi/fsutil 2862f6bc5ac9b97124e552a5c108230b38a1b0ca github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746 github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7 diff --git a/components/engine/vendor/github.com/moby/buildkit/frontend/dockerfile/parser/parser.go b/components/engine/vendor/github.com/moby/buildkit/frontend/dockerfile/parser/parser.go index 0453f3a9a2..262a768133 100644 --- a/components/engine/vendor/github.com/moby/buildkit/frontend/dockerfile/parser/parser.go +++ b/components/engine/vendor/github.com/moby/buildkit/frontend/dockerfile/parser/parser.go @@ -275,6 +275,11 @@ func Parse(rwc io.Reader) (*Result, error) { if len(warnings) > 0 { warnings = append(warnings, "[WARNING]: Empty continuation lines will become errors in a future release.") } + + if root.StartLine < 0 { + return nil, errors.New("file with no instructions.") + } + return &Result{ AST: root, Warnings: warnings,