github.com/damirazo/docker@v1.9.0/integration-cli/docker_api_build_test.go (about)

     1  package main
     2  
     3  import (
     4  	"archive/tar"
     5  	"bytes"
     6  	"net/http"
     7  	"strings"
     8  
     9  	"github.com/go-check/check"
    10  )
    11  
    12  func (s *DockerSuite) TestBuildApiDockerfilePath(c *check.C) {
    13  	// Test to make sure we stop people from trying to leave the
    14  	// build context when specifying the path to the dockerfile
    15  	buffer := new(bytes.Buffer)
    16  	tw := tar.NewWriter(buffer)
    17  	defer tw.Close()
    18  
    19  	dockerfile := []byte("FROM busybox")
    20  	if err := tw.WriteHeader(&tar.Header{
    21  		Name: "Dockerfile",
    22  		Size: int64(len(dockerfile)),
    23  	}); err != nil {
    24  		c.Fatalf("failed to write tar file header: %v", err)
    25  	}
    26  	if _, err := tw.Write(dockerfile); err != nil {
    27  		c.Fatalf("failed to write tar file content: %v", err)
    28  	}
    29  	if err := tw.Close(); err != nil {
    30  		c.Fatalf("failed to close tar archive: %v", err)
    31  	}
    32  
    33  	res, body, err := sockRequestRaw("POST", "/build?dockerfile=../Dockerfile", buffer, "application/x-tar")
    34  	c.Assert(err, check.IsNil)
    35  	c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
    36  
    37  	out, err := readBody(body)
    38  	if err != nil {
    39  		c.Fatal(err)
    40  	}
    41  
    42  	if !strings.Contains(string(out), "Forbidden path outside the build context") {
    43  		c.Fatalf("Didn't complain about leaving build context: %s", out)
    44  	}
    45  }
    46  
    47  func (s *DockerSuite) TestBuildApiDockerFileRemote(c *check.C) {
    48  	testRequires(c, NotUserNamespace)
    49  	testRequires(c, DaemonIsLinux)
    50  	server, err := fakeStorage(map[string]string{
    51  		"testD": `FROM busybox
    52  COPY * /tmp/
    53  RUN find / -name ba*
    54  RUN find /tmp/`,
    55  	})
    56  	if err != nil {
    57  		c.Fatal(err)
    58  	}
    59  	defer server.Close()
    60  
    61  	res, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+server.URL()+"/testD", nil, "application/json")
    62  	c.Assert(err, check.IsNil)
    63  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
    64  
    65  	buf, err := readBody(body)
    66  	if err != nil {
    67  		c.Fatal(err)
    68  	}
    69  
    70  	// Make sure Dockerfile exists.
    71  	// Make sure 'baz' doesn't exist ANYWHERE despite being mentioned in the URL
    72  	out := string(buf)
    73  	if !strings.Contains(out, "/tmp/Dockerfile") ||
    74  		strings.Contains(out, "baz") {
    75  		c.Fatalf("Incorrect output: %s", out)
    76  	}
    77  }
    78  
    79  func (s *DockerSuite) TestBuildApiRemoteTarballContext(c *check.C) {
    80  	testRequires(c, DaemonIsLinux)
    81  	buffer := new(bytes.Buffer)
    82  	tw := tar.NewWriter(buffer)
    83  	defer tw.Close()
    84  
    85  	dockerfile := []byte("FROM busybox")
    86  	if err := tw.WriteHeader(&tar.Header{
    87  		Name: "Dockerfile",
    88  		Size: int64(len(dockerfile)),
    89  	}); err != nil {
    90  		c.Fatalf("failed to write tar file header: %v", err)
    91  	}
    92  	if _, err := tw.Write(dockerfile); err != nil {
    93  		c.Fatalf("failed to write tar file content: %v", err)
    94  	}
    95  	if err := tw.Close(); err != nil {
    96  		c.Fatalf("failed to close tar archive: %v", err)
    97  	}
    98  
    99  	server, err := fakeBinaryStorage(map[string]*bytes.Buffer{
   100  		"testT.tar": buffer,
   101  	})
   102  	c.Assert(err, check.IsNil)
   103  
   104  	defer server.Close()
   105  
   106  	res, b, err := sockRequestRaw("POST", "/build?remote="+server.URL()+"/testT.tar", nil, "application/tar")
   107  	c.Assert(err, check.IsNil)
   108  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   109  	b.Close()
   110  }
   111  
   112  func (s *DockerSuite) TestBuildApiRemoteTarballContextWithCustomDockerfile(c *check.C) {
   113  	testRequires(c, DaemonIsLinux)
   114  	buffer := new(bytes.Buffer)
   115  	tw := tar.NewWriter(buffer)
   116  	defer tw.Close()
   117  
   118  	dockerfile := []byte(`FROM busybox
   119  RUN echo 'wrong'`)
   120  	if err := tw.WriteHeader(&tar.Header{
   121  		Name: "Dockerfile",
   122  		Size: int64(len(dockerfile)),
   123  	}); err != nil {
   124  		c.Fatalf("failed to write tar file header: %v", err)
   125  	}
   126  	if _, err := tw.Write(dockerfile); err != nil {
   127  		c.Fatalf("failed to write tar file content: %v", err)
   128  	}
   129  
   130  	custom := []byte(`FROM busybox
   131  RUN echo 'right'
   132  `)
   133  	if err := tw.WriteHeader(&tar.Header{
   134  		Name: "custom",
   135  		Size: int64(len(custom)),
   136  	}); err != nil {
   137  		c.Fatalf("failed to write tar file header: %v", err)
   138  	}
   139  	if _, err := tw.Write(custom); err != nil {
   140  		c.Fatalf("failed to write tar file content: %v", err)
   141  	}
   142  
   143  	if err := tw.Close(); err != nil {
   144  		c.Fatalf("failed to close tar archive: %v", err)
   145  	}
   146  
   147  	server, err := fakeBinaryStorage(map[string]*bytes.Buffer{
   148  		"testT.tar": buffer,
   149  	})
   150  	c.Assert(err, check.IsNil)
   151  
   152  	defer server.Close()
   153  	url := "/build?dockerfile=custom&remote=" + server.URL() + "/testT.tar"
   154  	res, body, err := sockRequestRaw("POST", url, nil, "application/tar")
   155  	c.Assert(err, check.IsNil)
   156  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   157  
   158  	defer body.Close()
   159  	content, err := readBody(body)
   160  	c.Assert(err, check.IsNil)
   161  
   162  	if strings.Contains(string(content), "wrong") {
   163  		c.Fatalf("Build used the wrong dockerfile.")
   164  	}
   165  }
   166  
   167  func (s *DockerSuite) TestBuildApiLowerDockerfile(c *check.C) {
   168  	testRequires(c, DaemonIsLinux)
   169  	git, err := newFakeGit("repo", map[string]string{
   170  		"dockerfile": `FROM busybox
   171  RUN echo from dockerfile`,
   172  	}, false)
   173  	if err != nil {
   174  		c.Fatal(err)
   175  	}
   176  	defer git.Close()
   177  
   178  	res, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
   179  	c.Assert(err, check.IsNil)
   180  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   181  
   182  	buf, err := readBody(body)
   183  	if err != nil {
   184  		c.Fatal(err)
   185  	}
   186  
   187  	out := string(buf)
   188  	if !strings.Contains(out, "from dockerfile") {
   189  		c.Fatalf("Incorrect output: %s", out)
   190  	}
   191  }
   192  
   193  func (s *DockerSuite) TestBuildApiBuildGitWithF(c *check.C) {
   194  	testRequires(c, DaemonIsLinux)
   195  	git, err := newFakeGit("repo", map[string]string{
   196  		"baz": `FROM busybox
   197  RUN echo from baz`,
   198  		"Dockerfile": `FROM busybox
   199  RUN echo from Dockerfile`,
   200  	}, false)
   201  	if err != nil {
   202  		c.Fatal(err)
   203  	}
   204  	defer git.Close()
   205  
   206  	// Make sure it tries to 'dockerfile' query param value
   207  	res, body, err := sockRequestRaw("POST", "/build?dockerfile=baz&remote="+git.RepoURL, nil, "application/json")
   208  	c.Assert(err, check.IsNil)
   209  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   210  
   211  	buf, err := readBody(body)
   212  	if err != nil {
   213  		c.Fatal(err)
   214  	}
   215  
   216  	out := string(buf)
   217  	if !strings.Contains(out, "from baz") {
   218  		c.Fatalf("Incorrect output: %s", out)
   219  	}
   220  }
   221  
   222  func (s *DockerSuite) TestBuildApiDoubleDockerfile(c *check.C) {
   223  	testRequires(c, UnixCli) // dockerfile overwrites Dockerfile on Windows
   224  	git, err := newFakeGit("repo", map[string]string{
   225  		"Dockerfile": `FROM busybox
   226  RUN echo from Dockerfile`,
   227  		"dockerfile": `FROM busybox
   228  RUN echo from dockerfile`,
   229  	}, false)
   230  	if err != nil {
   231  		c.Fatal(err)
   232  	}
   233  	defer git.Close()
   234  
   235  	// Make sure it tries to 'dockerfile' query param value
   236  	res, body, err := sockRequestRaw("POST", "/build?remote="+git.RepoURL, nil, "application/json")
   237  	c.Assert(err, check.IsNil)
   238  	c.Assert(res.StatusCode, check.Equals, http.StatusOK)
   239  
   240  	buf, err := readBody(body)
   241  	if err != nil {
   242  		c.Fatal(err)
   243  	}
   244  
   245  	out := string(buf)
   246  	if !strings.Contains(out, "from Dockerfile") {
   247  		c.Fatalf("Incorrect output: %s", out)
   248  	}
   249  }
   250  
   251  func (s *DockerSuite) TestBuildApiDockerfileSymlink(c *check.C) {
   252  	// Test to make sure we stop people from trying to leave the
   253  	// build context when specifying a symlink as the path to the dockerfile
   254  	buffer := new(bytes.Buffer)
   255  	tw := tar.NewWriter(buffer)
   256  	defer tw.Close()
   257  
   258  	if err := tw.WriteHeader(&tar.Header{
   259  		Name:     "Dockerfile",
   260  		Typeflag: tar.TypeSymlink,
   261  		Linkname: "/etc/passwd",
   262  	}); err != nil {
   263  		c.Fatalf("failed to write tar file header: %v", err)
   264  	}
   265  	if err := tw.Close(); err != nil {
   266  		c.Fatalf("failed to close tar archive: %v", err)
   267  	}
   268  
   269  	res, body, err := sockRequestRaw("POST", "/build", buffer, "application/x-tar")
   270  	c.Assert(err, check.IsNil)
   271  	c.Assert(res.StatusCode, check.Equals, http.StatusInternalServerError)
   272  
   273  	out, err := readBody(body)
   274  	if err != nil {
   275  		c.Fatal(err)
   276  	}
   277  
   278  	// The reason the error is "Cannot locate specified Dockerfile" is because
   279  	// in the builder, the symlink is resolved within the context, therefore
   280  	// Dockerfile -> /etc/passwd becomes etc/passwd from the context which is
   281  	// a nonexistent file.
   282  	if !strings.Contains(string(out), "Cannot locate specified Dockerfile: Dockerfile") {
   283  		c.Fatalf("Didn't complain about leaving build context: %s", out)
   284  	}
   285  }