github.com/AliyunContainerService/cli@v0.0.0-20181009023821-814ced4b30d0/e2e/image/push_test.go (about)

     1  package image
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/docker/cli/e2e/internal/fixtures"
    11  	"github.com/docker/cli/internal/test/environment"
    12  	"github.com/docker/cli/internal/test/output"
    13  	"gotest.tools/assert"
    14  	"gotest.tools/fs"
    15  	"gotest.tools/golden"
    16  	"gotest.tools/icmd"
    17  	"gotest.tools/skip"
    18  )
    19  
    20  const (
    21  	notary = "/usr/local/bin/notary"
    22  
    23  	pubkey1  = "./testdata/notary/delgkey1.crt"
    24  	privkey1 = "./testdata/notary/delgkey1.key"
    25  	pubkey2  = "./testdata/notary/delgkey2.crt"
    26  	privkey2 = "./testdata/notary/delgkey2.key"
    27  	pubkey3  = "./testdata/notary/delgkey3.crt"
    28  	privkey3 = "./testdata/notary/delgkey3.key"
    29  	pubkey4  = "./testdata/notary/delgkey4.crt"
    30  	privkey4 = "./testdata/notary/delgkey4.key"
    31  )
    32  
    33  func TestPushWithContentTrust(t *testing.T) {
    34  	skip.If(t, environment.RemoteDaemon())
    35  
    36  	dir := fixtures.SetupConfigFile(t)
    37  	defer dir.Remove()
    38  	image := createImage(t, registryPrefix, "trust-push", "latest")
    39  
    40  	result := icmd.RunCmd(icmd.Command("docker", "push", image),
    41  		fixtures.WithConfig(dir.Path()),
    42  		fixtures.WithTrust,
    43  		fixtures.WithNotary,
    44  		fixtures.WithPassphrase("foo", "bar"),
    45  	)
    46  	result.Assert(t, icmd.Success)
    47  	golden.Assert(t, result.Stderr(), "push-with-content-trust-err.golden")
    48  	output.Assert(t, result.Stdout(), map[int]func(string) error{
    49  		0: output.Equals("The push refers to repository [registry:5000/trust-push]"),
    50  		1: output.Equals("5bef08742407: Preparing"),
    51  		3: output.Equals("latest: digest: sha256:641b95ddb2ea9dc2af1a0113b6b348ebc20872ba615204fbe12148e98fd6f23d size: 528"),
    52  		4: output.Equals("Signing and pushing trust metadata"),
    53  		5: output.Equals(`Finished initializing "registry:5000/trust-push"`),
    54  		6: output.Equals("Successfully signed registry:5000/trust-push:latest"),
    55  	})
    56  }
    57  
    58  func TestPushWithContentTrustUnreachableServer(t *testing.T) {
    59  	skip.If(t, environment.RemoteDaemon())
    60  
    61  	dir := fixtures.SetupConfigFile(t)
    62  	defer dir.Remove()
    63  	image := createImage(t, registryPrefix, "trust-push-unreachable", "latest")
    64  
    65  	result := icmd.RunCmd(icmd.Command("docker", "push", image),
    66  		fixtures.WithConfig(dir.Path()),
    67  		fixtures.WithTrust,
    68  		fixtures.WithNotaryServer("https://invalidnotaryserver"),
    69  	)
    70  	result.Assert(t, icmd.Expected{
    71  		ExitCode: 1,
    72  		Err:      "error contacting notary server",
    73  	})
    74  }
    75  
    76  func TestPushWithContentTrustExistingTag(t *testing.T) {
    77  	skip.If(t, environment.RemoteDaemon())
    78  
    79  	dir := fixtures.SetupConfigFile(t)
    80  	defer dir.Remove()
    81  	image := createImage(t, registryPrefix, "trust-push-existing", "latest")
    82  
    83  	result := icmd.RunCmd(icmd.Command("docker", "push", image))
    84  	result.Assert(t, icmd.Success)
    85  
    86  	result = icmd.RunCmd(icmd.Command("docker", "push", image),
    87  		fixtures.WithConfig(dir.Path()),
    88  		fixtures.WithTrust,
    89  		fixtures.WithNotary,
    90  		fixtures.WithPassphrase("foo", "bar"),
    91  	)
    92  	result.Assert(t, icmd.Expected{
    93  		Out: "Signing and pushing trust metadata",
    94  	})
    95  
    96  	// Re-push
    97  	result = icmd.RunCmd(icmd.Command("docker", "push", image),
    98  		fixtures.WithConfig(dir.Path()),
    99  		fixtures.WithTrust,
   100  		fixtures.WithNotary,
   101  		fixtures.WithPassphrase("foo", "bar"),
   102  	)
   103  	result.Assert(t, icmd.Expected{
   104  		Out: "Signing and pushing trust metadata",
   105  	})
   106  }
   107  
   108  func TestPushWithContentTrustReleasesDelegationOnly(t *testing.T) {
   109  	skip.If(t, environment.RemoteDaemon())
   110  
   111  	role := "targets/releases"
   112  
   113  	dir := fixtures.SetupConfigFile(t)
   114  	defer dir.Remove()
   115  	copyPrivateKey(t, dir.Join("trust", "private"), privkey1)
   116  	notaryDir := setupNotaryConfig(t, dir)
   117  	defer notaryDir.Remove()
   118  	homeDir := fs.NewDir(t, "push_test_home")
   119  	defer notaryDir.Remove()
   120  
   121  	baseRef := fmt.Sprintf("%s/%s", registryPrefix, "trust-push-releases-delegation")
   122  	targetRef := fmt.Sprintf("%s:%s", baseRef, "latest")
   123  
   124  	// Init repository
   125  	notaryInit(t, notaryDir, homeDir, baseRef)
   126  	// Add delegation key (public key)
   127  	notaryAddDelegation(t, notaryDir, homeDir, baseRef, role, pubkey1)
   128  	// Publish it
   129  	notaryPublish(t, notaryDir, homeDir, baseRef)
   130  	// Import private key
   131  	notaryImportPrivateKey(t, notaryDir, homeDir, baseRef, role, privkey1)
   132  
   133  	// Tag & push with content trust
   134  	icmd.RunCommand("docker", "pull", fixtures.AlpineImage).Assert(t, icmd.Success)
   135  	icmd.RunCommand("docker", "tag", fixtures.AlpineImage, targetRef).Assert(t, icmd.Success)
   136  	result := icmd.RunCmd(icmd.Command("docker", "push", targetRef),
   137  		fixtures.WithConfig(dir.Path()),
   138  		fixtures.WithTrust,
   139  		fixtures.WithNotary,
   140  		fixtures.WithPassphrase("foo", "foo"),
   141  	)
   142  	result.Assert(t, icmd.Expected{
   143  		Out: "Signing and pushing trust metadata",
   144  	})
   145  
   146  	targetsInRole := notaryListTargetsInRole(t, notaryDir, homeDir, baseRef, role)
   147  	assert.Assert(t, targetsInRole["latest"] == role, "%v", targetsInRole)
   148  	targetsInRole = notaryListTargetsInRole(t, notaryDir, homeDir, baseRef, "targets")
   149  	assert.Assert(t, targetsInRole["latest"] != "targets", "%v", targetsInRole)
   150  
   151  	result = icmd.RunCmd(icmd.Command("docker", "pull", targetRef),
   152  		fixtures.WithConfig(dir.Path()),
   153  		fixtures.WithTrust,
   154  		fixtures.WithNotary,
   155  	)
   156  	result.Assert(t, icmd.Success)
   157  }
   158  
   159  func TestPushWithContentTrustSignsAllFirstLevelRolesWeHaveKeysFor(t *testing.T) {
   160  	skip.If(t, environment.RemoteDaemon())
   161  
   162  	dir := fixtures.SetupConfigFile(t)
   163  	defer dir.Remove()
   164  	copyPrivateKey(t, dir.Join("trust", "private"), privkey1)
   165  	copyPrivateKey(t, dir.Join("trust", "private"), privkey2)
   166  	copyPrivateKey(t, dir.Join("trust", "private"), privkey3)
   167  	notaryDir := setupNotaryConfig(t, dir)
   168  	defer notaryDir.Remove()
   169  	homeDir := fs.NewDir(t, "push_test_home")
   170  	defer notaryDir.Remove()
   171  
   172  	baseRef := fmt.Sprintf("%s/%s", registryPrefix, "trust-push-releases-first-roles")
   173  	targetRef := fmt.Sprintf("%s:%s", baseRef, "latest")
   174  
   175  	// Init repository
   176  	notaryInit(t, notaryDir, homeDir, baseRef)
   177  	// Add delegation key (public key)
   178  	notaryAddDelegation(t, notaryDir, homeDir, baseRef, "targets/role1", pubkey1)
   179  	notaryAddDelegation(t, notaryDir, homeDir, baseRef, "targets/role2", pubkey2)
   180  	notaryAddDelegation(t, notaryDir, homeDir, baseRef, "targets/role3", pubkey3)
   181  	notaryAddDelegation(t, notaryDir, homeDir, baseRef, "targets/role1/subrole", pubkey3)
   182  	// Import private key
   183  	notaryImportPrivateKey(t, notaryDir, homeDir, baseRef, "targets/role1", privkey1)
   184  	notaryImportPrivateKey(t, notaryDir, homeDir, baseRef, "targets/role2", privkey2)
   185  	notaryImportPrivateKey(t, notaryDir, homeDir, baseRef, "targets/role1/subrole", privkey3)
   186  	// Publish it
   187  	notaryPublish(t, notaryDir, homeDir, baseRef)
   188  
   189  	// Tag & push with content trust
   190  	icmd.RunCommand("docker", "pull", fixtures.AlpineImage).Assert(t, icmd.Success)
   191  	icmd.RunCommand("docker", "tag", fixtures.AlpineImage, targetRef).Assert(t, icmd.Success)
   192  	result := icmd.RunCmd(icmd.Command("docker", "push", targetRef),
   193  		fixtures.WithConfig(dir.Path()),
   194  		fixtures.WithTrust,
   195  		fixtures.WithNotary,
   196  		fixtures.WithPassphrase("foo", "foo"),
   197  	)
   198  	result.Assert(t, icmd.Expected{
   199  		Out: "Signing and pushing trust metadata",
   200  	})
   201  
   202  	// check to make sure that the target has been added to targets/role1 and targets/role2, and
   203  	// not targets (because there are delegations) or targets/role3 (due to missing key) or
   204  	// targets/role1/subrole (due to it being a second level delegation)
   205  	targetsInRole := notaryListTargetsInRole(t, notaryDir, homeDir, baseRef, "targets/role1")
   206  	assert.Assert(t, targetsInRole["latest"] == "targets/role1", "%v", targetsInRole)
   207  	targetsInRole = notaryListTargetsInRole(t, notaryDir, homeDir, baseRef, "targets/role2")
   208  	assert.Assert(t, targetsInRole["latest"] == "targets/role2", "%v", targetsInRole)
   209  	targetsInRole = notaryListTargetsInRole(t, notaryDir, homeDir, baseRef, "targets")
   210  	assert.Assert(t, targetsInRole["latest"] != "targets", "%v", targetsInRole)
   211  
   212  	assert.NilError(t, os.RemoveAll(filepath.Join(dir.Join("trust"))))
   213  	// Try to pull, should fail because non of these are the release role
   214  	// FIXME(vdemeester) should be unit test
   215  	result = icmd.RunCmd(icmd.Command("docker", "pull", targetRef),
   216  		fixtures.WithConfig(dir.Path()),
   217  		fixtures.WithTrust,
   218  		fixtures.WithNotary,
   219  	)
   220  	result.Assert(t, icmd.Expected{
   221  		ExitCode: 1,
   222  	})
   223  }
   224  
   225  func TestPushWithContentTrustSignsForRolesWithKeysAndValidPaths(t *testing.T) {
   226  	skip.If(t, environment.RemoteDaemon())
   227  
   228  	dir := fixtures.SetupConfigFile(t)
   229  	defer dir.Remove()
   230  	copyPrivateKey(t, dir.Join("trust", "private"), privkey1)
   231  	copyPrivateKey(t, dir.Join("trust", "private"), privkey2)
   232  	copyPrivateKey(t, dir.Join("trust", "private"), privkey3)
   233  	copyPrivateKey(t, dir.Join("trust", "private"), privkey4)
   234  	notaryDir := setupNotaryConfig(t, dir)
   235  	defer notaryDir.Remove()
   236  	homeDir := fs.NewDir(t, "push_test_home")
   237  	defer notaryDir.Remove()
   238  
   239  	baseRef := fmt.Sprintf("%s/%s", registryPrefix, "trust-push-releases-keys-valid-paths")
   240  	targetRef := fmt.Sprintf("%s:%s", baseRef, "latest")
   241  
   242  	// Init repository
   243  	notaryInit(t, notaryDir, homeDir, baseRef)
   244  	// Add delegation key (public key)
   245  	notaryAddDelegation(t, notaryDir, homeDir, baseRef, "targets/role1", pubkey1, "l", "z")
   246  	notaryAddDelegation(t, notaryDir, homeDir, baseRef, "targets/role2", pubkey2, "x", "y")
   247  	notaryAddDelegation(t, notaryDir, homeDir, baseRef, "targets/role3", pubkey3, "latest")
   248  	notaryAddDelegation(t, notaryDir, homeDir, baseRef, "targets/role4", pubkey4, "latest")
   249  	// Import private keys (except 3rd key)
   250  	notaryImportPrivateKey(t, notaryDir, homeDir, baseRef, "targets/role1", privkey1)
   251  	notaryImportPrivateKey(t, notaryDir, homeDir, baseRef, "targets/role2", privkey2)
   252  	notaryImportPrivateKey(t, notaryDir, homeDir, baseRef, "targets/role4", privkey4)
   253  	// Publish it
   254  	notaryPublish(t, notaryDir, homeDir, baseRef)
   255  
   256  	// Tag & push with content trust
   257  	icmd.RunCommand("docker", "pull", fixtures.AlpineImage).Assert(t, icmd.Success)
   258  	icmd.RunCommand("docker", "tag", fixtures.AlpineImage, targetRef).Assert(t, icmd.Success)
   259  	result := icmd.RunCmd(icmd.Command("docker", "push", targetRef),
   260  		fixtures.WithConfig(dir.Path()),
   261  		fixtures.WithTrust,
   262  		fixtures.WithNotary,
   263  		fixtures.WithPassphrase("foo", "foo"),
   264  	)
   265  	result.Assert(t, icmd.Expected{
   266  		Out: "Signing and pushing trust metadata",
   267  	})
   268  
   269  	// check to make sure that the target has been added to targets/role1 and targets/role4, and
   270  	// not targets (because there are delegations) or targets/role2 (due to path restrictions) or
   271  	// targets/role3 (due to missing key)
   272  	targetsInRole := notaryListTargetsInRole(t, notaryDir, homeDir, baseRef, "targets/role1")
   273  	assert.Assert(t, targetsInRole["latest"] == "targets/role1", "%v", targetsInRole)
   274  	targetsInRole = notaryListTargetsInRole(t, notaryDir, homeDir, baseRef, "targets/role4")
   275  	assert.Assert(t, targetsInRole["latest"] == "targets/role4", "%v", targetsInRole)
   276  	targetsInRole = notaryListTargetsInRole(t, notaryDir, homeDir, baseRef, "targets")
   277  	assert.Assert(t, targetsInRole["latest"] != "targets", "%v", targetsInRole)
   278  
   279  	assert.NilError(t, os.RemoveAll(filepath.Join(dir.Join("trust"))))
   280  	// Try to pull, should fail because non of these are the release role
   281  	// FIXME(vdemeester) should be unit test
   282  	result = icmd.RunCmd(icmd.Command("docker", "pull", targetRef),
   283  		fixtures.WithConfig(dir.Path()),
   284  		fixtures.WithTrust,
   285  		fixtures.WithNotary,
   286  	)
   287  	result.Assert(t, icmd.Expected{
   288  		ExitCode: 1,
   289  	})
   290  }
   291  
   292  func createImage(t *testing.T, registryPrefix, repo, tag string) string {
   293  	image := fmt.Sprintf("%s/%s:%s", registryPrefix, repo, tag)
   294  	icmd.RunCommand("docker", "pull", fixtures.AlpineImage).Assert(t, icmd.Success)
   295  	icmd.RunCommand("docker", "tag", fixtures.AlpineImage, image).Assert(t, icmd.Success)
   296  	return image
   297  }
   298  
   299  func withNotaryPassphrase(pwd string) func(*icmd.Cmd) {
   300  	return func(c *icmd.Cmd) {
   301  		c.Env = append(c.Env, []string{
   302  			fmt.Sprintf("NOTARY_ROOT_PASSPHRASE=%s", pwd),
   303  			fmt.Sprintf("NOTARY_TARGETS_PASSPHRASE=%s", pwd),
   304  			fmt.Sprintf("NOTARY_SNAPSHOT_PASSPHRASE=%s", pwd),
   305  			fmt.Sprintf("NOTARY_DELEGATION_PASSPHRASE=%s", pwd),
   306  		}...)
   307  	}
   308  }
   309  
   310  func notaryImportPrivateKey(t *testing.T, notaryDir, homeDir *fs.Dir, baseRef, role, privkey string) {
   311  	icmd.RunCmd(
   312  		icmd.Command(notary, "-c", notaryDir.Join("client-config.json"), "key", "import", privkey, "-g", baseRef, "-r", role),
   313  		withNotaryPassphrase("foo"),
   314  		fixtures.WithHome(homeDir.Path()),
   315  	).Assert(t, icmd.Success)
   316  }
   317  
   318  func notaryPublish(t *testing.T, notaryDir, homeDir *fs.Dir, baseRef string) {
   319  	icmd.RunCmd(
   320  		icmd.Command(notary, "-c", notaryDir.Join("client-config.json"), "publish", baseRef),
   321  		withNotaryPassphrase("foo"),
   322  		fixtures.WithHome(homeDir.Path()),
   323  	).Assert(t, icmd.Success)
   324  }
   325  
   326  func notaryAddDelegation(t *testing.T, notaryDir, homeDir *fs.Dir, baseRef, role, pubkey string, paths ...string) {
   327  	pathsArg := "--all-paths"
   328  	if len(paths) > 0 {
   329  		pathsArg = "--paths=" + strings.Join(paths, ",")
   330  	}
   331  	icmd.RunCmd(
   332  		icmd.Command(notary, "-c", notaryDir.Join("client-config.json"), "delegation", "add", baseRef, role, pubkey, pathsArg),
   333  		withNotaryPassphrase("foo"),
   334  		fixtures.WithHome(homeDir.Path()),
   335  	).Assert(t, icmd.Success)
   336  }
   337  
   338  func notaryInit(t *testing.T, notaryDir, homeDir *fs.Dir, baseRef string) {
   339  	icmd.RunCmd(
   340  		icmd.Command(notary, "-c", notaryDir.Join("client-config.json"), "init", baseRef),
   341  		withNotaryPassphrase("foo"),
   342  		fixtures.WithHome(homeDir.Path()),
   343  	).Assert(t, icmd.Success)
   344  }
   345  
   346  func notaryListTargetsInRole(t *testing.T, notaryDir, homeDir *fs.Dir, baseRef, role string) map[string]string {
   347  	result := icmd.RunCmd(
   348  		icmd.Command(notary, "-c", notaryDir.Join("client-config.json"), "list", baseRef, "-r", role),
   349  		fixtures.WithHome(homeDir.Path()),
   350  	)
   351  	out := result.Combined()
   352  
   353  	// should look something like:
   354  	//    NAME                                 DIGEST                                SIZE (BYTES)    ROLE
   355  	// ------------------------------------------------------------------------------------------------------
   356  	//   latest   24a36bbc059b1345b7e8be0df20f1b23caa3602e85d42fff7ecd9d0bd255de56   1377           targets
   357  
   358  	targets := make(map[string]string)
   359  
   360  	// no target
   361  	lines := strings.Split(strings.TrimSpace(out), "\n")
   362  	if len(lines) == 1 && strings.Contains(out, "No targets present in this repository.") {
   363  		return targets
   364  	}
   365  
   366  	// otherwise, there is at least one target
   367  	assert.Assert(t, len(lines) >= 3, "output is %s", out)
   368  
   369  	for _, line := range lines[2:] {
   370  		tokens := strings.Fields(line)
   371  		assert.Assert(t, len(tokens) == 4)
   372  		targets[tokens[0]] = tokens[3]
   373  	}
   374  
   375  	return targets
   376  }
   377  
   378  func setupNotaryConfig(t *testing.T, dockerConfigDir fs.Dir) *fs.Dir {
   379  	return fs.NewDir(t, "notary_test", fs.WithMode(0700),
   380  		fs.WithFile("client-config.json", fmt.Sprintf(`
   381  {
   382  	"trust_dir": "%s",
   383  	"remote_server": {
   384  		"url": "%s"
   385  	}
   386  }`, dockerConfigDir.Join("trust"), fixtures.NotaryURL)),
   387  	)
   388  }
   389  
   390  func copyPrivateKey(t *testing.T, dir, source string) {
   391  	icmd.RunCommand("/bin/cp", source, dir).Assert(t, icmd.Success)
   392  }