github.com/uriddle/docker@v0.0.0-20210926094723-4072e6aeb013/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  }