github.com/dpiddy/docker@v1.12.2-rc1/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 pushing again produces the same digest
   235  	out3, _, err := dockerCmdWithError("push", destRepoName)
   236  	c.Assert(err, check.IsNil, check.Commentf("pushing the image to the private registry has failed: %s", out2))
   237  
   238  	digest3 := reference.DigestRegexp.FindString(out3)
   239  	c.Assert(len(digest2), checker.GreaterThan, 0, check.Commentf("no digest found for pushed manifest"))
   240  	c.Assert(digest3, check.Equals, digest2)
   241  
   242  	// ensure that we can pull and run the cross-repo-pushed repository
   243  	dockerCmd(c, "rmi", destRepoName)
   244  	dockerCmd(c, "pull", destRepoName)
   245  	out4, _ := dockerCmd(c, "run", destRepoName, "echo", "-n", "hello world")
   246  	c.Assert(out4, check.Equals, "hello world")
   247  }
   248  
   249  func (s *DockerSchema1RegistrySuite) TestCrossRepositoryLayerPushNotSupported(c *check.C) {
   250  	sourceRepoName := fmt.Sprintf("%v/dockercli/busybox", privateRegistryURL)
   251  	// tag the image to upload it to the private registry
   252  	dockerCmd(c, "tag", "busybox", sourceRepoName)
   253  	// push the image to the registry
   254  	out1, _, err := dockerCmdWithError("push", sourceRepoName)
   255  	c.Assert(err, check.IsNil, check.Commentf("pushing the image to the private registry has failed: %s", out1))
   256  	// ensure that none of the layers were mounted from another repository during push
   257  	c.Assert(strings.Contains(out1, "Mounted from"), check.Equals, false)
   258  
   259  	digest1 := reference.DigestRegexp.FindString(out1)
   260  	c.Assert(len(digest1), checker.GreaterThan, 0, check.Commentf("no digest found for pushed manifest"))
   261  
   262  	destRepoName := fmt.Sprintf("%v/dockercli/crossrepopush", privateRegistryURL)
   263  	// retag the image to upload the same layers to another repo in the same registry
   264  	dockerCmd(c, "tag", "busybox", destRepoName)
   265  	// push the image to the registry
   266  	out2, _, err := dockerCmdWithError("push", destRepoName)
   267  	c.Assert(err, check.IsNil, check.Commentf("pushing the image to the private registry has failed: %s", out2))
   268  	// schema1 registry should not support cross-repo layer mounts, so ensure that this does not happen
   269  	c.Assert(strings.Contains(out2, "Mounted from"), check.Equals, false)
   270  
   271  	digest2 := reference.DigestRegexp.FindString(out2)
   272  	c.Assert(len(digest2), checker.GreaterThan, 0, check.Commentf("no digest found for pushed manifest"))
   273  	c.Assert(digest1, check.Not(check.Equals), digest2)
   274  
   275  	// ensure that we can pull and run the second pushed repository
   276  	dockerCmd(c, "rmi", destRepoName)
   277  	dockerCmd(c, "pull", destRepoName)
   278  	out3, _ := dockerCmd(c, "run", destRepoName, "echo", "-n", "hello world")
   279  	c.Assert(out3, check.Equals, "hello world")
   280  }
   281  
   282  func (s *DockerTrustSuite) TestTrustedPush(c *check.C) {
   283  	repoName := fmt.Sprintf("%v/dockerclitrusted/pushtest:latest", privateRegistryURL)
   284  	// tag the image and upload it to the private registry
   285  	dockerCmd(c, "tag", "busybox", repoName)
   286  
   287  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   288  	s.trustedCmd(pushCmd)
   289  	out, _, err := runCommandWithOutput(pushCmd)
   290  	c.Assert(err, check.IsNil, check.Commentf("Error running trusted push: %s\n%s", err, out))
   291  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push"))
   292  
   293  	// Try pull after push
   294  	pullCmd := exec.Command(dockerBinary, "pull", repoName)
   295  	s.trustedCmd(pullCmd)
   296  	out, _, err = runCommandWithOutput(pullCmd)
   297  	c.Assert(err, check.IsNil, check.Commentf(out))
   298  	c.Assert(string(out), checker.Contains, "Status: Image is up to date", check.Commentf(out))
   299  
   300  	// Assert that we rotated the snapshot key to the server by checking our local keystore
   301  	contents, err := ioutil.ReadDir(filepath.Join(cliconfig.ConfigDir(), "trust/private/tuf_keys", privateRegistryURL, "dockerclitrusted/pushtest"))
   302  	c.Assert(err, check.IsNil, check.Commentf("Unable to read local tuf key files"))
   303  	// Check that we only have 1 key (targets key)
   304  	c.Assert(contents, checker.HasLen, 1)
   305  }
   306  
   307  func (s *DockerTrustSuite) TestTrustedPushWithEnvPasswords(c *check.C) {
   308  	repoName := fmt.Sprintf("%v/dockerclienv/trusted:latest", privateRegistryURL)
   309  	// tag the image and upload it to the private registry
   310  	dockerCmd(c, "tag", "busybox", repoName)
   311  
   312  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   313  	s.trustedCmdWithPassphrases(pushCmd, "12345678", "12345678")
   314  	out, _, err := runCommandWithOutput(pushCmd)
   315  	c.Assert(err, check.IsNil, check.Commentf("Error running trusted push: %s\n%s", err, out))
   316  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push"))
   317  
   318  	// Try pull after push
   319  	pullCmd := exec.Command(dockerBinary, "pull", repoName)
   320  	s.trustedCmd(pullCmd)
   321  	out, _, err = runCommandWithOutput(pullCmd)
   322  	c.Assert(err, check.IsNil, check.Commentf(out))
   323  	c.Assert(string(out), checker.Contains, "Status: Image is up to date", check.Commentf(out))
   324  }
   325  
   326  func (s *DockerTrustSuite) TestTrustedPushWithFailingServer(c *check.C) {
   327  	repoName := fmt.Sprintf("%v/dockerclitrusted/failingserver:latest", privateRegistryURL)
   328  	// tag the image and upload it to the private registry
   329  	dockerCmd(c, "tag", "busybox", repoName)
   330  
   331  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   332  	// Using a name that doesn't resolve to an address makes this test faster
   333  	s.trustedCmdWithServer(pushCmd, "https://server.invalid:81/")
   334  	out, _, err := runCommandWithOutput(pushCmd)
   335  	c.Assert(err, check.NotNil, check.Commentf("Missing error while running trusted push w/ no server"))
   336  	c.Assert(out, checker.Contains, "error contacting notary server", check.Commentf("Missing expected output on trusted push"))
   337  }
   338  
   339  func (s *DockerTrustSuite) TestTrustedPushWithoutServerAndUntrusted(c *check.C) {
   340  	repoName := fmt.Sprintf("%v/dockerclitrusted/trustedandnot:latest", privateRegistryURL)
   341  	// tag the image and upload it to the private registry
   342  	dockerCmd(c, "tag", "busybox", repoName)
   343  
   344  	pushCmd := exec.Command(dockerBinary, "push", "--disable-content-trust", repoName)
   345  	// Using a name that doesn't resolve to an address makes this test faster
   346  	s.trustedCmdWithServer(pushCmd, "https://server.invalid")
   347  	out, _, err := runCommandWithOutput(pushCmd)
   348  	c.Assert(err, check.IsNil, check.Commentf("trusted push with no server and --disable-content-trust failed: %s\n%s", err, out))
   349  	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:"))
   350  }
   351  
   352  func (s *DockerTrustSuite) TestTrustedPushWithExistingTag(c *check.C) {
   353  	repoName := fmt.Sprintf("%v/dockerclitag/trusted:latest", privateRegistryURL)
   354  	// tag the image and upload it to the private registry
   355  	dockerCmd(c, "tag", "busybox", repoName)
   356  	dockerCmd(c, "push", repoName)
   357  
   358  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   359  	s.trustedCmd(pushCmd)
   360  	out, _, err := runCommandWithOutput(pushCmd)
   361  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   362  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
   363  
   364  	// Try pull after push
   365  	pullCmd := exec.Command(dockerBinary, "pull", repoName)
   366  	s.trustedCmd(pullCmd)
   367  	out, _, err = runCommandWithOutput(pullCmd)
   368  	c.Assert(err, check.IsNil, check.Commentf(out))
   369  	c.Assert(string(out), checker.Contains, "Status: Image is up to date", check.Commentf(out))
   370  }
   371  
   372  func (s *DockerTrustSuite) TestTrustedPushWithExistingSignedTag(c *check.C) {
   373  	repoName := fmt.Sprintf("%v/dockerclipushpush/trusted:latest", privateRegistryURL)
   374  	// tag the image and upload it to the private registry
   375  	dockerCmd(c, "tag", "busybox", repoName)
   376  
   377  	// Do a trusted push
   378  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   379  	s.trustedCmd(pushCmd)
   380  	out, _, err := runCommandWithOutput(pushCmd)
   381  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   382  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
   383  
   384  	// Do another trusted push
   385  	pushCmd = exec.Command(dockerBinary, "push", repoName)
   386  	s.trustedCmd(pushCmd)
   387  	out, _, err = runCommandWithOutput(pushCmd)
   388  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   389  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
   390  
   391  	dockerCmd(c, "rmi", repoName)
   392  
   393  	// Try pull to ensure the double push did not break our ability to pull
   394  	pullCmd := exec.Command(dockerBinary, "pull", repoName)
   395  	s.trustedCmd(pullCmd)
   396  	out, _, err = runCommandWithOutput(pullCmd)
   397  	c.Assert(err, check.IsNil, check.Commentf("Error running trusted pull: %s\n%s", err, out))
   398  	c.Assert(out, checker.Contains, "Status: Downloaded", check.Commentf("Missing expected output on trusted pull with --disable-content-trust"))
   399  
   400  }
   401  
   402  func (s *DockerTrustSuite) TestTrustedPushWithIncorrectPassphraseForNonRoot(c *check.C) {
   403  	repoName := fmt.Sprintf("%v/dockercliincorretpwd/trusted:latest", privateRegistryURL)
   404  	// tag the image and upload it to the private registry
   405  	dockerCmd(c, "tag", "busybox", repoName)
   406  
   407  	// Push with default passphrases
   408  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   409  	s.trustedCmd(pushCmd)
   410  	out, _, err := runCommandWithOutput(pushCmd)
   411  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   412  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push:\n%s", out))
   413  
   414  	// Push with wrong passphrases
   415  	pushCmd = exec.Command(dockerBinary, "push", repoName)
   416  	s.trustedCmdWithPassphrases(pushCmd, "12345678", "87654321")
   417  	out, _, err = runCommandWithOutput(pushCmd)
   418  	c.Assert(err, check.NotNil, check.Commentf("Error missing from trusted push with short targets passphrase: \n%s", out))
   419  	c.Assert(out, checker.Contains, "could not find necessary signing keys", check.Commentf("Missing expected output on trusted push with short targets/snapsnot passphrase"))
   420  }
   421  
   422  func (s *DockerTrustSuite) TestTrustedPushWithExpiredSnapshot(c *check.C) {
   423  	c.Skip("Currently changes system time, causing instability")
   424  	repoName := fmt.Sprintf("%v/dockercliexpiredsnapshot/trusted:latest", privateRegistryURL)
   425  	// tag the image and upload it to the private registry
   426  	dockerCmd(c, "tag", "busybox", repoName)
   427  
   428  	// Push with default passphrases
   429  	pushCmd := exec.Command(dockerBinary, "push", repoName)
   430  	s.trustedCmd(pushCmd)
   431  	out, _, err := runCommandWithOutput(pushCmd)
   432  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   433  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push"))
   434  
   435  	// Snapshots last for three years. This should be expired
   436  	fourYearsLater := time.Now().Add(time.Hour * 24 * 365 * 4)
   437  
   438  	runAtDifferentDate(fourYearsLater, func() {
   439  		// Push with wrong passphrases
   440  		pushCmd = exec.Command(dockerBinary, "push", repoName)
   441  		s.trustedCmd(pushCmd)
   442  		out, _, err = runCommandWithOutput(pushCmd)
   443  		c.Assert(err, check.NotNil, check.Commentf("Error missing from trusted push with expired snapshot: \n%s", out))
   444  		c.Assert(out, checker.Contains, "repository out-of-date", check.Commentf("Missing expected output on trusted push with expired snapshot"))
   445  	})
   446  }
   447  
   448  func (s *DockerTrustSuite) TestTrustedPushWithExpiredTimestamp(c *check.C) {
   449  	c.Skip("Currently changes system time, causing instability")
   450  	repoName := fmt.Sprintf("%v/dockercliexpiredtimestamppush/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  	// The timestamps expire in two weeks. Lets check three
   462  	threeWeeksLater := time.Now().Add(time.Hour * 24 * 21)
   463  
   464  	// Should succeed because the server transparently re-signs one
   465  	runAtDifferentDate(threeWeeksLater, func() {
   466  		pushCmd := exec.Command(dockerBinary, "push", repoName)
   467  		s.trustedCmd(pushCmd)
   468  		out, _, err := runCommandWithOutput(pushCmd)
   469  		c.Assert(err, check.IsNil, check.Commentf("Error running trusted push: %s\n%s", err, out))
   470  		c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with expired timestamp"))
   471  	})
   472  }
   473  
   474  func (s *DockerTrustSuite) TestTrustedPushWithReleasesDelegationOnly(c *check.C) {
   475  	testRequires(c, NotaryHosting)
   476  	repoName := fmt.Sprintf("%v/dockerclireleasedelegationinitfirst/trusted", privateRegistryURL)
   477  	targetName := fmt.Sprintf("%s:latest", repoName)
   478  	s.notaryInitRepo(c, repoName)
   479  	s.notaryCreateDelegation(c, repoName, "targets/releases", s.not.keys[0].Public)
   480  	s.notaryPublish(c, repoName)
   481  
   482  	s.notaryImportKey(c, repoName, "targets/releases", s.not.keys[0].Private)
   483  
   484  	// tag the image and upload it to the private registry
   485  	dockerCmd(c, "tag", "busybox", targetName)
   486  
   487  	pushCmd := exec.Command(dockerBinary, "push", targetName)
   488  	s.trustedCmd(pushCmd)
   489  	out, _, err := runCommandWithOutput(pushCmd)
   490  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   491  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
   492  	// check to make sure that the target has been added to targets/releases and not targets
   493  	s.assertTargetInRoles(c, repoName, "latest", "targets/releases")
   494  	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
   495  
   496  	// Try pull after push
   497  	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
   498  
   499  	pullCmd := exec.Command(dockerBinary, "pull", targetName)
   500  	s.trustedCmd(pullCmd)
   501  	out, _, err = runCommandWithOutput(pullCmd)
   502  	c.Assert(err, check.IsNil, check.Commentf(out))
   503  	c.Assert(string(out), checker.Contains, "Status: Image is up to date", check.Commentf(out))
   504  }
   505  
   506  func (s *DockerTrustSuite) TestTrustedPushSignsAllFirstLevelRolesWeHaveKeysFor(c *check.C) {
   507  	testRequires(c, NotaryHosting)
   508  	repoName := fmt.Sprintf("%v/dockerclimanyroles/trusted", privateRegistryURL)
   509  	targetName := fmt.Sprintf("%s:latest", repoName)
   510  	s.notaryInitRepo(c, repoName)
   511  	s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public)
   512  	s.notaryCreateDelegation(c, repoName, "targets/role2", s.not.keys[1].Public)
   513  	s.notaryCreateDelegation(c, repoName, "targets/role3", s.not.keys[2].Public)
   514  
   515  	// import everything except the third key
   516  	s.notaryImportKey(c, repoName, "targets/role1", s.not.keys[0].Private)
   517  	s.notaryImportKey(c, repoName, "targets/role2", s.not.keys[1].Private)
   518  
   519  	s.notaryCreateDelegation(c, repoName, "targets/role1/subrole", s.not.keys[3].Public)
   520  	s.notaryImportKey(c, repoName, "targets/role1/subrole", s.not.keys[3].Private)
   521  
   522  	s.notaryPublish(c, repoName)
   523  
   524  	// tag the image and upload it to the private registry
   525  	dockerCmd(c, "tag", "busybox", targetName)
   526  
   527  	pushCmd := exec.Command(dockerBinary, "push", targetName)
   528  	s.trustedCmd(pushCmd)
   529  	out, _, err := runCommandWithOutput(pushCmd)
   530  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   531  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
   532  
   533  	// check to make sure that the target has been added to targets/role1 and targets/role2, and
   534  	// not targets (because there are delegations) or targets/role3 (due to missing key) or
   535  	// targets/role1/subrole (due to it being a second level delegation)
   536  	s.assertTargetInRoles(c, repoName, "latest", "targets/role1", "targets/role2")
   537  	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
   538  
   539  	// Try pull after push
   540  	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
   541  
   542  	// pull should fail because none of these are the releases role
   543  	pullCmd := exec.Command(dockerBinary, "pull", targetName)
   544  	s.trustedCmd(pullCmd)
   545  	out, _, err = runCommandWithOutput(pullCmd)
   546  	c.Assert(err, check.NotNil, check.Commentf(out))
   547  }
   548  
   549  func (s *DockerTrustSuite) TestTrustedPushSignsForRolesWithKeysAndValidPaths(c *check.C) {
   550  	repoName := fmt.Sprintf("%v/dockerclirolesbykeysandpaths/trusted", privateRegistryURL)
   551  	targetName := fmt.Sprintf("%s:latest", repoName)
   552  	s.notaryInitRepo(c, repoName)
   553  	s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public, "l", "z")
   554  	s.notaryCreateDelegation(c, repoName, "targets/role2", s.not.keys[1].Public, "x", "y")
   555  	s.notaryCreateDelegation(c, repoName, "targets/role3", s.not.keys[2].Public, "latest")
   556  	s.notaryCreateDelegation(c, repoName, "targets/role4", s.not.keys[3].Public, "latest")
   557  
   558  	// import everything except the third key
   559  	s.notaryImportKey(c, repoName, "targets/role1", s.not.keys[0].Private)
   560  	s.notaryImportKey(c, repoName, "targets/role2", s.not.keys[1].Private)
   561  	s.notaryImportKey(c, repoName, "targets/role4", s.not.keys[3].Private)
   562  
   563  	s.notaryPublish(c, repoName)
   564  
   565  	// tag the image and upload it to the private registry
   566  	dockerCmd(c, "tag", "busybox", targetName)
   567  
   568  	pushCmd := exec.Command(dockerBinary, "push", targetName)
   569  	s.trustedCmd(pushCmd)
   570  	out, _, err := runCommandWithOutput(pushCmd)
   571  	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
   572  	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
   573  
   574  	// check to make sure that the target has been added to targets/role1 and targets/role4, and
   575  	// not targets (because there are delegations) or targets/role2 (due to path restrictions) or
   576  	// targets/role3 (due to missing key)
   577  	s.assertTargetInRoles(c, repoName, "latest", "targets/role1", "targets/role4")
   578  	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
   579  
   580  	// Try pull after push
   581  	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
   582  
   583  	// pull should fail because none of these are the releases role
   584  	pullCmd := exec.Command(dockerBinary, "pull", targetName)
   585  	s.trustedCmd(pullCmd)
   586  	out, _, err = runCommandWithOutput(pullCmd)
   587  	c.Assert(err, check.NotNil, check.Commentf(out))
   588  }
   589  
   590  func (s *DockerTrustSuite) TestTrustedPushDoesntSignTargetsIfDelegationsExist(c *check.C) {
   591  	testRequires(c, NotaryHosting)
   592  	repoName := fmt.Sprintf("%v/dockerclireleasedelegationnotsignable/trusted", privateRegistryURL)
   593  	targetName := fmt.Sprintf("%s:latest", repoName)
   594  	s.notaryInitRepo(c, repoName)
   595  	s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public)
   596  	s.notaryPublish(c, repoName)
   597  
   598  	// do not import any delegations key
   599  
   600  	// tag the image and upload it to the private registry
   601  	dockerCmd(c, "tag", "busybox", targetName)
   602  
   603  	pushCmd := exec.Command(dockerBinary, "push", targetName)
   604  	s.trustedCmd(pushCmd)
   605  	out, _, err := runCommandWithOutput(pushCmd)
   606  	c.Assert(err, check.NotNil, check.Commentf("trusted push succeeded but should have failed:\n%s", out))
   607  	c.Assert(out, checker.Contains, "no valid signing keys",
   608  		check.Commentf("Missing expected output on trusted push without keys"))
   609  
   610  	s.assertTargetNotInRoles(c, repoName, "latest", "targets", "targets/role1")
   611  }
   612  
   613  func (s *DockerRegistryAuthHtpasswdSuite) TestPushNoCredentialsNoRetry(c *check.C) {
   614  	repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
   615  	dockerCmd(c, "tag", "busybox", repoName)
   616  	out, _, err := dockerCmdWithError("push", repoName)
   617  	c.Assert(err, check.NotNil, check.Commentf(out))
   618  	c.Assert(out, check.Not(checker.Contains), "Retrying")
   619  	c.Assert(out, checker.Contains, "no basic auth credentials")
   620  }
   621  
   622  // This may be flaky but it's needed not to regress on unauthorized push, see #21054
   623  func (s *DockerSuite) TestPushToCentralRegistryUnauthorized(c *check.C) {
   624  	testRequires(c, Network)
   625  	repoName := "test/busybox"
   626  	dockerCmd(c, "tag", "busybox", repoName)
   627  	out, _, err := dockerCmdWithError("push", repoName)
   628  	c.Assert(err, check.NotNil, check.Commentf(out))
   629  	c.Assert(out, check.Not(checker.Contains), "Retrying")
   630  }
   631  
   632  func getTestTokenService(status int, body string) *httptest.Server {
   633  	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   634  		w.WriteHeader(status)
   635  		w.Header().Set("Content-Type", "application/json")
   636  		w.Write([]byte(body))
   637  	}))
   638  }
   639  
   640  func (s *DockerRegistryAuthTokenSuite) TestPushTokenServiceUnauthResponse(c *check.C) {
   641  	ts := getTestTokenService(http.StatusUnauthorized, `{"errors": [{"Code":"UNAUTHORIZED", "message": "a message", "detail": null}]}`)
   642  	defer ts.Close()
   643  	s.setupRegistryWithTokenService(c, ts.URL)
   644  	repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
   645  	dockerCmd(c, "tag", "busybox", repoName)
   646  	out, _, err := dockerCmdWithError("push", repoName)
   647  	c.Assert(err, check.NotNil, check.Commentf(out))
   648  	c.Assert(out, checker.Not(checker.Contains), "Retrying")
   649  	c.Assert(out, checker.Contains, "unauthorized: a message")
   650  }
   651  
   652  func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseUnauthorized(c *check.C) {
   653  	ts := getTestTokenService(http.StatusUnauthorized, `{"error": "unauthorized"}`)
   654  	defer ts.Close()
   655  	s.setupRegistryWithTokenService(c, ts.URL)
   656  	repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
   657  	dockerCmd(c, "tag", "busybox", repoName)
   658  	out, _, err := dockerCmdWithError("push", repoName)
   659  	c.Assert(err, check.NotNil, check.Commentf(out))
   660  	c.Assert(out, checker.Not(checker.Contains), "Retrying")
   661  	split := strings.Split(out, "\n")
   662  	c.Assert(split[len(split)-2], check.Equals, "unauthorized: authentication required")
   663  }
   664  
   665  func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseError(c *check.C) {
   666  	ts := getTestTokenService(http.StatusInternalServerError, `{"error": "unexpected"}`)
   667  	defer ts.Close()
   668  	s.setupRegistryWithTokenService(c, ts.URL)
   669  	repoName := fmt.Sprintf("%s/busybox", privateRegistryURL)
   670  	dockerCmd(c, "tag", "busybox", repoName)
   671  	out, _, err := dockerCmdWithError("push", repoName)
   672  	c.Assert(err, check.NotNil, check.Commentf(out))
   673  	c.Assert(out, checker.Contains, "Retrying")
   674  	split := strings.Split(out, "\n")
   675  	c.Assert(split[len(split)-2], check.Equals, "received unexpected HTTP status: 500 Internal Server Error")
   676  }
   677  
   678  func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseUnparsable(c *check.C) {
   679  	ts := getTestTokenService(http.StatusForbidden, `no way`)
   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], checker.Contains, "error parsing HTTP 403 response body: ")
   689  }
   690  
   691  func (s *DockerRegistryAuthTokenSuite) TestPushMisconfiguredTokenServiceResponseNoToken(c *check.C) {
   692  	ts := getTestTokenService(http.StatusOK, `{"something": "wrong"}`)
   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.Not(checker.Contains), "Retrying")
   700  	split := strings.Split(out, "\n")
   701  	c.Assert(split[len(split)-2], check.Equals, "authorization server did not include a token in the response")
   702  }