github.com/ruphin/docker@v1.10.1/integration-cli/docker_cli_by_digest_test.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "os" 7 "path/filepath" 8 "regexp" 9 "strings" 10 11 "github.com/docker/distribution/digest" 12 "github.com/docker/distribution/manifest/schema1" 13 "github.com/docker/distribution/manifest/schema2" 14 "github.com/docker/docker/pkg/integration/checker" 15 "github.com/docker/docker/pkg/stringutils" 16 "github.com/docker/engine-api/types" 17 "github.com/go-check/check" 18 ) 19 20 var ( 21 remoteRepoName = "dockercli/busybox-by-dgst" 22 repoName = fmt.Sprintf("%v/%s", privateRegistryURL, remoteRepoName) 23 pushDigestRegex = regexp.MustCompile("[\\S]+: digest: ([\\S]+) size: [0-9]+") 24 digestRegex = regexp.MustCompile("Digest: ([\\S]+)") 25 ) 26 27 func setupImage(c *check.C) (digest.Digest, error) { 28 return setupImageWithTag(c, "latest") 29 } 30 31 func setupImageWithTag(c *check.C, tag string) (digest.Digest, error) { 32 containerName := "busyboxbydigest" 33 34 dockerCmd(c, "run", "-d", "-e", "digest=1", "--name", containerName, "busybox") 35 36 // tag the image to upload it to the private registry 37 repoAndTag := repoName + ":" + tag 38 out, _, err := dockerCmdWithError("commit", containerName, repoAndTag) 39 c.Assert(err, checker.IsNil, check.Commentf("image tagging failed: %s", out)) 40 41 // delete the container as we don't need it any more 42 err = deleteContainer(containerName) 43 c.Assert(err, checker.IsNil) 44 45 // push the image 46 out, _, err = dockerCmdWithError("push", repoAndTag) 47 c.Assert(err, checker.IsNil, check.Commentf("pushing the image to the private registry has failed: %s", out)) 48 49 // delete our local repo that we previously tagged 50 rmiout, _, err := dockerCmdWithError("rmi", repoAndTag) 51 c.Assert(err, checker.IsNil, check.Commentf("error deleting images prior to real test: %s", rmiout)) 52 53 matches := pushDigestRegex.FindStringSubmatch(out) 54 c.Assert(matches, checker.HasLen, 2, check.Commentf("unable to parse digest from push output: %s", out)) 55 pushDigest := matches[1] 56 57 return digest.Digest(pushDigest), nil 58 } 59 60 func testPullByTagDisplaysDigest(c *check.C) { 61 testRequires(c, DaemonIsLinux) 62 pushDigest, err := setupImage(c) 63 c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) 64 65 // pull from the registry using the tag 66 out, _ := dockerCmd(c, "pull", repoName) 67 68 // the pull output includes "Digest: <digest>", so find that 69 matches := digestRegex.FindStringSubmatch(out) 70 c.Assert(matches, checker.HasLen, 2, check.Commentf("unable to parse digest from pull output: %s", out)) 71 pullDigest := matches[1] 72 73 // make sure the pushed and pull digests match 74 c.Assert(pushDigest.String(), checker.Equals, pullDigest) 75 } 76 77 func (s *DockerRegistrySuite) TestPullByTagDisplaysDigest(c *check.C) { 78 testPullByTagDisplaysDigest(c) 79 } 80 81 func (s *DockerSchema1RegistrySuite) TestPullByTagDisplaysDigest(c *check.C) { 82 testPullByTagDisplaysDigest(c) 83 } 84 85 func testPullByDigest(c *check.C) { 86 testRequires(c, DaemonIsLinux) 87 pushDigest, err := setupImage(c) 88 c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) 89 90 // pull from the registry using the <name>@<digest> reference 91 imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest) 92 out, _ := dockerCmd(c, "pull", imageReference) 93 94 // the pull output includes "Digest: <digest>", so find that 95 matches := digestRegex.FindStringSubmatch(out) 96 c.Assert(matches, checker.HasLen, 2, check.Commentf("unable to parse digest from pull output: %s", out)) 97 pullDigest := matches[1] 98 99 // make sure the pushed and pull digests match 100 c.Assert(pushDigest.String(), checker.Equals, pullDigest) 101 } 102 103 func (s *DockerRegistrySuite) TestPullByDigest(c *check.C) { 104 testPullByDigest(c) 105 } 106 107 func (s *DockerSchema1RegistrySuite) TestPullByDigest(c *check.C) { 108 testPullByDigest(c) 109 } 110 111 func testPullByDigestNoFallback(c *check.C) { 112 testRequires(c, DaemonIsLinux) 113 // pull from the registry using the <name>@<digest> reference 114 imageReference := fmt.Sprintf("%s@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", repoName) 115 out, _, err := dockerCmdWithError("pull", imageReference) 116 c.Assert(err, checker.NotNil, check.Commentf("expected non-zero exit status and correct error message when pulling non-existing image")) 117 c.Assert(out, checker.Contains, "manifest unknown", check.Commentf("expected non-zero exit status and correct error message when pulling non-existing image")) 118 } 119 120 func (s *DockerRegistrySuite) TestPullByDigestNoFallback(c *check.C) { 121 testPullByDigestNoFallback(c) 122 } 123 124 func (s *DockerSchema1RegistrySuite) TestPullByDigestNoFallback(c *check.C) { 125 testPullByDigestNoFallback(c) 126 } 127 128 func (s *DockerRegistrySuite) TestCreateByDigest(c *check.C) { 129 pushDigest, err := setupImage(c) 130 c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) 131 132 imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest) 133 134 containerName := "createByDigest" 135 out, _ := dockerCmd(c, "create", "--name", containerName, imageReference) 136 137 res, err := inspectField(containerName, "Config.Image") 138 c.Assert(err, checker.IsNil, check.Commentf("failed to get Config.Image: %s", out)) 139 c.Assert(res, checker.Equals, imageReference) 140 } 141 142 func (s *DockerRegistrySuite) TestRunByDigest(c *check.C) { 143 pushDigest, err := setupImage(c) 144 c.Assert(err, checker.IsNil) 145 146 imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest) 147 148 containerName := "runByDigest" 149 out, _ := dockerCmd(c, "run", "--name", containerName, imageReference, "sh", "-c", "echo found=$digest") 150 151 foundRegex := regexp.MustCompile("found=([^\n]+)") 152 matches := foundRegex.FindStringSubmatch(out) 153 c.Assert(matches, checker.HasLen, 2, check.Commentf("unable to parse digest from pull output: %s", out)) 154 c.Assert(matches[1], checker.Equals, "1", check.Commentf("Expected %q, got %q", "1", matches[1])) 155 156 res, err := inspectField(containerName, "Config.Image") 157 c.Assert(err, checker.IsNil, check.Commentf("failed to get Config.Image: %s", out)) 158 c.Assert(res, checker.Equals, imageReference) 159 } 160 161 func (s *DockerRegistrySuite) TestRemoveImageByDigest(c *check.C) { 162 digest, err := setupImage(c) 163 c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) 164 165 imageReference := fmt.Sprintf("%s@%s", repoName, digest) 166 167 // pull from the registry using the <name>@<digest> reference 168 dockerCmd(c, "pull", imageReference) 169 170 // make sure inspect runs ok 171 _, err = inspectField(imageReference, "Id") 172 c.Assert(err, checker.IsNil, check.Commentf("failed to inspect image")) 173 174 // do the delete 175 err = deleteImages(imageReference) 176 c.Assert(err, checker.IsNil, check.Commentf("unexpected error deleting image")) 177 178 // try to inspect again - it should error this time 179 _, err = inspectField(imageReference, "Id") 180 //unexpected nil err trying to inspect what should be a non-existent image 181 c.Assert(err, checker.NotNil) 182 c.Assert(err.Error(), checker.Contains, "No such image") 183 } 184 185 func (s *DockerRegistrySuite) TestBuildByDigest(c *check.C) { 186 digest, err := setupImage(c) 187 c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) 188 189 imageReference := fmt.Sprintf("%s@%s", repoName, digest) 190 191 // pull from the registry using the <name>@<digest> reference 192 dockerCmd(c, "pull", imageReference) 193 194 // get the image id 195 imageID, err := inspectField(imageReference, "Id") 196 c.Assert(err, checker.IsNil, check.Commentf("error getting image id")) 197 198 // do the build 199 name := "buildbydigest" 200 _, err = buildImage(name, fmt.Sprintf( 201 `FROM %s 202 CMD ["/bin/echo", "Hello World"]`, imageReference), 203 true) 204 c.Assert(err, checker.IsNil) 205 206 // get the build's image id 207 res, err := inspectField(name, "Config.Image") 208 c.Assert(err, checker.IsNil) 209 // make sure they match 210 c.Assert(res, checker.Equals, imageID) 211 } 212 213 func (s *DockerRegistrySuite) TestTagByDigest(c *check.C) { 214 digest, err := setupImage(c) 215 c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) 216 217 imageReference := fmt.Sprintf("%s@%s", repoName, digest) 218 219 // pull from the registry using the <name>@<digest> reference 220 dockerCmd(c, "pull", imageReference) 221 222 // tag it 223 tag := "tagbydigest" 224 dockerCmd(c, "tag", imageReference, tag) 225 226 expectedID, err := inspectField(imageReference, "Id") 227 c.Assert(err, checker.IsNil, check.Commentf("error getting original image id")) 228 229 tagID, err := inspectField(tag, "Id") 230 c.Assert(err, checker.IsNil, check.Commentf("error getting tagged image id")) 231 c.Assert(tagID, checker.Equals, expectedID) 232 } 233 234 func (s *DockerRegistrySuite) TestListImagesWithoutDigests(c *check.C) { 235 digest, err := setupImage(c) 236 c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) 237 238 imageReference := fmt.Sprintf("%s@%s", repoName, digest) 239 240 // pull from the registry using the <name>@<digest> reference 241 dockerCmd(c, "pull", imageReference) 242 243 out, _ := dockerCmd(c, "images") 244 c.Assert(out, checker.Not(checker.Contains), "DIGEST", check.Commentf("list output should not have contained DIGEST header")) 245 } 246 247 func (s *DockerRegistrySuite) TestListImagesWithDigests(c *check.C) { 248 249 // setup image1 250 digest1, err := setupImageWithTag(c, "tag1") 251 c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) 252 imageReference1 := fmt.Sprintf("%s@%s", repoName, digest1) 253 c.Logf("imageReference1 = %s", imageReference1) 254 255 // pull image1 by digest 256 dockerCmd(c, "pull", imageReference1) 257 258 // list images 259 out, _ := dockerCmd(c, "images", "--digests") 260 261 // make sure repo shown, tag=<none>, digest = $digest1 262 re1 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest1.String() + `\s`) 263 c.Assert(re1.MatchString(out), checker.True, check.Commentf("expected %q: %s", re1.String(), out)) 264 // setup image2 265 digest2, err := setupImageWithTag(c, "tag2") 266 //error setting up image 267 c.Assert(err, checker.IsNil) 268 imageReference2 := fmt.Sprintf("%s@%s", repoName, digest2) 269 c.Logf("imageReference2 = %s", imageReference2) 270 271 // pull image1 by digest 272 dockerCmd(c, "pull", imageReference1) 273 274 // pull image2 by digest 275 dockerCmd(c, "pull", imageReference2) 276 277 // list images 278 out, _ = dockerCmd(c, "images", "--digests") 279 280 // make sure repo shown, tag=<none>, digest = $digest1 281 c.Assert(re1.MatchString(out), checker.True, check.Commentf("expected %q: %s", re1.String(), out)) 282 283 // make sure repo shown, tag=<none>, digest = $digest2 284 re2 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest2.String() + `\s`) 285 c.Assert(re2.MatchString(out), checker.True, check.Commentf("expected %q: %s", re2.String(), out)) 286 287 // pull tag1 288 dockerCmd(c, "pull", repoName+":tag1") 289 290 // list images 291 out, _ = dockerCmd(c, "images", "--digests") 292 293 // make sure image 1 has repo, tag, <none> AND repo, <none>, digest 294 reWithTag1 := regexp.MustCompile(`\s*` + repoName + `\s*tag1\s*<none>\s`) 295 reWithDigest1 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest1.String() + `\s`) 296 c.Assert(reWithDigest1.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithDigest1.String(), out)) 297 c.Assert(reWithTag1.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithTag1.String(), out)) 298 // make sure image 2 has repo, <none>, digest 299 c.Assert(re2.MatchString(out), checker.True, check.Commentf("expected %q: %s", re2.String(), out)) 300 301 // pull tag 2 302 dockerCmd(c, "pull", repoName+":tag2") 303 304 // list images 305 out, _ = dockerCmd(c, "images", "--digests") 306 307 // make sure image 1 has repo, tag, digest 308 c.Assert(reWithTag1.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithTag1.String(), out)) 309 310 // make sure image 2 has repo, tag, digest 311 reWithTag2 := regexp.MustCompile(`\s*` + repoName + `\s*tag2\s*<none>\s`) 312 reWithDigest2 := regexp.MustCompile(`\s*` + repoName + `\s*<none>\s*` + digest2.String() + `\s`) 313 c.Assert(reWithTag2.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithTag2.String(), out)) 314 c.Assert(reWithDigest2.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithDigest2.String(), out)) 315 316 // list images 317 out, _ = dockerCmd(c, "images", "--digests") 318 319 // make sure image 1 has repo, tag, digest 320 c.Assert(reWithTag1.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithTag1.String(), out)) 321 // make sure image 2 has repo, tag, digest 322 c.Assert(reWithTag2.MatchString(out), checker.True, check.Commentf("expected %q: %s", reWithTag2.String(), out)) 323 // make sure busybox has tag, but not digest 324 busyboxRe := regexp.MustCompile(`\s*busybox\s*latest\s*<none>\s`) 325 c.Assert(busyboxRe.MatchString(out), checker.True, check.Commentf("expected %q: %s", busyboxRe.String(), out)) 326 } 327 328 func (s *DockerRegistrySuite) TestInspectImageWithDigests(c *check.C) { 329 digest, err := setupImage(c) 330 c.Assert(err, check.IsNil, check.Commentf("error setting up image")) 331 332 imageReference := fmt.Sprintf("%s@%s", repoName, digest) 333 334 // pull from the registry using the <name>@<digest> reference 335 dockerCmd(c, "pull", imageReference) 336 337 out, _ := dockerCmd(c, "inspect", imageReference) 338 339 var imageJSON []types.ImageInspect 340 err = json.Unmarshal([]byte(out), &imageJSON) 341 c.Assert(err, checker.IsNil) 342 c.Assert(imageJSON, checker.HasLen, 1) 343 c.Assert(imageJSON[0].RepoDigests, checker.HasLen, 1) 344 c.Assert(stringutils.InSlice(imageJSON[0].RepoDigests, imageReference), checker.Equals, true) 345 } 346 347 func (s *DockerRegistrySuite) TestPsListContainersFilterAncestorImageByDigest(c *check.C) { 348 digest, err := setupImage(c) 349 c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) 350 351 imageReference := fmt.Sprintf("%s@%s", repoName, digest) 352 353 // pull from the registry using the <name>@<digest> reference 354 dockerCmd(c, "pull", imageReference) 355 356 // build a image from it 357 imageName1 := "images_ps_filter_test" 358 _, err = buildImage(imageName1, fmt.Sprintf( 359 `FROM %s 360 LABEL match me 1`, imageReference), true) 361 c.Assert(err, checker.IsNil) 362 363 // run a container based on that 364 out, _ := dockerCmd(c, "run", "-d", imageReference, "echo", "hello") 365 expectedID := strings.TrimSpace(out) 366 367 // run a container based on the a descendant of that too 368 out, _ = dockerCmd(c, "run", "-d", imageName1, "echo", "hello") 369 expectedID1 := strings.TrimSpace(out) 370 371 expectedIDs := []string{expectedID, expectedID1} 372 373 // Invalid imageReference 374 out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", fmt.Sprintf("--filter=ancestor=busybox@%s", digest)) 375 // Filter container for ancestor filter should be empty 376 c.Assert(strings.TrimSpace(out), checker.Equals, "") 377 378 // Valid imageReference 379 out, _ = dockerCmd(c, "ps", "-a", "-q", "--no-trunc", "--filter=ancestor="+imageReference) 380 checkPsAncestorFilterOutput(c, out, imageReference, expectedIDs) 381 } 382 383 func (s *DockerRegistrySuite) TestDeleteImageByIDOnlyPulledByDigest(c *check.C) { 384 pushDigest, err := setupImage(c) 385 c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) 386 387 // pull from the registry using the <name>@<digest> reference 388 imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest) 389 dockerCmd(c, "pull", imageReference) 390 // just in case... 391 392 imageID, err := inspectField(imageReference, "Id") 393 c.Assert(err, checker.IsNil, check.Commentf("error inspecting image id")) 394 395 dockerCmd(c, "rmi", imageID) 396 } 397 398 func (s *DockerRegistrySuite) TestDeleteImageWithDigestAndTag(c *check.C) { 399 pushDigest, err := setupImage(c) 400 c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) 401 402 // pull from the registry using the <name>@<digest> reference 403 imageReference := fmt.Sprintf("%s@%s", repoName, pushDigest) 404 dockerCmd(c, "pull", imageReference) 405 406 imageID, err := inspectField(imageReference, "Id") 407 c.Assert(err, checker.IsNil, check.Commentf("error inspecting image id")) 408 409 repoTag := repoName + ":sometag" 410 repoTag2 := repoName + ":othertag" 411 dockerCmd(c, "tag", imageReference, repoTag) 412 dockerCmd(c, "tag", imageReference, repoTag2) 413 414 dockerCmd(c, "rmi", repoTag2) 415 416 // rmi should have deleted only repoTag2, because there's another tag 417 _, err = inspectField(repoTag, "Id") 418 c.Assert(err, checker.IsNil, check.Commentf("repoTag should not have been removed")) 419 420 dockerCmd(c, "rmi", repoTag) 421 422 // rmi should have deleted the tag, the digest reference, and the image itself 423 _, err = inspectField(imageID, "Id") 424 c.Assert(err, checker.NotNil, check.Commentf("image should have been deleted")) 425 } 426 427 // TestPullFailsWithAlteredManifest tests that a `docker pull` fails when 428 // we have modified a manifest blob and its digest cannot be verified. 429 // This is the schema2 version of the test. 430 func (s *DockerRegistrySuite) TestPullFailsWithAlteredManifest(c *check.C) { 431 testRequires(c, DaemonIsLinux) 432 manifestDigest, err := setupImage(c) 433 c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) 434 435 // Load the target manifest blob. 436 manifestBlob := s.reg.readBlobContents(c, manifestDigest) 437 438 var imgManifest schema2.Manifest 439 err = json.Unmarshal(manifestBlob, &imgManifest) 440 c.Assert(err, checker.IsNil, check.Commentf("unable to decode image manifest from blob")) 441 442 // Change a layer in the manifest. 443 imgManifest.Layers[0].Digest = digest.Digest("sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef") 444 445 // Move the existing data file aside, so that we can replace it with a 446 // malicious blob of data. NOTE: we defer the returned undo func. 447 undo := s.reg.tempMoveBlobData(c, manifestDigest) 448 defer undo() 449 450 alteredManifestBlob, err := json.MarshalIndent(imgManifest, "", " ") 451 c.Assert(err, checker.IsNil, check.Commentf("unable to encode altered image manifest to JSON")) 452 453 s.reg.writeBlobContents(c, manifestDigest, alteredManifestBlob) 454 455 // Now try pulling that image by digest. We should get an error about 456 // digest verification for the manifest digest. 457 458 // Pull from the registry using the <name>@<digest> reference. 459 imageReference := fmt.Sprintf("%s@%s", repoName, manifestDigest) 460 out, exitStatus, _ := dockerCmdWithError("pull", imageReference) 461 c.Assert(exitStatus, checker.Not(check.Equals), 0) 462 463 expectedErrorMsg := fmt.Sprintf("manifest verification failed for digest %s", manifestDigest) 464 c.Assert(out, checker.Contains, expectedErrorMsg) 465 } 466 467 // TestPullFailsWithAlteredManifest tests that a `docker pull` fails when 468 // we have modified a manifest blob and its digest cannot be verified. 469 // This is the schema1 version of the test. 470 func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredManifest(c *check.C) { 471 testRequires(c, DaemonIsLinux) 472 manifestDigest, err := setupImage(c) 473 c.Assert(err, checker.IsNil, check.Commentf("error setting up image")) 474 475 // Load the target manifest blob. 476 manifestBlob := s.reg.readBlobContents(c, manifestDigest) 477 478 var imgManifest schema1.Manifest 479 err = json.Unmarshal(manifestBlob, &imgManifest) 480 c.Assert(err, checker.IsNil, check.Commentf("unable to decode image manifest from blob")) 481 482 // Change a layer in the manifest. 483 imgManifest.FSLayers[0] = schema1.FSLayer{ 484 BlobSum: digest.Digest("sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), 485 } 486 487 // Move the existing data file aside, so that we can replace it with a 488 // malicious blob of data. NOTE: we defer the returned undo func. 489 undo := s.reg.tempMoveBlobData(c, manifestDigest) 490 defer undo() 491 492 alteredManifestBlob, err := json.MarshalIndent(imgManifest, "", " ") 493 c.Assert(err, checker.IsNil, check.Commentf("unable to encode altered image manifest to JSON")) 494 495 s.reg.writeBlobContents(c, manifestDigest, alteredManifestBlob) 496 497 // Now try pulling that image by digest. We should get an error about 498 // digest verification for the manifest digest. 499 500 // Pull from the registry using the <name>@<digest> reference. 501 imageReference := fmt.Sprintf("%s@%s", repoName, manifestDigest) 502 out, exitStatus, _ := dockerCmdWithError("pull", imageReference) 503 c.Assert(exitStatus, checker.Not(check.Equals), 0) 504 505 expectedErrorMsg := fmt.Sprintf("image verification failed for digest %s", manifestDigest) 506 c.Assert(out, checker.Contains, expectedErrorMsg) 507 } 508 509 // TestPullFailsWithAlteredLayer tests that a `docker pull` fails when 510 // we have modified a layer blob and its digest cannot be verified. 511 // This is the schema2 version of the test. 512 func (s *DockerRegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) { 513 testRequires(c, DaemonIsLinux) 514 manifestDigest, err := setupImage(c) 515 c.Assert(err, checker.IsNil) 516 517 // Load the target manifest blob. 518 manifestBlob := s.reg.readBlobContents(c, manifestDigest) 519 520 var imgManifest schema2.Manifest 521 err = json.Unmarshal(manifestBlob, &imgManifest) 522 c.Assert(err, checker.IsNil) 523 524 // Next, get the digest of one of the layers from the manifest. 525 targetLayerDigest := imgManifest.Layers[0].Digest 526 527 // Move the existing data file aside, so that we can replace it with a 528 // malicious blob of data. NOTE: we defer the returned undo func. 529 undo := s.reg.tempMoveBlobData(c, targetLayerDigest) 530 defer undo() 531 532 // Now make a fake data blob in this directory. 533 s.reg.writeBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for.")) 534 535 // Now try pulling that image by digest. We should get an error about 536 // digest verification for the target layer digest. 537 538 // Remove distribution cache to force a re-pull of the blobs 539 if err := os.RemoveAll(filepath.Join(dockerBasePath, "image", s.d.storageDriver, "distribution")); err != nil { 540 c.Fatalf("error clearing distribution cache: %v", err) 541 } 542 543 // Pull from the registry using the <name>@<digest> reference. 544 imageReference := fmt.Sprintf("%s@%s", repoName, manifestDigest) 545 out, exitStatus, _ := dockerCmdWithError("pull", imageReference) 546 c.Assert(exitStatus, checker.Not(check.Equals), 0, check.Commentf("expected a zero exit status")) 547 548 expectedErrorMsg := fmt.Sprintf("filesystem layer verification failed for digest %s", targetLayerDigest) 549 c.Assert(out, checker.Contains, expectedErrorMsg, check.Commentf("expected error message in output: %s", out)) 550 } 551 552 // TestPullFailsWithAlteredLayer tests that a `docker pull` fails when 553 // we have modified a layer blob and its digest cannot be verified. 554 // This is the schema1 version of the test. 555 func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) { 556 testRequires(c, DaemonIsLinux) 557 manifestDigest, err := setupImage(c) 558 c.Assert(err, checker.IsNil) 559 560 // Load the target manifest blob. 561 manifestBlob := s.reg.readBlobContents(c, manifestDigest) 562 563 var imgManifest schema1.Manifest 564 err = json.Unmarshal(manifestBlob, &imgManifest) 565 c.Assert(err, checker.IsNil) 566 567 // Next, get the digest of one of the layers from the manifest. 568 targetLayerDigest := imgManifest.FSLayers[0].BlobSum 569 570 // Move the existing data file aside, so that we can replace it with a 571 // malicious blob of data. NOTE: we defer the returned undo func. 572 undo := s.reg.tempMoveBlobData(c, targetLayerDigest) 573 defer undo() 574 575 // Now make a fake data blob in this directory. 576 s.reg.writeBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for.")) 577 578 // Now try pulling that image by digest. We should get an error about 579 // digest verification for the target layer digest. 580 581 // Remove distribution cache to force a re-pull of the blobs 582 if err := os.RemoveAll(filepath.Join(dockerBasePath, "image", s.d.storageDriver, "distribution")); err != nil { 583 c.Fatalf("error clearing distribution cache: %v", err) 584 } 585 586 // Pull from the registry using the <name>@<digest> reference. 587 imageReference := fmt.Sprintf("%s@%s", repoName, manifestDigest) 588 out, exitStatus, _ := dockerCmdWithError("pull", imageReference) 589 c.Assert(exitStatus, checker.Not(check.Equals), 0, check.Commentf("expected a zero exit status")) 590 591 expectedErrorMsg := fmt.Sprintf("filesystem layer verification failed for digest %s", targetLayerDigest) 592 c.Assert(out, checker.Contains, expectedErrorMsg, check.Commentf("expected error message in output: %s", out)) 593 }