github.com/noxiouz/docker@v0.7.3-0.20160629055221-3d231c78e8c5/integration-cli/docker_cli_push_test.go (about)

     1  package main
     2  
     3  import (
     4  	"archive/tar"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"net/http/httptest"
     9  	"os"
    10  	"os/exec"
    11  	"path/filepath"
    12  	"strings"
    13  	"time"
    14  
    15  	"github.com/docker/distribution/reference"
    16  	"github.com/docker/docker/cliconfig"
    17  	"github.com/docker/docker/pkg/integration/checker"
    18  	"github.com/go-check/check"
    19  )
    20  
    21  // Pushing an image to a private registry.
    22  func testPushBusyboxImage(c *check.C) {
    23  	repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
    24  	// tag the image to upload it to the private registry
    25  	dockerCmd(c, "tag", "busybox", repoName)
    26  	// push the image to the registry
    27  	dockerCmd(c, "push", repoName)
    28  }
    29  
    30  func (s *DockerRegistrySuite) TestPushBusyboxImage(c *check.C) {
    31  	testPushBusyboxImage(c)
    32  }
    33  
    34  func (s *DockerSchema1RegistrySuite) TestPushBusyboxImage(c *check.C) {
    35  	testPushBusyboxImage(c)
    36  }
    37  
    38  // pushing an image without a prefix should throw an error
    39  func (s *DockerSuite) TestPushUnprefixedRepo(c *check.C) {
    40  	out, _, err := dockerCmdWithError("push", "busybox")
    41  	c.Assert(err, check.NotNil, check.Commentf("pushing an unprefixed repo didn't result in a non-zero exit status: %s", out))
    42  }
    43  
    44  func testPushUntagged(c *check.C) {
    45  	repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
    46  	expected := "An image does not exist locally with the tag"
    47  
    48  	out, _, err := dockerCmdWithError("push", repoName)
    49  	c.Assert(err, check.NotNil, check.Commentf("pushing the image to the private registry should have failed: output %q", out))
    50  	c.Assert(out, checker.Contains, expected, check.Commentf("pushing the image failed"))
    51  }
    52  
    53  func (s *DockerRegistrySuite) TestPushUntagged(c *check.C) {
    54  	testPushUntagged(c)
    55  }
    56  
    57  func (s *DockerSchema1RegistrySuite) TestPushUntagged(c *check.C) {
    58  	testPushUntagged(c)
    59  }
    60  
    61  func testPushBadTag(c *check.C) {
    62  	repoName := fmt.Sprintf("%v/dockercli/busybox:latest", privateRegistryURL)
    63  	expected := "does not exist"
    64  
    65  	out, _, err := dockerCmdWithError("push", repoName)
    66  	c.Assert(err, check.NotNil, check.Commentf("pushing the image to the private registry should have failed: output %q", out))
    67  	c.Assert(out, checker.Contains, expected, check.Commentf("pushing the image failed"))
    68  }
    69  
    70  func (s *DockerRegistrySuite) TestPushBadTag(c *check.C) {
    71  	testPushBadTag(c)
    72  }
    73  
    74  func (s *DockerSchema1RegistrySuite) TestPushBadTag(c *check.C) {
    75  	testPushBadTag(c)
    76  }
    77  
    78  func testPushMultipleTags(c *check.C) {
    79  	repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
    80  	repoTag1 := fmt.Sprintf("%v/dockercli/busybox:t1", privateRegistryURL)
    81  	repoTag2 := fmt.Sprintf("%v/dockercli/busybox:t2", privateRegistryURL)
    82  	// tag the image and upload it to the private registry
    83  	dockerCmd(c, "tag", "busybox", repoTag1)
    84  
    85  	dockerCmd(c, "tag", "busybox", repoTag2)
    86  
    87  	dockerCmd(c, "push", repoName)
    88  
    89  	// Ensure layer list is equivalent for repoTag1 and repoTag2
    90  	out1, _ := dockerCmd(c, "pull", repoTag1)
    91  
    92  	imageAlreadyExists := ": Image already exists"
    93  	var out1Lines []string
    94  	for _, outputLine := range strings.Split(out1, "\n") {
    95  		if strings.Contains(outputLine, imageAlreadyExists) {
    96  			out1Lines = append(out1Lines, outputLine)
    97  		}
    98  	}
    99  
   100  	out2, _ := dockerCmd(c, "pull", repoTag2)
   101  
   102  	var out2Lines []string
   103  	for _, outputLine := range strings.Split(out2, "\n") {
   104  		if strings.Contains(outputLine, imageAlreadyExists) {
   105  			out1Lines = append(out1Lines, outputLine)
   106  		}
   107  	}
   108  	c.Assert(out2Lines, checker.HasLen, len(out1Lines))
   109  
   110  	for i := range out1Lines {
   111  		c.Assert(out1Lines[i], checker.Equals, out2Lines[i])
   112  	}
   113  }
   114  
   115  func (s *DockerRegistrySuite) TestPushMultipleTags(c *check.C) {
   116  	testPushMultipleTags(c)
   117  }
   118  
   119  func (s *DockerSchema1RegistrySuite) TestPushMultipleTags(c *check.C) {
   120  	testPushMultipleTags(c)
   121  }
   122  
   123  func testPushEmptyLayer(c *check.C) {
   124  	repoName := fmt.Sprintf("%v/dockercli/emptylayer", privateRegistryURL)
   125  	emptyTarball, err := ioutil.TempFile("", "empty_tarball")
   126  	c.Assert(err, check.IsNil, check.Commentf("Unable to create test file"))
   127  
   128  	tw := tar.NewWriter(emptyTarball)
   129  	err = tw.Close()
   130  	c.Assert(err, check.IsNil, check.Commentf("Error creating empty tarball"))
   131  
   132  	freader, err := os.Open(emptyTarball.Name())
   133  	c.Assert(err, check.IsNil, check.Commentf("Could not open test tarball"))
   134  
   135  	importCmd := exec.Command(dockerBinary, "import", "-", repoName)
   136  	importCmd.Stdin = freader
   137  	out, _, err := runCommandWithOutput(importCmd)
   138  	c.Assert(err, check.IsNil, check.Commentf("import failed: %q", out))
   139  
   140  	// Now verify we can push it
   141  	out, _, err = dockerCmdWithError("push", repoName)
   142  	c.Assert(err, check.IsNil, check.Commentf("pushing the image to the private registry has failed: %s", out))
   143  }
   144  
   145  func (s *DockerRegistrySuite) TestPushEmptyLayer(c *check.C) {
   146  	testPushEmptyLayer(c)
   147  }
   148  
   149  func (s *DockerSchema1RegistrySuite) TestPushEmptyLayer(c *check.C) {
   150  	testPushEmptyLayer(c)
   151  }
   152  
   153  // testConcurrentPush pushes multiple tags to the same repo
   154  // concurrently.
   155  func testConcurrentPush(c *check.C) {
   156  	repoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
   157  
   158  	repos := []string{}
   159  	for _, tag := range []string{"push1", "push2", "push3"} {
   160  		repo := fmt.Sprintf("%v:%v", repoName, tag)
   161  		_, err := buildImage(repo, fmt.Sprintf(`
   162  	FROM busybox
   163  	ENTRYPOINT ["/bin/echo"]
   164  	ENV FOO foo
   165  	ENV BAR bar
   166  	CMD echo %s
   167  `, repo), true)
   168  		c.Assert(err, checker.IsNil)
   169  		repos = append(repos, repo)
   170  	}
   171  
   172  	// Push tags, in parallel
   173  	results := make(chan error)
   174  
   175  	for _, repo := range repos {
   176  		go func(repo string) {
   177  			_, _, err := runCommandWithOutput(exec.Command(dockerBinary, "push", repo))
   178  			results <- err
   179  		}(repo)
   180  	}
   181  
   182  	for range repos {
   183  		err := <-results
   184  		c.Assert(err, checker.IsNil, check.Commentf("concurrent push failed with error: %v", err))
   185  	}
   186  
   187  	// Clear local images store.
   188  	args := append([]string{"rmi"}, repos...)
   189  	dockerCmd(c, args...)
   190  
   191  	// Re-pull and run individual tags, to make sure pushes succeeded
   192  	for _, repo := range repos {
   193  		dockerCmd(c, "pull", repo)
   194  		dockerCmd(c, "inspect", repo)
   195  		out, _ := dockerCmd(c, "run", "--rm", repo)
   196  		c.Assert(strings.TrimSpace(out), checker.Equals, "/bin/sh -c echo "+repo)
   197  	}
   198  }
   199  
   200  func (s *DockerRegistrySuite) TestConcurrentPush(c *check.C) {
   201  	testConcurrentPush(c)
   202  }
   203  
   204  func (s *DockerSchema1RegistrySuite) TestConcurrentPush(c *check.C) {
   205  	testConcurrentPush(c)
   206  }
   207  
   208  func (s *DockerRegistrySuite) TestCrossRepositoryLayerPush(c *check.C) {
   209  	sourceRepoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
   210  	// tag the image to upload it to the private registry
   211  	dockerCmd(c, "tag", "busybox", sourceRepoName)
   212  	// push the image to the registry
   213  	out1, _, err := dockerCmdWithError("push", sourceRepoName)
   214  	c.Assert(err, check.IsNil, check.Commentf("pushing the image to the private registry has failed: %s", out1))
   215  	// ensure that none of the layers were mounted from another repository during push
   216  	c.Assert(strings.Contains(out1, "Mounted from"), check.Equals, false)
   217  
   218  	digest1 := reference.DigestRegexp.FindString(out1)
   219  	c.Assert(len(digest1), checker.GreaterThan, 0, check.Commentf("no digest found for pushed manifest"))
   220  
   221  	destRepoName := fmt.Sprintf("%v/dockercli/crossrepopush", privateRegistryURL)
   222  	// retag the image to upload the same layers to another repo in the same registry
   223  	dockerCmd(c, "tag", "busybox", destRepoName)
   224  	// push the image to the registry
   225  	out2, _, err := dockerCmdWithError("push", destRepoName)
   226  	c.Assert(err, check.IsNil, check.Commentf("pushing the image to the private registry has failed: %s", out2))
   227  	// ensure that layers were mounted from the first repo during push
   228  	c.Assert(strings.Contains(out2, "Mounted from dockercli/busybox"), check.Equals, true)
   229  
   230  	digest2 := reference.DigestRegexp.FindString(out2)
   231  	c.Assert(len(digest2), checker.GreaterThan, 0, check.Commentf("no digest found for pushed manifest"))
   232  	c.Assert(digest1, check.Equals, digest2)
   233  
   234  	// ensure that we can pull and run the cross-repo-pushed repository
   235  	dockerCmd(c, "rmi", destRepoName)
   236  	dockerCmd(c, "pull", destRepoName)
   237  	out3, _ := dockerCmd(c, "run", destRepoName, "echo", "-n", "hello world")
   238  	c.Assert(out3, check.Equals, "hello world")
   239  }
   240  
   241  func (s *DockerSchema1RegistrySuite) TestCrossRepositoryLayerPushNotSupported(c *check.C) {
   242  	sourceRepoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
   243  	// tag the image to upload it to the private registry
   244  	dockerCmd(c, "tag", "busybox", sourceRepoName)
   245  	// push the image to the registry
   246  	out1, _, err := dockerCmdWithError("push", sourceRepoName)
   247  	c.Assert(err, check.IsNil, check.Commentf("pushing the image to the private registry has failed: %s", out1))
   248  	// ensure that none of the layers were mounted from another repository during push
   249  	c.Assert(strings.Contains(out1, "Mounted from"), check.Equals, false)
   250  
   251  	digest1 := reference.DigestRegexp.FindString(out1)
   252  	c.Assert(len(digest1), checker.GreaterThan, 0, check.Commentf("no digest found for pushed manifest"))
   253  
   254  	destRepoName := fmt.Sprintf("%v/dockercli/crossrepopush", privateRegistryURL)
   255  	// retag the image to upload the same layers to another repo in the same registry
   256  	dockerCmd(c, "tag", "busybox", destRepoName)
   257  	// push the image to the registry
   258  	out2, _, err := dockerCmdWithError("push", destRepoName)
   259  	c.Assert(err, check.IsNil, check.Commentf("pushing the image to the private registry has failed: %s", out2))
   260  	// schema1 registry should not support cross-repo layer mounts, so ensure that this does not happen
   261  	c.Assert(strings.Contains(out2, "Mounted from"), check.Equals, false)
   262  
   263  	digest2 := reference.DigestRegexp.FindString(out2)
   264  	c.Assert(len(digest2), checker.GreaterThan, 0, check.Commentf("no digest found for pushed manifest"))
   265  	c.Assert(digest1, check.Not(check.Equals), digest2)
   266  
   267  	// ensure that we can pull and run the second pushed repository
   268  	dockerCmd(c, "rmi", destRepoName)
   269  	dockerCmd(c, "pull", destRepoName)
   270  	out3, _ := dockerCmd(c, "run", destRepoName, "echo", "-n", "hello world")
   271  	c.Assert(out3, check.Equals, "hello world")
   272  }
   273  
   274  func (s *DockerTrustSuite) TestTrustedPush(c *check.C) {
   275  	repoName := fmt.Sprintf("%v/dockerclitrusted/pushtest:latest", privateRegistryURL)
   276  	// tag the image and upload it to the private registry
   277  	dockerCmd(c, "tag", "busybox", repoName)
   278  
   279  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   280  	s.trustedCmd(pushCmd)
   281  	out, _, err := runCommandWithOutput(pushCmd)
   282  	c.Assert(err, check.IsNil, check.Commentf("Error running trusted push: %s\n%s", err, out))
   283  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push"))
   284  
   285  	// Try pull after push
   286  	pullCmd := exec.Command(dockerBinary, "pull", repoName)
   287  	s.trustedCmd(pullCmd)
   288  	out, _, err = runCommandWithOutput(pullCmd)
   289  	c.Assert(err, check.IsNil, check.Commentf(out))
   290  	c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf(out))
   291  
   292  	// Assert that we rotated the snapshot key to the server by checking our local keystore
   293  	contents, err := ioutil.ReadDir(filepath.Join(cliconfig.ConfigDir(), "trust/private/tuf_keys", privateRegistryURL, "dockerclitrusted/pushtest"))
   294  	c.Assert(err, check.IsNil, check.Commentf("Unable to read local tuf key files"))
   295  	// Check that we only have 1 key (targets key)
   296  	c.Assert(contents, checker.HasLen, 1)
   297  }
   298  
   299  func (s *DockerTrustSuite) TestTrustedPushWithEnvPasswords(c *check.C) {
   300  	repoName := fmt.Sprintf("%v/dockerclienv/trusted:latest", privateRegistryURL)
   301  	// tag the image and upload it to the private registry
   302  	dockerCmd(c, "tag", "busybox", repoName)
   303  
   304  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   305  	s.trustedCmdWithPassphrases(pushCmd, "12345678", "12345678")
   306  	out, _, err := runCommandWithOutput(pushCmd)
   307  	c.Assert(err, check.IsNil, check.Commentf("Error running trusted push: %s\n%s", err, out))
   308  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push"))
   309  
   310  	// Try pull after push
   311  	pullCmd := exec.Command(dockerBinary, "pull", repoName)
   312  	s.trustedCmd(pullCmd)
   313  	out, _, err = runCommandWithOutput(pullCmd)
   314  	c.Assert(err, check.IsNil, check.Commentf(out))
   315  	c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf(out))
   316  }
   317  
   318  func (s *DockerTrustSuite) TestTrustedPushWithFailingServer(c *check.C) {
   319  	repoName := fmt.Sprintf("%v/dockerclitrusted/failingserver:latest", privateRegistryURL)
   320  	// tag the image and upload it to the private registry
   321  	dockerCmd(c, "tag", "busybox", repoName)
   322  
   323  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   324  	// Using a name that doesn't resolve to an address makes this test faster
   325  	s.trustedCmdWithServer(pushCmd, "https://server.invalid:81/")
   326  	out, _, err := runCommandWithOutput(pushCmd)
   327  	c.Assert(err, check.NotNil, check.Commentf("Missing error while running trusted push w/ no server"))
   328  	c.Assert(out, checker.Contains, "error contacting notary server", check.Commentf("Missing expected output on trusted push"))
   329  }
   330  
   331  func (s *DockerTrustSuite) TestTrustedPushWithoutServerAndUntrusted(c *check.C) {
   332  	repoName := fmt.Sprintf("%v/dockerclitrusted/trustedandnot:latest", privateRegistryURL)
   333  	// tag the image and upload it to the private registry
   334  	dockerCmd(c, "tag", "busybox", repoName)
   335  
   336  	pushCmd := exec.Command(dockerBinary, "push", "--disable-content-trust", repoName)
   337  	// Using a name that doesn't resolve to an address makes this test faster
   338  	s.trustedCmdWithServer(pushCmd, "https://server.invalid")
   339  	out, _, err := runCommandWithOutput(pushCmd)
   340  	c.Assert(err, check.IsNil, check.Commentf("trusted push with no server and --disable-content-trust failed: %s\n%s", err, out))
   341  	c.Assert(out, check.Not(checker.Contains), "Error establishing connection to notary repository", check.Commentf("Missing expected output on trusted push with --disable-content-trust:"))
   342  }
   343  
   344  func (s *DockerTrustSuite) TestTrustedPushWithExistingTag(c *check.C) {
   345  	repoName := fmt.Sprintf("%v/dockerclitag/trusted:latest", privateRegistryURL)
   346  	// tag the image and upload it to the private registry
   347  	dockerCmd(c, "tag", "busybox", repoName)
   348  	dockerCmd(c, "push", repoName)
   349  
   350  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   351  	s.trustedCmd(pushCmd)
   352  	out, _, err := runCommandWithOutput(pushCmd)
   353  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   354  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
   355  
   356  	// Try pull after push
   357  	pullCmd := exec.Command(dockerBinary, "pull", repoName)
   358  	s.trustedCmd(pullCmd)
   359  	out, _, err = runCommandWithOutput(pullCmd)
   360  	c.Assert(err, check.IsNil, check.Commentf(out))
   361  	c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf(out))
   362  }
   363  
   364  func (s *DockerTrustSuite) TestTrustedPushWithExistingSignedTag(c *check.C) {
   365  	repoName := fmt.Sprintf("%v/dockerclipushpush/trusted:latest", privateRegistryURL)
   366  	// tag the image and upload it to the private registry
   367  	dockerCmd(c, "tag", "busybox", repoName)
   368  
   369  	// Do a trusted push
   370  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   371  	s.trustedCmd(pushCmd)
   372  	out, _, err := runCommandWithOutput(pushCmd)
   373  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   374  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
   375  
   376  	// Do another trusted push
   377  	pushCmd = exec.Command(dockerBinary, "push", repoName)
   378  	s.trustedCmd(pushCmd)
   379  	out, _, err = runCommandWithOutput(pushCmd)
   380  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   381  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
   382  
   383  	dockerCmd(c, "rmi", repoName)
   384  
   385  	// Try pull to ensure the double push did not break our ability to pull
   386  	pullCmd := exec.Command(dockerBinary, "pull", repoName)
   387  	s.trustedCmd(pullCmd)
   388  	out, _, err = runCommandWithOutput(pullCmd)
   389  	c.Assert(err, check.IsNil, check.Commentf("Error running trusted pull: %s\n%s", err, out))
   390  	c.Assert(out, checker.Contains, "Status: Downloaded", check.Commentf("Missing expected output on trusted pull with --disable-content-trust"))
   391  
   392  }
   393  
   394  func (s *DockerTrustSuite) TestTrustedPushWithIncorrectPassphraseForNonRoot(c *check.C) {
   395  	repoName := fmt.Sprintf("%v/dockercliincorretpwd/trusted:latest", privateRegistryURL)
   396  	// tag the image and upload it to the private registry
   397  	dockerCmd(c, "tag", "busybox", repoName)
   398  
   399  	// Push with default passphrases
   400  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   401  	s.trustedCmd(pushCmd)
   402  	out, _, err := runCommandWithOutput(pushCmd)
   403  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   404  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push:\n%s", out))
   405  
   406  	// Push with wrong passphrases
   407  	pushCmd = exec.Command(dockerBinary, "push", repoName)
   408  	s.trustedCmdWithPassphrases(pushCmd, "12345678", "87654321")
   409  	out, _, err = runCommandWithOutput(pushCmd)
   410  	c.Assert(err, check.NotNil, check.Commentf("Error missing from trusted push with short targets passphrase: \n%s", out))
   411  	c.Assert(out, checker.Contains, "could not find necessary signing keys", check.Commentf("Missing expected output on trusted push with short targets/snapsnot passphrase"))
   412  }
   413  
   414  func (s *DockerTrustSuite) TestTrustedPushWithExpiredSnapshot(c *check.C) {
   415  	c.Skip("Currently changes system time, causing instability")
   416  	repoName := fmt.Sprintf("%v/dockercliexpiredsnapshot/trusted:latest", privateRegistryURL)
   417  	// tag the image and upload it to the private registry
   418  	dockerCmd(c, "tag", "busybox", repoName)
   419  
   420  	// Push with default passphrases
   421  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   422  	s.trustedCmd(pushCmd)
   423  	out, _, err := runCommandWithOutput(pushCmd)
   424  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   425  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push"))
   426  
   427  	// Snapshots last for three years. This should be expired
   428  	fourYearsLater := time.Now().Add(time.Hour * 24 * 365 * 4)
   429  
   430  	runAtDifferentDate(fourYearsLater, func() {
   431  		// Push with wrong passphrases
   432  		pushCmd = exec.Command(dockerBinary, "push", repoName)
   433  		s.trustedCmd(pushCmd)
   434  		out, _, err = runCommandWithOutput(pushCmd)
   435  		c.Assert(err, check.NotNil, check.Commentf("Error missing from trusted push with expired snapshot: \n%s", out))
   436  		c.Assert(out, checker.Contains, "repository out-of-date", check.Commentf("Missing expected output on trusted push with expired snapshot"))
   437  	})
   438  }
   439  
   440  func (s *DockerTrustSuite) TestTrustedPushWithExpiredTimestamp(c *check.C) {
   441  	c.Skip("Currently changes system time, causing instability")
   442  	repoName := fmt.Sprintf("%v/dockercliexpiredtimestamppush/trusted:latest", privateRegistryURL)
   443  	// tag the image and upload it to the private registry
   444  	dockerCmd(c, "tag", "busybox", repoName)
   445  
   446  	// Push with default passphrases
   447  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   448  	s.trustedCmd(pushCmd)
   449  	out, _, err := runCommandWithOutput(pushCmd)
   450  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   451  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push"))
   452  
   453  	// The timestamps expire in two weeks. Lets check three
   454  	threeWeeksLater := time.Now().Add(time.Hour * 24 * 21)
   455  
   456  	// Should succeed because the server transparently re-signs one
   457  	runAtDifferentDate(threeWeeksLater, func() {
   458  		pushCmd := exec.Command(dockerBinary, "push", repoName)
   459  		s.trustedCmd(pushCmd)
   460  		out, _, err := runCommandWithOutput(pushCmd)
   461  		c.Assert(err, check.IsNil, check.Commentf("Error running trusted push: %s\n%s", err, out))
   462  		c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with expired timestamp"))
   463  	})
   464  }
   465  
   466  func (s *DockerTrustSuite) TestTrustedPushWithReleasesDelegationOnly(c *check.C) {
   467  	testRequires(c, NotaryHosting)
   468  	repoName := fmt.Sprintf("%v/dockerclireleasedelegationinitfirst/trusted", privateRegistryURL)
   469  	targetName := fmt.Sprintf("%s:latest", repoName)
   470  	s.notaryInitRepo(c, repoName)
   471  	s.notaryCreateDelegation(c, repoName, "targets/releases", s.not.keys[0].Public)
   472  	s.notaryPublish(c, repoName)
   473  
   474  	s.notaryImportKey(c, repoName, "targets/releases", s.not.keys[0].Private)
   475  
   476  	// tag the image and upload it to the private registry
   477  	dockerCmd(c, "tag", "busybox", targetName)
   478  
   479  	pushCmd := exec.Command(dockerBinary, "push", targetName)
   480  	s.trustedCmd(pushCmd)
   481  	out, _, err := runCommandWithOutput(pushCmd)
   482  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   483  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
   484  	// check to make sure that the target has been added to targets/releases and not targets
   485  	s.assertTargetInRoles(c, repoName, "latest", "targets/releases")
   486  	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
   487  
   488  	// Try pull after push
   489  	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
   490  
   491  	pullCmd := exec.Command(dockerBinary, "pull", targetName)
   492  	s.trustedCmd(pullCmd)
   493  	out, _, err = runCommandWithOutput(pullCmd)
   494  	c.Assert(err, check.IsNil, check.Commentf(out))
   495  	c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf(out))
   496  }
   497  
   498  func (s *DockerTrustSuite) TestTrustedPushSignsAllFirstLevelRolesWeHaveKeysFor(c *check.C) {
   499  	testRequires(c, NotaryHosting)
   500  	repoName := fmt.Sprintf("%v/dockerclimanyroles/trusted", privateRegistryURL)
   501  	targetName := fmt.Sprintf("%s:latest", repoName)
   502  	s.notaryInitRepo(c, repoName)
   503  	s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public)
   504  	s.notaryCreateDelegation(c, repoName, "targets/role2", s.not.keys[1].Public)
   505  	s.notaryCreateDelegation(c, repoName, "targets/role3", s.not.keys[2].Public)
   506  
   507  	// import everything except the third key
   508  	s.notaryImportKey(c, repoName, "targets/role1", s.not.keys[0].Private)
   509  	s.notaryImportKey(c, repoName, "targets/role2", s.not.keys[1].Private)
   510  
   511  	s.notaryCreateDelegation(c, repoName, "targets/role1/subrole", s.not.keys[3].Public)
   512  	s.notaryImportKey(c, repoName, "targets/role1/subrole", s.not.keys[3].Private)
   513  
   514  	s.notaryPublish(c, repoName)
   515  
   516  	// tag the image and upload it to the private registry
   517  	dockerCmd(c, "tag", "busybox", targetName)
   518  
   519  	pushCmd := exec.Command(dockerBinary, "push", targetName)
   520  	s.trustedCmd(pushCmd)
   521  	out, _, err := runCommandWithOutput(pushCmd)
   522  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   523  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
   524  
   525  	// check to make sure that the target has been added to targets/role1 and targets/role2, and
   526  	// not targets (because there are delegations) or targets/role3 (due to missing key) or
   527  	// targets/role1/subrole (due to it being a second level delegation)
   528  	s.assertTargetInRoles(c, repoName, "latest", "targets/role1", "targets/role2")
   529  	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
   530  
   531  	// Try pull after push
   532  	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
   533  
   534  	// pull should fail because none of these are the releases role
   535  	pullCmd := exec.Command(dockerBinary, "pull", targetName)
   536  	s.trustedCmd(pullCmd)
   537  	out, _, err = runCommandWithOutput(pullCmd)
   538  	c.Assert(err, check.NotNil, check.Commentf(out))
   539  }
   540  
   541  func (s *DockerTrustSuite) TestTrustedPushSignsForRolesWithKeysAndValidPaths(c *check.C) {
   542  	repoName := fmt.Sprintf("%v/dockerclirolesbykeysandpaths/trusted", privateRegistryURL)
   543  	targetName := fmt.Sprintf("%s:latest", repoName)
   544  	s.notaryInitRepo(c, repoName)
   545  	s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public, "l", "z")
   546  	s.notaryCreateDelegation(c, repoName, "targets/role2", s.not.keys[1].Public, "x", "y")
   547  	s.notaryCreateDelegation(c, repoName, "targets/role3", s.not.keys[2].Public, "latest")
   548  	s.notaryCreateDelegation(c, repoName, "targets/role4", s.not.keys[3].Public, "latest")
   549  
   550  	// import everything except the third key
   551  	s.notaryImportKey(c, repoName, "targets/role1", s.not.keys[0].Private)
   552  	s.notaryImportKey(c, repoName, "targets/role2", s.not.keys[1].Private)
   553  	s.notaryImportKey(c, repoName, "targets/role4", s.not.keys[3].Private)
   554  
   555  	s.notaryPublish(c, repoName)
   556  
   557  	// tag the image and upload it to the private registry
   558  	dockerCmd(c, "tag", "busybox", targetName)
   559  
   560  	pushCmd := exec.Command(dockerBinary, "push", targetName)
   561  	s.trustedCmd(pushCmd)
   562  	out, _, err := runCommandWithOutput(pushCmd)
   563  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   564  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
   565  
   566  	// check to make sure that the target has been added to targets/role1 and targets/role4, and
   567  	// not targets (because there are delegations) or targets/role2 (due to path restrictions) or
   568  	// targets/role3 (due to missing key)
   569  	s.assertTargetInRoles(c, repoName, "latest", "targets/role1", "targets/role4")
   570  	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
   571  
   572  	// Try pull after push
   573  	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
   574  
   575  	// pull should fail because none of these are the releases role
   576  	pullCmd := exec.Command(dockerBinary, "pull", targetName)
   577  	s.trustedCmd(pullCmd)
   578  	out, _, err = runCommandWithOutput(pullCmd)
   579  	c.Assert(err, check.NotNil, check.Commentf(out))
   580  }
   581  
   582  func (s *DockerTrustSuite) TestTrustedPushDoesntSignTargetsIfDelegationsExist(c *check.C) {
   583  	testRequires(c, NotaryHosting)
   584  	repoName := fmt.Sprintf("%v/dockerclireleasedelegationnotsignable/trusted", privateRegistryURL)
   585  	targetName := fmt.Sprintf("%s:latest", repoName)
   586  	s.notaryInitRepo(c, repoName)
   587  	s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public)
   588  	s.notaryPublish(c, repoName)
   589  
   590  	// do not import any delegations key
   591  
   592  	// tag the image and upload it to the private registry
   593  	dockerCmd(c, "tag", "busybox", targetName)
   594  
   595  	pushCmd := exec.Command(dockerBinary, "push", targetName)
   596  	s.trustedCmd(pushCmd)
   597  	out, _, err := runCommandWithOutput(pushCmd)
   598  	c.Assert(err, check.NotNil, check.Commentf("trusted push succeeded but should have failed:\n%s", out))
   599  	c.Assert(out, checker.Contains, "no valid signing keys",
   600  		check.Commentf("Missing expected output on trusted push without keys"))
   601  
   602  	s.assertTargetNotInRoles(c, repoName, "latest", "targets", "targets/role1")
   603  }
   604  
   605  func (s *DockerRegistryAuthHtpasswdSuite) TestPushNoCredentialsNoRetry(c *check.C) {
   606  	repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
   607  	dockerCmd(c, "tag", "busybox", repoName)
   608  	out, _, err := dockerCmdWithError("push", repoName)
   609  	c.Assert(err, check.NotNil, check.Commentf(out))
   610  	c.Assert(out, check.Not(checker.Contains), "Retrying")
   611  	c.Assert(out, checker.Contains, "no basic auth credentials")
   612  }
   613  
   614  // This may be flaky but it's needed not to regress on unauthorized push, see #21054
   615  func (s *DockerSuite) TestPushToCentralRegistryUnauthorized(c *check.C) {
   616  	testRequires(c, Network)
   617  	repoName := "test/busybox"
   618  	dockerCmd(c, "tag", "busybox", repoName)
   619  	out, _, err := dockerCmdWithError("push", repoName)
   620  	c.Assert(err, check.NotNil, check.Commentf(out))
   621  	c.Assert(out, check.Not(checker.Contains), "Retrying")
   622  }
   623  
   624  func getTestTokenService(status int, body string) *httptest.Server {
   625  	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   626  		w.WriteHeader(status)
   627  		w.Header().Set("Content-Type", "application/json")
   628  		w.Write([]byte(body))
   629  	}))
   630  }
   631  
   632  func (s *DockerRegistryAuthTokenSuite) TestPushTokenServiceUnauthResponse(c *check.C) {
   633  	ts := getTestTokenService(http.StatusUnauthorized, `{"errors": [{"Code":"UNAUTHORIZED", "message": "a message", "detail": null}]}`)
   634  	defer ts.Close()
   635  	s.setupRegistryWithTokenService(c, ts.URL)
   636  	repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
   637  	dockerCmd(c, "tag", "busybox", repoName)
   638  	out, _, err := dockerCmdWithError("push", repoName)
   639  	c.Assert(err, check.NotNil, check.Commentf(out))
   640  	c.Assert(out, checker.Not(checker.Contains), "Retrying")
   641  	c.Assert(out, checker.Contains, "unauthorized: a message")
   642  }
   643  
   644  func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseUnauthorized(c *check.C) {
   645  	ts := getTestTokenService(http.StatusUnauthorized, `{"error": "unauthorized"}`)
   646  	defer ts.Close()
   647  	s.setupRegistryWithTokenService(c, ts.URL)
   648  	repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
   649  	dockerCmd(c, "tag", "busybox", repoName)
   650  	out, _, err := dockerCmdWithError("push", repoName)
   651  	c.Assert(err, check.NotNil, check.Commentf(out))
   652  	c.Assert(out, checker.Not(checker.Contains), "Retrying")
   653  	split := strings.Split(out, "\n")
   654  	c.Assert(split[len(split)-2], check.Equals, "unauthorized: authentication required")
   655  }
   656  
   657  func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseError(c *check.C) {
   658  	ts := getTestTokenService(http.StatusInternalServerError, `{"error": "unexpected"}`)
   659  	defer ts.Close()
   660  	s.setupRegistryWithTokenService(c, ts.URL)
   661  	repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
   662  	dockerCmd(c, "tag", "busybox", repoName)
   663  	out, _, err := dockerCmdWithError("push", repoName)
   664  	c.Assert(err, check.NotNil, check.Commentf(out))
   665  	c.Assert(out, checker.Contains, "Retrying")
   666  	split := strings.Split(out, "\n")
   667  	c.Assert(split[len(split)-2], check.Equals, "received unexpected HTTP status: 500 Internal Server Error")
   668  }
   669  
   670  func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseUnparsable(c *check.C) {
   671  	ts := getTestTokenService(http.StatusForbidden, `no way`)
   672  	defer ts.Close()
   673  	s.setupRegistryWithTokenService(c, ts.URL)
   674  	repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
   675  	dockerCmd(c, "tag", "busybox", repoName)
   676  	out, _, err := dockerCmdWithError("push", repoName)
   677  	c.Assert(err, check.NotNil, check.Commentf(out))
   678  	c.Assert(out, checker.Not(checker.Contains), "Retrying")
   679  	split := strings.Split(out, "\n")
   680  	c.Assert(split[len(split)-2], checker.Contains, "error parsing HTTP 403 response body: ")
   681  }
   682  
   683  func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseNoToken(c *check.C) {
   684  	ts := getTestTokenService(http.StatusOK, `{"something": "wrong"}`)
   685  	defer ts.Close()
   686  	s.setupRegistryWithTokenService(c, ts.URL)
   687  	repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
   688  	dockerCmd(c, "tag", "busybox", repoName)
   689  	out, _, err := dockerCmdWithError("push", repoName)
   690  	c.Assert(err, check.NotNil, check.Commentf(out))
   691  	c.Assert(out, checker.Not(checker.Contains), "Retrying")
   692  	split := strings.Split(out, "\n")
   693  	c.Assert(split[len(split)-2], check.Equals, "authorization server did not include a token in the response")
   694  }