github.com/boynux/docker@v1.11.0-rc4/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/digest"
    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 := "Repository does not exist"
    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 := digest.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 := digest.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 := digest.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 := digest.DigestRegexp.FindString(out2)
   264  	c.Assert(len(digest2), checker.GreaterThan, 0, check.Commentf("no digest found for pushed manifest"))
   265  	c.Assert(digest1, 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  // This test ensures backwards compatibility with old ENV variables. Should be
   319  // deprecated by 1.10
   320  func (s *DockerTrustSuite) TestTrustedPushWithDeprecatedEnvPasswords(c *check.C) {
   321  	repoName := fmt.Sprintf("%v/dockercli/trusteddeprecated:latest", privateRegistryURL)
   322  	// tag the image and upload it to the private registry
   323  	dockerCmd(c, "tag", "busybox", repoName)
   324  
   325  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   326  	s.trustedCmdWithDeprecatedEnvPassphrases(pushCmd, "12345678", "12345678")
   327  	out, _, err := runCommandWithOutput(pushCmd)
   328  	c.Assert(err, check.IsNil, check.Commentf("Error running trusted push: %s\n%s", err, out))
   329  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push"))
   330  }
   331  
   332  func (s *DockerTrustSuite) TestTrustedPushWithFailingServer(c *check.C) {
   333  	repoName := fmt.Sprintf("%v/dockerclitrusted/failingserver:latest", privateRegistryURL)
   334  	// tag the image and upload it to the private registry
   335  	dockerCmd(c, "tag", "busybox", repoName)
   336  
   337  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   338  	s.trustedCmdWithServer(pushCmd, "https://example.com:81/")
   339  	out, _, err := runCommandWithOutput(pushCmd)
   340  	c.Assert(err, check.NotNil, check.Commentf("Missing error while running trusted push w/ no server"))
   341  	c.Assert(out, checker.Contains, "error contacting notary server", check.Commentf("Missing expected output on trusted push"))
   342  }
   343  
   344  func (s *DockerTrustSuite) TestTrustedPushWithoutServerAndUntrusted(c *check.C) {
   345  	repoName := fmt.Sprintf("%v/dockerclitrusted/trustedandnot:latest", privateRegistryURL)
   346  	// tag the image and upload it to the private registry
   347  	dockerCmd(c, "tag", "busybox", repoName)
   348  
   349  	pushCmd := exec.Command(dockerBinary, "push", "--disable-content-trust", repoName)
   350  	s.trustedCmdWithServer(pushCmd, "https://example.com/")
   351  	out, _, err := runCommandWithOutput(pushCmd)
   352  	c.Assert(err, check.IsNil, check.Commentf("trusted push with no server and --disable-content-trust failed: %s\n%s", err, out))
   353  	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:"))
   354  }
   355  
   356  func (s *DockerTrustSuite) TestTrustedPushWithExistingTag(c *check.C) {
   357  	repoName := fmt.Sprintf("%v/dockerclitag/trusted:latest", privateRegistryURL)
   358  	// tag the image and upload it to the private registry
   359  	dockerCmd(c, "tag", "busybox", repoName)
   360  	dockerCmd(c, "push", repoName)
   361  
   362  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   363  	s.trustedCmd(pushCmd)
   364  	out, _, err := runCommandWithOutput(pushCmd)
   365  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   366  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
   367  
   368  	// Try pull after push
   369  	pullCmd := exec.Command(dockerBinary, "pull", repoName)
   370  	s.trustedCmd(pullCmd)
   371  	out, _, err = runCommandWithOutput(pullCmd)
   372  	c.Assert(err, check.IsNil, check.Commentf(out))
   373  	c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf(out))
   374  }
   375  
   376  func (s *DockerTrustSuite) TestTrustedPushWithExistingSignedTag(c *check.C) {
   377  	repoName := fmt.Sprintf("%v/dockerclipushpush/trusted:latest", privateRegistryURL)
   378  	// tag the image and upload it to the private registry
   379  	dockerCmd(c, "tag", "busybox", repoName)
   380  
   381  	// Do a trusted push
   382  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   383  	s.trustedCmd(pushCmd)
   384  	out, _, err := runCommandWithOutput(pushCmd)
   385  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   386  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
   387  
   388  	// Do another trusted push
   389  	pushCmd = exec.Command(dockerBinary, "push", repoName)
   390  	s.trustedCmd(pushCmd)
   391  	out, _, err = runCommandWithOutput(pushCmd)
   392  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   393  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
   394  
   395  	dockerCmd(c, "rmi", repoName)
   396  
   397  	// Try pull to ensure the double push did not break our ability to pull
   398  	pullCmd := exec.Command(dockerBinary, "pull", repoName)
   399  	s.trustedCmd(pullCmd)
   400  	out, _, err = runCommandWithOutput(pullCmd)
   401  	c.Assert(err, check.IsNil, check.Commentf("Error running trusted pull: %s\n%s", err, out))
   402  	c.Assert(out, checker.Contains, "Status: Downloaded", check.Commentf("Missing expected output on trusted pull with --disable-content-trust"))
   403  
   404  }
   405  
   406  func (s *DockerTrustSuite) TestTrustedPushWithIncorrectPassphraseForNonRoot(c *check.C) {
   407  	repoName := fmt.Sprintf("%v/dockercliincorretpwd/trusted:latest", privateRegistryURL)
   408  	// tag the image and upload it to the private registry
   409  	dockerCmd(c, "tag", "busybox", repoName)
   410  
   411  	// Push with default passphrases
   412  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   413  	s.trustedCmd(pushCmd)
   414  	out, _, err := runCommandWithOutput(pushCmd)
   415  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   416  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push:\n%s", out))
   417  
   418  	// Push with wrong passphrases
   419  	pushCmd = exec.Command(dockerBinary, "push", repoName)
   420  	s.trustedCmdWithPassphrases(pushCmd, "12345678", "87654321")
   421  	out, _, err = runCommandWithOutput(pushCmd)
   422  	c.Assert(err, check.NotNil, check.Commentf("Error missing from trusted push with short targets passphrase: \n%s", out))
   423  	c.Assert(out, checker.Contains, "could not find necessary signing keys", check.Commentf("Missing expected output on trusted push with short targets/snapsnot passphrase"))
   424  }
   425  
   426  // This test ensures backwards compatibility with old ENV variables. Should be
   427  // deprecated by 1.10
   428  func (s *DockerTrustSuite) TestTrustedPushWithIncorrectDeprecatedPassphraseForNonRoot(c *check.C) {
   429  	repoName := fmt.Sprintf("%v/dockercliincorretdeprecatedpwd/trusted:latest", privateRegistryURL)
   430  	// tag the image and upload it to the private registry
   431  	dockerCmd(c, "tag", "busybox", repoName)
   432  
   433  	// Push with default passphrases
   434  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   435  	s.trustedCmd(pushCmd)
   436  	out, _, err := runCommandWithOutput(pushCmd)
   437  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   438  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push"))
   439  
   440  	// Push with wrong passphrases
   441  	pushCmd = exec.Command(dockerBinary, "push", repoName)
   442  	s.trustedCmdWithDeprecatedEnvPassphrases(pushCmd, "12345678", "87654321")
   443  	out, _, err = runCommandWithOutput(pushCmd)
   444  	c.Assert(err, check.NotNil, check.Commentf("Error missing from trusted push with short targets passphrase: \n%s", out))
   445  	c.Assert(out, checker.Contains, "could not find necessary signing keys", check.Commentf("Missing expected output on trusted push with short targets/snapsnot passphrase"))
   446  }
   447  
   448  func (s *DockerTrustSuite) TestTrustedPushWithExpiredSnapshot(c *check.C) {
   449  	c.Skip("Currently changes system time, causing instability")
   450  	repoName := fmt.Sprintf("%v/dockercliexpiredsnapshot/trusted:latest", privateRegistryURL)
   451  	// tag the image and upload it to the private registry
   452  	dockerCmd(c, "tag", "busybox", repoName)
   453  
   454  	// Push with default passphrases
   455  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   456  	s.trustedCmd(pushCmd)
   457  	out, _, err := runCommandWithOutput(pushCmd)
   458  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   459  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push"))
   460  
   461  	// Snapshots last for three years. This should be expired
   462  	fourYearsLater := time.Now().Add(time.Hour * 24 * 365 * 4)
   463  
   464  	runAtDifferentDate(fourYearsLater, func() {
   465  		// Push with wrong passphrases
   466  		pushCmd = exec.Command(dockerBinary, "push", repoName)
   467  		s.trustedCmd(pushCmd)
   468  		out, _, err = runCommandWithOutput(pushCmd)
   469  		c.Assert(err, check.NotNil, check.Commentf("Error missing from trusted push with expired snapshot: \n%s", out))
   470  		c.Assert(out, checker.Contains, "repository out-of-date", check.Commentf("Missing expected output on trusted push with expired snapshot"))
   471  	})
   472  }
   473  
   474  func (s *DockerTrustSuite) TestTrustedPushWithExpiredTimestamp(c *check.C) {
   475  	c.Skip("Currently changes system time, causing instability")
   476  	repoName := fmt.Sprintf("%v/dockercliexpiredtimestamppush/trusted:latest", privateRegistryURL)
   477  	// tag the image and upload it to the private registry
   478  	dockerCmd(c, "tag", "busybox", repoName)
   479  
   480  	// Push with default passphrases
   481  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   482  	s.trustedCmd(pushCmd)
   483  	out, _, err := runCommandWithOutput(pushCmd)
   484  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   485  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push"))
   486  
   487  	// The timestamps expire in two weeks. Lets check three
   488  	threeWeeksLater := time.Now().Add(time.Hour * 24 * 21)
   489  
   490  	// Should succeed because the server transparently re-signs one
   491  	runAtDifferentDate(threeWeeksLater, func() {
   492  		pushCmd := exec.Command(dockerBinary, "push", repoName)
   493  		s.trustedCmd(pushCmd)
   494  		out, _, err := runCommandWithOutput(pushCmd)
   495  		c.Assert(err, check.IsNil, check.Commentf("Error running trusted push: %s\n%s", err, out))
   496  		c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with expired timestamp"))
   497  	})
   498  }
   499  
   500  func (s *DockerTrustSuite) TestTrustedPushWithReleasesDelegationOnly(c *check.C) {
   501  	testRequires(c, NotaryHosting)
   502  	repoName := fmt.Sprintf("%v/dockerclireleasedelegationinitfirst/trusted", privateRegistryURL)
   503  	targetName := fmt.Sprintf("%s:latest", repoName)
   504  	s.notaryInitRepo(c, repoName)
   505  	s.notaryCreateDelegation(c, repoName, "targets/releases", s.not.keys[0].Public)
   506  	s.notaryPublish(c, repoName)
   507  
   508  	s.notaryImportKey(c, repoName, "targets/releases", s.not.keys[0].Private)
   509  
   510  	// tag the image and upload it to the private registry
   511  	dockerCmd(c, "tag", "busybox", targetName)
   512  
   513  	pushCmd := exec.Command(dockerBinary, "push", targetName)
   514  	s.trustedCmd(pushCmd)
   515  	out, _, err := runCommandWithOutput(pushCmd)
   516  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   517  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
   518  	// check to make sure that the target has been added to targets/releases and not targets
   519  	s.assertTargetInRoles(c, repoName, "latest", "targets/releases")
   520  	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
   521  
   522  	// Try pull after push
   523  	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
   524  
   525  	pullCmd := exec.Command(dockerBinary, "pull", targetName)
   526  	s.trustedCmd(pullCmd)
   527  	out, _, err = runCommandWithOutput(pullCmd)
   528  	c.Assert(err, check.IsNil, check.Commentf(out))
   529  	c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf(out))
   530  }
   531  
   532  func (s *DockerTrustSuite) TestTrustedPushSignsAllFirstLevelRolesWeHaveKeysFor(c *check.C) {
   533  	testRequires(c, NotaryHosting)
   534  	repoName := fmt.Sprintf("%v/dockerclimanyroles/trusted", privateRegistryURL)
   535  	targetName := fmt.Sprintf("%s:latest", repoName)
   536  	s.notaryInitRepo(c, repoName)
   537  	s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public)
   538  	s.notaryCreateDelegation(c, repoName, "targets/role2", s.not.keys[1].Public)
   539  	s.notaryCreateDelegation(c, repoName, "targets/role3", s.not.keys[2].Public)
   540  
   541  	// import everything except the third key
   542  	s.notaryImportKey(c, repoName, "targets/role1", s.not.keys[0].Private)
   543  	s.notaryImportKey(c, repoName, "targets/role2", s.not.keys[1].Private)
   544  
   545  	s.notaryCreateDelegation(c, repoName, "targets/role1/subrole", s.not.keys[3].Public)
   546  	s.notaryImportKey(c, repoName, "targets/role1/subrole", s.not.keys[3].Private)
   547  
   548  	s.notaryPublish(c, repoName)
   549  
   550  	// tag the image and upload it to the private registry
   551  	dockerCmd(c, "tag", "busybox", targetName)
   552  
   553  	pushCmd := exec.Command(dockerBinary, "push", targetName)
   554  	s.trustedCmd(pushCmd)
   555  	out, _, err := runCommandWithOutput(pushCmd)
   556  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   557  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
   558  
   559  	// check to make sure that the target has been added to targets/role1 and targets/role2, and
   560  	// not targets (because there are delegations) or targets/role3 (due to missing key) or
   561  	// targets/role1/subrole (due to it being a second level delegation)
   562  	s.assertTargetInRoles(c, repoName, "latest", "targets/role1", "targets/role2")
   563  	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
   564  
   565  	// Try pull after push
   566  	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
   567  
   568  	// pull should fail because none of these are the releases role
   569  	pullCmd := exec.Command(dockerBinary, "pull", targetName)
   570  	s.trustedCmd(pullCmd)
   571  	out, _, err = runCommandWithOutput(pullCmd)
   572  	c.Assert(err, check.NotNil, check.Commentf(out))
   573  }
   574  
   575  func (s *DockerTrustSuite) TestTrustedPushSignsForRolesWithKeysAndValidPaths(c *check.C) {
   576  	repoName := fmt.Sprintf("%v/dockerclirolesbykeysandpaths/trusted", privateRegistryURL)
   577  	targetName := fmt.Sprintf("%s:latest", repoName)
   578  	s.notaryInitRepo(c, repoName)
   579  	s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public, "l", "z")
   580  	s.notaryCreateDelegation(c, repoName, "targets/role2", s.not.keys[1].Public, "x", "y")
   581  	s.notaryCreateDelegation(c, repoName, "targets/role3", s.not.keys[2].Public, "latest")
   582  	s.notaryCreateDelegation(c, repoName, "targets/role4", s.not.keys[3].Public, "latest")
   583  
   584  	// import everything except the third key
   585  	s.notaryImportKey(c, repoName, "targets/role1", s.not.keys[0].Private)
   586  	s.notaryImportKey(c, repoName, "targets/role2", s.not.keys[1].Private)
   587  	s.notaryImportKey(c, repoName, "targets/role4", s.not.keys[3].Private)
   588  
   589  	s.notaryPublish(c, repoName)
   590  
   591  	// tag the image and upload it to the private registry
   592  	dockerCmd(c, "tag", "busybox", targetName)
   593  
   594  	pushCmd := exec.Command(dockerBinary, "push", targetName)
   595  	s.trustedCmd(pushCmd)
   596  	out, _, err := runCommandWithOutput(pushCmd)
   597  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   598  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
   599  
   600  	// check to make sure that the target has been added to targets/role1 and targets/role4, and
   601  	// not targets (because there are delegations) or targets/role2 (due to path restrictions) or
   602  	// targets/role3 (due to missing key)
   603  	s.assertTargetInRoles(c, repoName, "latest", "targets/role1", "targets/role4")
   604  	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
   605  
   606  	// Try pull after push
   607  	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
   608  
   609  	// pull should fail because none of these are the releases role
   610  	pullCmd := exec.Command(dockerBinary, "pull", targetName)
   611  	s.trustedCmd(pullCmd)
   612  	out, _, err = runCommandWithOutput(pullCmd)
   613  	c.Assert(err, check.NotNil, check.Commentf(out))
   614  }
   615  
   616  func (s *DockerTrustSuite) TestTrustedPushDoesntSignTargetsIfDelegationsExist(c *check.C) {
   617  	testRequires(c, NotaryHosting)
   618  	repoName := fmt.Sprintf("%v/dockerclireleasedelegationnotsignable/trusted", privateRegistryURL)
   619  	targetName := fmt.Sprintf("%s:latest", repoName)
   620  	s.notaryInitRepo(c, repoName)
   621  	s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public)
   622  	s.notaryPublish(c, repoName)
   623  
   624  	// do not import any delegations key
   625  
   626  	// tag the image and upload it to the private registry
   627  	dockerCmd(c, "tag", "busybox", targetName)
   628  
   629  	pushCmd := exec.Command(dockerBinary, "push", targetName)
   630  	s.trustedCmd(pushCmd)
   631  	out, _, err := runCommandWithOutput(pushCmd)
   632  	c.Assert(err, check.NotNil, check.Commentf("trusted push succeeded but should have failed:\n%s", out))
   633  	c.Assert(out, checker.Contains, "no valid signing keys",
   634  		check.Commentf("Missing expected output on trusted push without keys"))
   635  
   636  	s.assertTargetNotInRoles(c, repoName, "latest", "targets", "targets/role1")
   637  }
   638  
   639  func (s *DockerRegistryAuthHtpasswdSuite) TestPushNoCredentialsNoRetry(c *check.C) {
   640  	repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
   641  	dockerCmd(c, "tag", "busybox", repoName)
   642  	out, _, err := dockerCmdWithError("push", repoName)
   643  	c.Assert(err, check.NotNil, check.Commentf(out))
   644  	c.Assert(out, check.Not(checker.Contains), "Retrying")
   645  	c.Assert(out, checker.Contains, "no basic auth credentials")
   646  }
   647  
   648  // This may be flaky but it's needed not to regress on unauthorized push, see #21054
   649  func (s *DockerSuite) TestPushToCentralRegistryUnauthorized(c *check.C) {
   650  	testRequires(c, Network)
   651  	repoName := "test/busybox"
   652  	dockerCmd(c, "tag", "busybox", repoName)
   653  	out, _, err := dockerCmdWithError("push", repoName)
   654  	c.Assert(err, check.NotNil, check.Commentf(out))
   655  	c.Assert(out, check.Not(checker.Contains), "Retrying")
   656  }
   657  
   658  func getTestTokenService(status int, body string) *httptest.Server {
   659  	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   660  		w.WriteHeader(status)
   661  		w.Header().Set("Content-Type", "application/json")
   662  		w.Write([]byte(body))
   663  	}))
   664  }
   665  
   666  func (s *DockerRegistryAuthTokenSuite) TestPushTokenServiceUnauthResponse(c *check.C) {
   667  	ts := getTestTokenService(http.StatusUnauthorized, `{"errors": [{"Code":"UNAUTHORIZED", "message": "a message", "detail": null}]}`)
   668  	defer ts.Close()
   669  	s.setupRegistryWithTokenService(c, ts.URL)
   670  	repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
   671  	dockerCmd(c, "tag", "busybox", repoName)
   672  	out, _, err := dockerCmdWithError("push", repoName)
   673  	c.Assert(err, check.NotNil, check.Commentf(out))
   674  	c.Assert(out, checker.Not(checker.Contains), "Retrying")
   675  	c.Assert(out, checker.Contains, "unauthorized: a message")
   676  }
   677  
   678  func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseUnauthorized(c *check.C) {
   679  	ts := getTestTokenService(http.StatusUnauthorized, `{"error": "unauthorized"}`)
   680  	defer ts.Close()
   681  	s.setupRegistryWithTokenService(c, ts.URL)
   682  	repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
   683  	dockerCmd(c, "tag", "busybox", repoName)
   684  	out, _, err := dockerCmdWithError("push", repoName)
   685  	c.Assert(err, check.NotNil, check.Commentf(out))
   686  	c.Assert(out, checker.Not(checker.Contains), "Retrying")
   687  	split := strings.Split(out, "\n")
   688  	c.Assert(split[len(split)-2], check.Equals, "unauthorized: authentication required")
   689  }
   690  
   691  func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseError(c *check.C) {
   692  	ts := getTestTokenService(http.StatusInternalServerError, `{"error": "unexpected"}`)
   693  	defer ts.Close()
   694  	s.setupRegistryWithTokenService(c, ts.URL)
   695  	repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
   696  	dockerCmd(c, "tag", "busybox", repoName)
   697  	out, _, err := dockerCmdWithError("push", repoName)
   698  	c.Assert(err, check.NotNil, check.Commentf(out))
   699  	c.Assert(out, checker.Contains, "Retrying")
   700  	split := strings.Split(out, "\n")
   701  	c.Assert(split[len(split)-2], check.Equals, "received unexpected HTTP status: 500 Internal Server Error")
   702  }
   703  
   704  func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseUnparsable(c *check.C) {
   705  	ts := getTestTokenService(http.StatusForbidden, `no way`)
   706  	defer ts.Close()
   707  	s.setupRegistryWithTokenService(c, ts.URL)
   708  	repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
   709  	dockerCmd(c, "tag", "busybox", repoName)
   710  	out, _, err := dockerCmdWithError("push", repoName)
   711  	c.Assert(err, check.NotNil, check.Commentf(out))
   712  	c.Assert(out, checker.Not(checker.Contains), "Retrying")
   713  	split := strings.Split(out, "\n")
   714  	c.Assert(split[len(split)-2], checker.Contains, "error parsing HTTP 403 response body: ")
   715  }
   716  
   717  func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseNoToken(c *check.C) {
   718  	ts := getTestTokenService(http.StatusOK, `{"something": "wrong"}`)
   719  	defer ts.Close()
   720  	s.setupRegistryWithTokenService(c, ts.URL)
   721  	repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
   722  	dockerCmd(c, "tag", "busybox", repoName)
   723  	out, _, err := dockerCmdWithError("push", repoName)
   724  	c.Assert(err, check.NotNil, check.Commentf(out))
   725  	c.Assert(out, checker.Not(checker.Contains), "Retrying")
   726  	split := strings.Split(out, "\n")
   727  	c.Assert(split[len(split)-2], check.Equals, "authorization server did not include a token in the response")
   728  }