diff --git a/cli/command/image/build.go b/cli/command/image/build.go index 5661e15d03..19865717a6 100644 --- a/cli/command/image/build.go +++ b/cli/command/image/build.go @@ -21,6 +21,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/docker/pkg/archive" + "github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/progress" "github.com/docker/docker/pkg/streamformatter" @@ -243,6 +244,7 @@ func runBuild(dockerCli command.Cli, options buildOptions) error { excludes = build.TrimBuildFilesFromExcludes(excludes, relDockerfile, options.dockerfileFromStdin()) buildCtx, err = archive.TarWithOptions(contextDir, &archive.TarOptions{ ExcludePatterns: excludes, + ChownOpts: &idtools.IDPair{UID: 0, GID: 0}, }) if err != nil { return err diff --git a/cli/command/image/build_test.go b/cli/command/image/build_test.go index 325c82343e..1ccd70e45d 100644 --- a/cli/command/image/build_test.go +++ b/cli/command/image/build_test.go @@ -6,18 +6,57 @@ import ( "io/ioutil" "os" "path/filepath" + "runtime" "sort" + "syscall" "testing" "github.com/docker/cli/cli/command" "github.com/docker/cli/internal/test" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/archive" + "github.com/gotestyourself/gotestyourself/fs" + "github.com/gotestyourself/gotestyourself/skip" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/net/context" ) +func TestRunBuildResetsUidAndGidInContext(t *testing.T) { + skip.IfCondition(t, runtime.GOOS == "windows", "uid and gid not relevant on windows") + dest := fs.NewDir(t, "test-build-context-dest") + defer dest.Remove() + + fakeImageBuild := func(_ context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) { + assert.NoError(t, archive.Untar(context, dest.Path(), nil)) + + body := new(bytes.Buffer) + return types.ImageBuildResponse{Body: ioutil.NopCloser(body)}, nil + } + cli := test.NewFakeCli(&fakeClient{imageBuildFunc: fakeImageBuild}) + + dir := fs.NewDir(t, "test-build-context", + fs.WithFile("foo", "some content", fs.AsUser(65534, 65534)), + fs.WithFile("Dockerfile", ` + FROM alpine:3.6 + COPY foo bar / + `), + ) + defer dir.Remove() + + options := newBuildOptions() + options.context = dir.Path() + + err := runBuild(cli, options) + require.NoError(t, err) + + files, err := ioutil.ReadDir(dest.Path()) + require.NoError(t, err) + for _, fileInfo := range files { + assert.Equal(t, uint32(0), fileInfo.Sys().(*syscall.Stat_t).Uid) + assert.Equal(t, uint32(0), fileInfo.Sys().(*syscall.Stat_t).Gid) + } +} func TestRunBuildDockerfileFromStdinWithCompress(t *testing.T) { dest, err := ioutil.TempDir("", "test-build-compress-dest") require.NoError(t, err) diff --git a/vendor.conf b/vendor.conf index 685d48d3d0..be845f4268 100755 --- a/vendor.conf +++ b/vendor.conf @@ -20,7 +20,7 @@ github.com/gogo/protobuf v0.4 github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4 github.com/gorilla/context v1.1 github.com/gorilla/mux v1.1 -github.com/gotestyourself/gotestyourself v1.1.0 +github.com/gotestyourself/gotestyourself v1.2.0 github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 github.com/mattn/go-shellwords v1.0.3 github.com/Microsoft/go-winio v0.4.4 @@ -28,7 +28,7 @@ github.com/miekg/pkcs11 df8ae6ca730422dba20c768ff38ef7d79077a59f github.com/mitchellh/mapstructure f3009df150dadf309fdee4a54ed65c124afad715 github.com/moby/buildkit da2b9dc7dab99e824b2b1067ad7d0523e32dd2d9 https://github.com/dmcgowan/buildkit.git github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty -github.com/opencontainers/go-digest 21dfd564fd89c944783d00d069f33e3e7123c448 +github.com/opencontainers/go-digest 21dfd564fd89c944783d00d069f33e3e7123c448 github.com/opencontainers/image-spec v1.0.0 github.com/opencontainers/runc d40db12e72a40109dfcf28539f5ee0930d2f0277 github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9 diff --git a/vendor/github.com/gotestyourself/gotestyourself/fs/ops.go b/vendor/github.com/gotestyourself/gotestyourself/fs/ops.go index 4fbc40f422..7cc63994c8 100644 --- a/vendor/github.com/gotestyourself/gotestyourself/fs/ops.go +++ b/vendor/github.com/gotestyourself/gotestyourself/fs/ops.go @@ -31,14 +31,17 @@ func AsUser(uid, gid int) PathOp { } // WithFile creates a file in the directory at path with content -func WithFile(filename, content string) PathOp { +func WithFile(filename, content string, ops ...PathOp) PathOp { return func(path Path) error { - return createFile(path.Path(), filename, content) + fullpath := filepath.Join(path.Path(), filepath.FromSlash(filename)) + if err := createFile(fullpath, content); err != nil { + return err + } + return applyPathOps(&File{path: fullpath}, ops) } } -func createFile(dir, filename, content string) error { - fullpath := filepath.Join(dir, filepath.FromSlash(filename)) +func createFile(fullpath string, content string) error { return ioutil.WriteFile(fullpath, []byte(content), 0644) } @@ -46,7 +49,8 @@ func createFile(dir, filename, content string) error { func WithFiles(files map[string]string) PathOp { return func(path Path) error { for filename, content := range files { - if err := createFile(path.Path(), filename, content); err != nil { + fullpath := filepath.Join(path.Path(), filepath.FromSlash(filename)) + if err := createFile(fullpath, content); err != nil { return err } } @@ -61,6 +65,35 @@ func FromDir(source string) PathOp { } } +// WithDir creates a subdirectory in the directory at path. Additional PathOp +// can be used to modify the subdirectory +func WithDir(name string, ops ...PathOp) PathOp { + return func(path Path) error { + fullpath := filepath.Join(path.Path(), filepath.FromSlash(name)) + err := os.MkdirAll(fullpath, 0755) + if err != nil { + return err + } + return applyPathOps(&Dir{path: fullpath}, ops) + } +} + +func applyPathOps(path Path, ops []PathOp) error { + for _, op := range ops { + if err := op(path); err != nil { + return err + } + } + return nil +} + +// WithMode sets the file mode on the directory or file at path +func WithMode(mode os.FileMode) PathOp { + return func(path Path) error { + return os.Chmod(path.Path(), mode) + } +} + func copyDirectory(source, dest string) error { entries, err := ioutil.ReadDir(source) if err != nil { diff --git a/vendor/github.com/gotestyourself/gotestyourself/skip/skip.go b/vendor/github.com/gotestyourself/gotestyourself/skip/skip.go index d92110b0ef..1a6446593f 100644 --- a/vendor/github.com/gotestyourself/gotestyourself/skip/skip.go +++ b/vendor/github.com/gotestyourself/gotestyourself/skip/skip.go @@ -54,16 +54,17 @@ func IfCondition(t skipT, condition bool, msgAndArgs ...interface{}) { t.Skip(formatWithCustomMessage(source, formatMessage(msgAndArgs...))) } +// getConditionSource returns the condition string by reading it from the file +// identified in the callstack. In golang 1.9 the line number changed from +// being the line where the statement ended to the line where the statement began. func getConditionSource() (string, error) { - const callstackIndex = 3 - lines, err := getSourceLine(callstackIndex) + lines, err := getSourceLine() if err != nil { return "", err } for i := range lines { - source := strings.Join(lines[len(lines)-i-1:], "\n") - node, err := parser.ParseExpr(source) + node, err := parser.ParseExpr(getSource(lines, i)) if err == nil { return getConditionArgFromAST(node) } @@ -79,7 +80,8 @@ const maxContextLines = 10 // few preceding lines. To properly parse the AST a complete statement is // required, and that statement may be split across multiple lines, so include // up to maxContextLines. -func getSourceLine(stackIndex int) ([]string, error) { +func getSourceLine() ([]string, error) { + const stackIndex = 3 _, filename, line, ok := runtime.Caller(stackIndex) if !ok { return nil, errors.New("failed to get caller info") @@ -94,11 +96,8 @@ func getSourceLine(stackIndex int) ([]string, error) { if len(lines) < line { return nil, errors.Errorf("file %s does not have line %d", filename, line) } - firstLine := line - maxContextLines - if firstLine < 0 { - firstLine = 0 - } - return lines[firstLine:line], nil + firstLine, lastLine := getSourceLinesRange(line, len(lines)) + return lines[firstLine:lastLine], nil } func getConditionArgFromAST(node ast.Expr) (string, error) { diff --git a/vendor/github.com/gotestyourself/gotestyourself/skip/skip_go18.go b/vendor/github.com/gotestyourself/gotestyourself/skip/skip_go18.go new file mode 100644 index 0000000000..586e58a735 --- /dev/null +++ b/vendor/github.com/gotestyourself/gotestyourself/skip/skip_go18.go @@ -0,0 +1,17 @@ +// +build !go1.9,!go.10,!go.11,!go1.12 + +package skip + +import "strings" + +func getSourceLinesRange(line int, _ int) (int, int) { + firstLine := line - maxContextLines + if firstLine < 0 { + firstLine = 0 + } + return firstLine, line +} + +func getSource(lines []string, i int) string { + return strings.Join(lines[len(lines)-i-1:], "\n") +} diff --git a/vendor/github.com/gotestyourself/gotestyourself/skip/skip_go19.go b/vendor/github.com/gotestyourself/gotestyourself/skip/skip_go19.go new file mode 100644 index 0000000000..8aedc4b2c1 --- /dev/null +++ b/vendor/github.com/gotestyourself/gotestyourself/skip/skip_go19.go @@ -0,0 +1,17 @@ +// +build go1.9 + +package skip + +import "strings" + +func getSourceLinesRange(line int, lines int) (int, int) { + lastLine := line + maxContextLines + if lastLine > lines { + lastLine = lines + } + return line - 1, lastLine +} + +func getSource(lines []string, i int) string { + return strings.Join(lines[:i], "\n") +}