diff --git a/api/client/build.go b/api/client/build.go index f424e9b3f6..54e76521b7 100644 --- a/api/client/build.go +++ b/api/client/build.go @@ -302,6 +302,22 @@ func getDockerfileRelPath(givenContextDir, givenDockerfile string) (absContextDi return "", "", fmt.Errorf("unable to get absolute context directory: %v", err) } + // The context dir might be a symbolic link, so follow it to the actual + // target directory. + absContextDir, err = filepath.EvalSymlinks(absContextDir) + if err != nil { + return "", "", fmt.Errorf("unable to evaluate symlinks in context path: %v", err) + } + + stat, err := os.Lstat(absContextDir) + if err != nil { + return "", "", fmt.Errorf("unable to stat context directory %q: %v", absContextDir, err) + } + + if !stat.IsDir() { + return "", "", fmt.Errorf("context must be a directory: %s", absContextDir) + } + absDockerfile := givenDockerfile if absDockerfile == "" { // No -f/--file was specified so use the default relative to the diff --git a/integration-cli/docker_cli_build_test.go b/integration-cli/docker_cli_build_test.go index c5d86d6f3d..9bba032542 100644 --- a/integration-cli/docker_cli_build_test.go +++ b/integration-cli/docker_cli_build_test.go @@ -5394,3 +5394,41 @@ func (s *DockerTrustSuite) TestTrustedBuildUntrustedTag(c *check.C) { c.Fatalf("Unexpected output on trusted build with untrusted tag:\n%s", out) } } + +func (s *DockerTrustSuite) TestBuildContextDirIsSymlink(c *check.C) { + tempDir, err := ioutil.TempDir("", "test-build-dir-is-symlink-") + if err != nil { + c.Fatal(err) + } + defer os.RemoveAll(tempDir) + + // Make a real context directory in this temp directory with a simple + // Dockerfile. + realContextDirname := filepath.Join(tempDir, "context") + if err := os.Mkdir(realContextDirname, os.FileMode(0755)); err != nil { + c.Fatal(err) + } + + if err = ioutil.WriteFile( + filepath.Join(realContextDirname, "Dockerfile"), + []byte(` + FROM busybox + RUN echo hello world + `), + os.FileMode(0644), + ); err != nil { + c.Fatal(err) + } + + // Make a symlink to the real context directory. + contextSymlinkName := filepath.Join(tempDir, "context_link") + if err := os.Symlink(realContextDirname, contextSymlinkName); err != nil { + c.Fatal(err) + } + + // Executing the build with the symlink as the specified context should + // *not* fail. + if out, exitStatus := dockerCmd(c, "build", contextSymlinkName); exitStatus != 0 { + c.Fatalf("build failed with exit status %d: %s", exitStatus, out) + } +}