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