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