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