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