github.com/sijibomii/docker@v0.0.0-20231230191044-5cf6ca554647/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 := "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 := 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 }