Browse code

Merge pull request #38487 from LinuxMercedes/error-on-empty-dockerfile

Error on empty dockerfile

Sebastiaan van Stijn authored on 2019/01/16 05:41:12
Showing 11 changed files
... ...
@@ -12,6 +12,7 @@ import (
12 12
 	"github.com/docker/docker/api/types/backend"
13 13
 	"github.com/docker/docker/builder"
14 14
 	"github.com/docker/docker/builder/dockerignore"
15
+	"github.com/docker/docker/errdefs"
15 16
 	"github.com/docker/docker/pkg/fileutils"
16 17
 	"github.com/docker/docker/pkg/urlutil"
17 18
 	"github.com/moby/buildkit/frontend/dockerfile/parser"
... ...
@@ -34,8 +35,9 @@ func Detect(config backend.BuildConfig) (remote builder.Source, dockerfile *pars
34 34
 	case remoteURL == ClientSessionRemote:
35 35
 		res, err := parser.Parse(config.Source)
36 36
 		if err != nil {
37
-			return nil, nil, err
37
+			return nil, nil, errdefs.InvalidParameter(err)
38 38
 		}
39
+
39 40
 		return nil, res, nil
40 41
 	case urlutil.IsGitURL(remoteURL):
41 42
 		remote, dockerfile, err = newGitRemote(remoteURL, dockerfilePath)
... ...
@@ -106,7 +108,7 @@ func newURLRemote(url string, dockerfilePath string, progressReader func(in io.R
106 106
 	switch contentType {
107 107
 	case mimeTypes.TextPlain:
108 108
 		res, err := parser.Parse(progressReader(content))
109
-		return nil, res, err
109
+		return nil, res, errdefs.InvalidParameter(err)
110 110
 	default:
111 111
 		source, err := FromArchive(progressReader(content))
112 112
 		if err != nil {
... ...
@@ -146,11 +148,17 @@ func readAndParseDockerfile(name string, rc io.Reader) (*parser.Result, error) {
146 146
 	br := bufio.NewReader(rc)
147 147
 	if _, err := br.Peek(1); err != nil {
148 148
 		if err == io.EOF {
149
-			return nil, errors.Errorf("the Dockerfile (%s) cannot be empty", name)
149
+			return nil, errdefs.InvalidParameter(errors.Errorf("the Dockerfile (%s) cannot be empty", name))
150 150
 		}
151 151
 		return nil, errors.Wrap(err, "unexpected error reading Dockerfile")
152 152
 	}
153
-	return parser.Parse(br)
153
+
154
+	dockerfile, err := parser.Parse(br)
155
+	if err != nil {
156
+		return nil, errdefs.InvalidParameter(errors.Wrapf(err, "failed to parse %s", name))
157
+	}
158
+
159
+	return dockerfile, nil
154 160
 }
155 161
 
156 162
 func openAt(remote builder.Source, path string) (driver.File, error) {
... ...
@@ -467,6 +467,61 @@ RUN for g in $(seq 0 8); do dd if=/dev/urandom of=rnd bs=1K count=1 seek=$((1024
467 467
 	assert.Check(t, is.Contains(out.String(), "Successfully built"))
468 468
 }
469 469
 
470
+func TestBuildWithEmptyDockerfile(t *testing.T) {
471
+	ctx := context.TODO()
472
+	defer setupTest(t)()
473
+
474
+	tests := []struct {
475
+		name        string
476
+		dockerfile  string
477
+		expectedErr string
478
+	}{
479
+		{
480
+			name:        "empty-dockerfile",
481
+			dockerfile:  "",
482
+			expectedErr: "cannot be empty",
483
+		},
484
+		{
485
+			name: "empty-lines-dockerfile",
486
+			dockerfile: `
487
+			
488
+			
489
+			
490
+			`,
491
+			expectedErr: "file with no instructions",
492
+		},
493
+		{
494
+			name:        "comment-only-dockerfile",
495
+			dockerfile:  `# this is a comment`,
496
+			expectedErr: "file with no instructions",
497
+		},
498
+	}
499
+
500
+	apiclient := testEnv.APIClient()
501
+
502
+	for _, tc := range tests {
503
+		tc := tc
504
+		t.Run(tc.name, func(t *testing.T) {
505
+			t.Parallel()
506
+
507
+			buf := bytes.NewBuffer(nil)
508
+			w := tar.NewWriter(buf)
509
+			writeTarRecord(t, w, "Dockerfile", tc.dockerfile)
510
+			err := w.Close()
511
+			assert.NilError(t, err)
512
+
513
+			_, err = apiclient.ImageBuild(ctx,
514
+				buf,
515
+				types.ImageBuildOptions{
516
+					Remove:      true,
517
+					ForceRemove: true,
518
+				})
519
+
520
+			assert.Check(t, is.Contains(err.Error(), tc.expectedErr))
521
+		})
522
+	}
523
+}
524
+
470 525
 func writeTarRecord(t *testing.T, w *tar.Writer, fn, contents string) {
471 526
 	err := w.WriteHeader(&tar.Header{
472 527
 		Name:     fn,
... ...
@@ -26,7 +26,7 @@ github.com/imdario/mergo v0.3.6
26 26
 golang.org/x/sync 1d60e4601c6fd243af51cc01ddf169918a5407ca
27 27
 
28 28
 # buildkit
29
-github.com/moby/buildkit d9f75920678e35090025bb89344c5370e2efc8e7
29
+github.com/moby/buildkit 34ff9c2366a878ada7938d2f9ede71741b0a220c
30 30
 github.com/tonistiigi/fsutil 2862f6bc5ac9b97124e552a5c108230b38a1b0ca
31 31
 github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746
32 32
 github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
... ...
@@ -31,19 +31,15 @@ Introductory blog post https://blog.mobyproject.org/introducing-buildkit-17e056c
31 31
 
32 32
 ### Used by
33 33
 
34
-[Moby & Docker](https://github.com/moby/moby/pull/37151)
34
+BuildKit is used by the following projects:
35 35
 
36
-[img](https://github.com/genuinetools/img)
37
-
38
-[OpenFaaS Cloud](https://github.com/openfaas/openfaas-cloud)
39
-
40
-[container build interface](https://github.com/containerbuilding/cbi)
41
-
42
-[Knative Build Templates](https://github.com/knative/build-templates)
43
-
44
-[boss](https://github.com/crosbymichael/boss)
45
-
46
-[Rio](https://github.com/rancher/rio) (on roadmap)
36
+- [Moby & Docker](https://github.com/moby/moby/pull/37151)
37
+- [img](https://github.com/genuinetools/img)
38
+- [OpenFaaS Cloud](https://github.com/openfaas/openfaas-cloud)
39
+- [container build interface](https://github.com/containerbuilding/cbi)
40
+- [Knative Build Templates](https://github.com/knative/build-templates)
41
+- [boss](https://github.com/crosbymichael/boss)
42
+- [Rio](https://github.com/rancher/rio) (on roadmap)
47 43
 
48 44
 ### Quick start
49 45
 
... ...
@@ -252,7 +248,7 @@ export JAEGER_TRACE=0.0.0.0:6831
252 252
 
253 253
 ### Supported runc version
254 254
 
255
-During development, BuildKit is tested with the version of runc that is being used by the containerd repository. Please refer to [runc.md](https://github.com/containerd/containerd/blob/v1.2.0-rc.1/RUNC.md) for more information.
255
+During development, BuildKit is tested with the version of runc that is being used by the containerd repository. Please refer to [runc.md](https://github.com/containerd/containerd/blob/v1.2.1/RUNC.md) for more information.
256 256
 
257 257
 ### Running BuildKit without root privileges
258 258
 
... ...
@@ -260,35 +256,5 @@ Please refer to [`docs/rootless.md`](docs/rootless.md).
260 260
 
261 261
 ### Contributing
262 262
 
263
-Running tests:
264
-
265
-```bash
266
-make test
267
-```
268
-
269
-This runs all unit and integration tests in a containerized environment. Locally, every package can be tested separately with standard Go tools, but integration tests are skipped if local user doesn't have enough permissions or worker binaries are not installed.
270
-
271
-```
272
-# test a specific package only
273
-make test TESTPKGS=./client
274
-
275
-# run a specific test with all worker combinations
276
-make test TESTPKGS=./client TESTFLAGS="--run /TestCallDiskUsage -v" 
277
-
278
-# run all integration tests with a specific worker
279
-# supported workers: oci, oci-rootless, containerd, containerd-1.0
280
-make test TESTPKGS=./client TESTFLAGS="--run //worker=containerd -v" 
281
-```
282
-
283
-Updating vendored dependencies:
284
-
285
-```bash
286
-# update vendor.conf
287
-make vendor
288
-```
289
-
290
-Validating your updates before submission:
291
-
292
-```bash
293
-make validate-all
294
-```
263
+Want to contribute to BuildKit? Awesome! You can find information about
264
+contributing to this project in the [CONTRIBUTING.md](/.github/CONTRIBUTING.md)
... ...
@@ -34,5 +34,21 @@ func dispatchSecret(m *instructions.Mount) (llb.RunOption, error) {
34 34
 		opts = append(opts, llb.SecretOptional)
35 35
 	}
36 36
 
37
+	if m.UID != nil || m.GID != nil || m.Mode != nil {
38
+		var uid, gid, mode int
39
+		if m.UID != nil {
40
+			uid = int(*m.UID)
41
+		}
42
+		if m.GID != nil {
43
+			gid = int(*m.GID)
44
+		}
45
+		if m.Mode != nil {
46
+			mode = int(*m.Mode)
47
+		} else {
48
+			mode = 0400
49
+		}
50
+		opts = append(opts, llb.SecretFileOpt(uid, gid, mode))
51
+	}
52
+
37 53
 	return llb.AddSecret(target, opts...), nil
38 54
 }
... ...
@@ -15,7 +15,6 @@ func dispatchSSH(m *instructions.Mount) (llb.RunOption, error) {
15 15
 	opts := []llb.SSHOption{llb.SSHID(m.CacheID)}
16 16
 
17 17
 	if m.Target != "" {
18
-		// TODO(AkihiroSuda): support specifying permission bits
19 18
 		opts = append(opts, llb.SSHSocketTarget(m.Target))
20 19
 	}
21 20
 
... ...
@@ -23,5 +22,21 @@ func dispatchSSH(m *instructions.Mount) (llb.RunOption, error) {
23 23
 		opts = append(opts, llb.SSHOptional)
24 24
 	}
25 25
 
26
+	if m.UID != nil || m.GID != nil || m.Mode != nil {
27
+		var uid, gid, mode int
28
+		if m.UID != nil {
29
+			uid = int(*m.UID)
30
+		}
31
+		if m.GID != nil {
32
+			gid = int(*m.GID)
33
+		}
34
+		if m.Mode != nil {
35
+			mode = int(*m.Mode)
36
+		} else {
37
+			mode = 0600
38
+		}
39
+		opts = append(opts, llb.SSHSocketOpt(m.Target, uid, gid, mode))
40
+	}
41
+
26 42
 	return llb.AddSSHSocket(opts...), nil
27 43
 }
... ...
@@ -108,6 +108,9 @@ type Mount struct {
108 108
 	CacheID      string
109 109
 	CacheSharing string
110 110
 	Required     bool
111
+	Mode         *uint64
112
+	UID          *uint64
113
+	GID          *uint64
111 114
 }
112 115
 
113 116
 func parseMount(value string) (*Mount, error) {
... ...
@@ -180,11 +183,43 @@ func parseMount(value string) (*Mount, error) {
180 180
 				return nil, errors.Errorf("unsupported sharing value %q", value)
181 181
 			}
182 182
 			m.CacheSharing = strings.ToLower(value)
183
+		case "mode":
184
+			mode, err := strconv.ParseUint(value, 8, 32)
185
+			if err != nil {
186
+				return nil, errors.Errorf("invalid value %s for mode", value)
187
+			}
188
+			m.Mode = &mode
189
+		case "uid":
190
+			uid, err := strconv.ParseUint(value, 10, 32)
191
+			if err != nil {
192
+				return nil, errors.Errorf("invalid value %s for uid", value)
193
+			}
194
+			m.UID = &uid
195
+		case "gid":
196
+			gid, err := strconv.ParseUint(value, 10, 32)
197
+			if err != nil {
198
+				return nil, errors.Errorf("invalid value %s for gid", value)
199
+			}
200
+			m.GID = &gid
183 201
 		default:
184 202
 			return nil, errors.Errorf("unexpected key '%s' in '%s'", key, field)
185 203
 		}
186 204
 	}
187 205
 
206
+	fileInfoAllowed := m.Type == MountTypeSecret || m.Type == MountTypeSSH
207
+
208
+	if m.Mode != nil && !fileInfoAllowed {
209
+		return nil, errors.Errorf("mode not allowed for %q type mounts")
210
+	}
211
+
212
+	if m.UID != nil && !fileInfoAllowed {
213
+		return nil, errors.Errorf("uid not allowed for %q type mounts")
214
+	}
215
+
216
+	if m.GID != nil && !fileInfoAllowed {
217
+		return nil, errors.Errorf("gid not allowed for %q type mounts")
218
+	}
219
+
188 220
 	if roAuto {
189 221
 		if m.Type == MountTypeCache {
190 222
 			m.ReadOnly = false
... ...
@@ -275,6 +275,11 @@ func Parse(rwc io.Reader) (*Result, error) {
275 275
 	if len(warnings) > 0 {
276 276
 		warnings = append(warnings, "[WARNING]: Empty continuation lines will become errors in a future release.")
277 277
 	}
278
+
279
+	if root.StartLine < 0 {
280
+		return nil, errors.New("file with no instructions.")
281
+	}
282
+
278 283
 	return &Result{
279 284
 		AST:         root,
280 285
 		Warnings:    warnings,
... ...
@@ -96,7 +96,7 @@ func (cs *containerdSnapshotter) release() error {
96 96
 	defer cs.mu.Unlock()
97 97
 	var err error
98 98
 	for _, f := range cs.releasers {
99
-		if err1 := f(); err != nil && err == nil {
99
+		if err1 := f(); err1 != nil && err == nil {
100 100
 			err = err1
101 101
 		}
102 102
 	}
... ...
@@ -331,7 +331,7 @@ func (sm *sshMountInstance) Mount() ([]mount.Mount, error) {
331 331
 		ID:   sm.sm.mount.SSHOpt.ID,
332 332
 		UID:  int(sm.sm.mount.SSHOpt.Uid),
333 333
 		GID:  int(sm.sm.mount.SSHOpt.Gid),
334
-		Mode: int(sm.sm.mount.SSHOpt.Mode),
334
+		Mode: int(sm.sm.mount.SSHOpt.Mode & 0777),
335 335
 	})
336 336
 	if err != nil {
337 337
 		cancel()
... ...
@@ -447,7 +447,7 @@ func (sm *secretMountInstance) Mount() ([]mount.Mount, error) {
447 447
 		return nil, err
448 448
 	}
449 449
 
450
-	if err := os.Chmod(fp, os.FileMode(sm.sm.mount.SecretOpt.Mode)); err != nil {
450
+	if err := os.Chmod(fp, os.FileMode(sm.sm.mount.SecretOpt.Mode&0777)); err != nil {
451 451
 		return nil, err
452 452
 	}
453 453
 
... ...
@@ -6,10 +6,10 @@ github.com/davecgh/go-spew v1.1.0
6 6
 github.com/pmezard/go-difflib v1.0.0
7 7
 golang.org/x/sys 1b2967e3c290b7c545b3db0deeda16e9be4f98a2
8 8
 
9
-github.com/containerd/containerd 1a5f9a3434ac53c0e9d27093ecc588e0c281c333
9
+github.com/containerd/containerd 47b328aab79146a9e81e37704db60e7e04a09256
10 10
 github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
11 11
 golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
12
-github.com/sirupsen/logrus v1.0.0
12
+github.com/sirupsen/logrus v1.0.3
13 13
 google.golang.org/grpc v1.12.0
14 14
 github.com/opencontainers/go-digest c9281466c8b2f606084ac71339773efd177436e7
15 15
 golang.org/x/net 0ed95abb35c445290478a5348a7b38bb154135fd
... ...
@@ -18,7 +18,7 @@ github.com/gogo/googleapis b23578765ee54ff6bceff57f397d833bf4ca6869
18 18
 github.com/golang/protobuf v1.1.0
19 19
 github.com/containerd/continuity bd77b46c8352f74eb12c85bdc01f4b90f69d66b4
20 20
 github.com/opencontainers/image-spec v1.0.1
21
-github.com/opencontainers/runc a00bf0190895aa465a5fbed0268888e2c8ddfe85
21
+github.com/opencontainers/runc 96ec2177ae841256168fcf76954f7177af9446eb
22 22
 github.com/Microsoft/go-winio v0.4.11
23 23
 github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
24 24
 github.com/opencontainers/runtime-spec eba862dc2470385a233c7507392675cbeadf7353 # v1.0.1-45-geba862d
... ...
@@ -30,7 +30,7 @@ github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
30 30
 github.com/syndtr/gocapability db04d3cc01c8b54962a58ec7e491717d06cfcc16
31 31
 github.com/Microsoft/hcsshim v0.7.9
32 32
 golang.org/x/crypto 0709b304e793a5edb4a2c0145f281ecdc20838a4
33
-github.com/containerd/cri 8506fe836677cc3bb23a16b68145128243d843b5 # release/1.2 branch
33
+github.com/containerd/cri f913714917d2456d7e65a0be84962b1ce8acb487 # release/1.2 branch
34 34
 
35 35
 github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c
36 36
 github.com/morikuni/aec 39771216ff4c63d11f5e604076f9c45e8be1067b