Browse code

Pull, Pull-A, and Build will only pull tags from the targets role or the targets/releases role. It will ignore tags in all other delegation roles.

Signed-off-by: cyli <cyli@twistedmatrix.com>

cyli authored on 2016/03/17 11:59:18
Showing 5 changed files
... ...
@@ -259,6 +259,11 @@ func (cli *DockerCli) trustedReference(ref reference.NamedTagged) (reference.Can
259 259
 	if err != nil {
260 260
 		return nil, err
261 261
 	}
262
+	// Only list tags in the top level targets role or the releases delegation role - ignore
263
+	// all other delegation roles
264
+	if t.Role != releasesRole && t.Role != data.CanonicalTargetsRole {
265
+		return nil, notaryError(repoInfo.FullName(), fmt.Errorf("No trust data for %s", ref.Tag()))
266
+	}
262 267
 	r, err := convertTarget(t.Target)
263 268
 	if err != nil {
264 269
 		return nil, err
... ...
@@ -332,13 +337,27 @@ func (cli *DockerCli) trustedPull(repoInfo *registry.RepositoryInfo, ref registr
332 332
 				fmt.Fprintf(cli.out, "Skipping target for %q\n", repoInfo.Name())
333 333
 				continue
334 334
 			}
335
+			// Only list tags in the top level targets role or the releases delegation role - ignore
336
+			// all other delegation roles
337
+			if tgt.Role != releasesRole && tgt.Role != data.CanonicalTargetsRole {
338
+				continue
339
+			}
335 340
 			refs = append(refs, t)
336 341
 		}
342
+		if len(refs) == 0 {
343
+			return notaryError(repoInfo.FullName(), fmt.Errorf("No trusted tags for %s", repoInfo.FullName()))
344
+		}
337 345
 	} else {
338 346
 		t, err := notaryRepo.GetTargetByName(ref.String(), releasesRole, data.CanonicalTargetsRole)
339 347
 		if err != nil {
340 348
 			return notaryError(repoInfo.FullName(), err)
341 349
 		}
350
+		// Only get the tag if it's in the top level targets role or the releases delegation role
351
+		// ignore it if it's in any other delegation roles
352
+		if t.Role != releasesRole && t.Role != data.CanonicalTargetsRole {
353
+			return notaryError(repoInfo.FullName(), fmt.Errorf("No trust data for %s", ref.String()))
354
+		}
355
+
342 356
 		logrus.Debugf("retrieving target for %s role\n", t.Role)
343 357
 		r, err := convertTarget(t.Target)
344 358
 		if err != nil {
... ...
@@ -496,9 +515,9 @@ func (cli *DockerCli) addTargetToAllSignableRoles(repo *client.NotaryRepository,
496 496
 	var signableRoles []string
497 497
 
498 498
 	// translate the full key names, which includes the GUN, into just the key IDs
499
-	allCanonicalKeyIDs := make(map[string]string)
499
+	allCanonicalKeyIDs := make(map[string]struct{})
500 500
 	for fullKeyID := range repo.CryptoService.ListAllKeys() {
501
-		allCanonicalKeyIDs[path.Base(fullKeyID)] = ""
501
+		allCanonicalKeyIDs[path.Base(fullKeyID)] = struct{}{}
502 502
 	}
503 503
 
504 504
 	allDelegationRoles, err := repo.GetDelegationRoles()
... ...
@@ -506,6 +525,13 @@ func (cli *DockerCli) addTargetToAllSignableRoles(repo *client.NotaryRepository,
506 506
 		return err
507 507
 	}
508 508
 
509
+	// if there are no delegation roles, then just try to sign it into the targets role
510
+	if len(allDelegationRoles) == 0 {
511
+		return repo.AddTarget(target, data.CanonicalTargetsRole)
512
+	}
513
+
514
+	// there are delegation roles, find every delegation role we have a key for, and
515
+	// attempt to sign into into all those roles.
509 516
 	for _, delegationRole := range allDelegationRoles {
510 517
 		// We do not support signing any delegation role that isn't a direct child of the targets role.
511 518
 		// Also don't bother checking the keys if we can't add the target
... ...
@@ -517,11 +543,12 @@ func (cli *DockerCli) addTargetToAllSignableRoles(repo *client.NotaryRepository,
517 517
 		for _, canonicalKeyID := range delegationRole.KeyIDs {
518 518
 			if _, ok := allCanonicalKeyIDs[canonicalKeyID]; ok {
519 519
 				signableRoles = append(signableRoles, delegationRole.Name)
520
+				break
520 521
 			}
521 522
 		}
522 523
 	}
523 524
 
524
-	if len(allDelegationRoles) > 0 && len(signableRoles) == 0 {
525
+	if len(signableRoles) == 0 {
525 526
 		return fmt.Errorf("no valid signing keys for delegation roles")
526 527
 	}
527 528
 
... ...
@@ -5799,6 +5799,83 @@ func (s *DockerTrustSuite) TestBuildContextDirIsSymlink(c *check.C) {
5799 5799
 	}
5800 5800
 }
5801 5801
 
5802
+func (s *DockerTrustSuite) TestTrustedBuildTagFromReleasesRole(c *check.C) {
5803
+	testRequires(c, NotaryHosting)
5804
+
5805
+	latestTag := s.setupTrustedImage(c, "trusted-build-releases-role")
5806
+	repoName := strings.TrimSuffix(latestTag, ":latest")
5807
+
5808
+	// Now create the releases role
5809
+	s.notaryCreateDelegation(c, repoName, "targets/releases", s.not.keys[0].Public)
5810
+	s.notaryImportKey(c, repoName, "targets/releases", s.not.keys[0].Private)
5811
+	s.notaryPublish(c, repoName)
5812
+
5813
+	// push a different tag to the releases role
5814
+	otherTag := fmt.Sprintf("%s:other", repoName)
5815
+	dockerCmd(c, "tag", "busybox", otherTag)
5816
+
5817
+	pushCmd := exec.Command(dockerBinary, "push", otherTag)
5818
+	s.trustedCmd(pushCmd)
5819
+	out, _, err := runCommandWithOutput(pushCmd)
5820
+	c.Assert(err, check.IsNil, check.Commentf("Trusted push failed: %s", out))
5821
+	s.assertTargetInRoles(c, repoName, "other", "targets/releases")
5822
+	s.assertTargetNotInRoles(c, repoName, "other", "targets")
5823
+
5824
+	out, status := dockerCmd(c, "rmi", otherTag)
5825
+	c.Assert(status, check.Equals, 0, check.Commentf("docker rmi failed: %s", out))
5826
+
5827
+	dockerFile := fmt.Sprintf(`
5828
+  FROM %s
5829
+  RUN []
5830
+    `, otherTag)
5831
+
5832
+	name := "testtrustedbuildreleasesrole"
5833
+
5834
+	buildCmd := buildImageCmd(name, dockerFile, true)
5835
+	s.trustedCmd(buildCmd)
5836
+	out, _, err = runCommandWithOutput(buildCmd)
5837
+	c.Assert(err, check.IsNil, check.Commentf("Trusted build failed: %s", out))
5838
+	c.Assert(out, checker.Contains, fmt.Sprintf("FROM %s@sha", repoName))
5839
+}
5840
+
5841
+func (s *DockerTrustSuite) TestTrustedBuildTagIgnoresOtherDelegationRoles(c *check.C) {
5842
+	testRequires(c, NotaryHosting)
5843
+
5844
+	latestTag := s.setupTrustedImage(c, "trusted-build-releases-role")
5845
+	repoName := strings.TrimSuffix(latestTag, ":latest")
5846
+
5847
+	// Now create a non-releases delegation role
5848
+	s.notaryCreateDelegation(c, repoName, "targets/other", s.not.keys[0].Public)
5849
+	s.notaryImportKey(c, repoName, "targets/other", s.not.keys[0].Private)
5850
+	s.notaryPublish(c, repoName)
5851
+
5852
+	// push a different tag to the other role
5853
+	otherTag := fmt.Sprintf("%s:other", repoName)
5854
+	dockerCmd(c, "tag", "busybox", otherTag)
5855
+
5856
+	pushCmd := exec.Command(dockerBinary, "push", otherTag)
5857
+	s.trustedCmd(pushCmd)
5858
+	out, _, err := runCommandWithOutput(pushCmd)
5859
+	c.Assert(err, check.IsNil, check.Commentf("Trusted push failed: %s", out))
5860
+	s.assertTargetInRoles(c, repoName, "other", "targets/other")
5861
+	s.assertTargetNotInRoles(c, repoName, "other", "targets")
5862
+
5863
+	out, status := dockerCmd(c, "rmi", otherTag)
5864
+	c.Assert(status, check.Equals, 0, check.Commentf("docker rmi failed: %s", out))
5865
+
5866
+	dockerFile := fmt.Sprintf(`
5867
+  FROM %s
5868
+  RUN []
5869
+    `, otherTag)
5870
+
5871
+	name := "testtrustedbuildotherrole"
5872
+
5873
+	buildCmd := buildImageCmd(name, dockerFile, true)
5874
+	s.trustedCmd(buildCmd)
5875
+	out, _, err = runCommandWithOutput(buildCmd)
5876
+	c.Assert(err, check.NotNil, check.Commentf("Trusted build expected to fail: %s", out))
5877
+}
5878
+
5802 5879
 // Issue #15634: COPY fails when path starts with "null"
5803 5880
 func (s *DockerSuite) TestBuildNullStringInAddCopyVolume(c *check.C) {
5804 5881
 	name := "testbuildnullstringinaddcopyvolume"
... ...
@@ -256,16 +256,17 @@ func (s *DockerTrustSuite) TestTrustedPullDelete(c *check.C) {
256 256
 }
257 257
 
258 258
 func (s *DockerTrustSuite) TestTrustedPullReadsFromReleasesRole(c *check.C) {
259
+	testRequires(c, NotaryHosting)
259 260
 	repoName := fmt.Sprintf("%v/dockerclireleasesdelegationpulling/trusted", privateRegistryURL)
260 261
 	targetName := fmt.Sprintf("%s:latest", repoName)
261
-	pwd := "12345678"
262 262
 
263 263
 	// Push with targets first, initializing the repo
264 264
 	dockerCmd(c, "tag", "busybox", targetName)
265 265
 	pushCmd := exec.Command(dockerBinary, "push", targetName)
266
-	s.trustedCmdWithPassphrases(pushCmd, pwd, pwd)
266
+	s.trustedCmd(pushCmd)
267 267
 	out, _, err := runCommandWithOutput(pushCmd)
268 268
 	c.Assert(err, check.IsNil, check.Commentf(out))
269
+	s.assertTargetInRoles(c, repoName, "latest", "targets")
269 270
 
270 271
 	// Try pull, check we retrieve from targets role
271 272
 	pullCmd := exec.Command(dockerBinary, "-D", "pull", repoName)
... ...
@@ -275,15 +276,31 @@ func (s *DockerTrustSuite) TestTrustedPullReadsFromReleasesRole(c *check.C) {
275 275
 	c.Assert(out, checker.Contains, "retrieving target for targets role")
276 276
 
277 277
 	// Now we'll create the releases role, and try pushing and pulling
278
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/releases", s.not.keys[0].Public)
278
+	s.notaryCreateDelegation(c, repoName, "targets/releases", s.not.keys[0].Public)
279 279
 	s.notaryImportKey(c, repoName, "targets/releases", s.not.keys[0].Private)
280
-	s.notaryPublish(c, repoName, pwd)
280
+	s.notaryPublish(c, repoName)
281
+
282
+	// try a pull, check that we can still pull because we can still read the
283
+	// old tag in the targets role
284
+	pullCmd = exec.Command(dockerBinary, "-D", "pull", repoName)
285
+	s.trustedCmd(pullCmd)
286
+	out, _, err = runCommandWithOutput(pullCmd)
287
+	c.Assert(err, check.IsNil, check.Commentf(out))
288
+	c.Assert(out, checker.Contains, "retrieving target for targets role")
289
+
290
+	// try a pull -a, check that it succeeds because we can still pull from the
291
+	// targets role
292
+	pullCmd = exec.Command(dockerBinary, "-D", "pull", "-a", repoName)
293
+	s.trustedCmd(pullCmd)
294
+	out, _, err = runCommandWithOutput(pullCmd)
295
+	c.Assert(err, check.IsNil, check.Commentf(out))
281 296
 
282 297
 	// Push, should sign with targets/releases
283 298
 	dockerCmd(c, "tag", "busybox", targetName)
284 299
 	pushCmd = exec.Command(dockerBinary, "push", targetName)
285
-	s.trustedCmdWithPassphrases(pushCmd, pwd, pwd)
300
+	s.trustedCmd(pushCmd)
286 301
 	out, _, err = runCommandWithOutput(pushCmd)
302
+	s.assertTargetInRoles(c, repoName, "latest", "targets", "targets/releases")
287 303
 
288 304
 	// Try pull, check we retrieve from targets/releases role
289 305
 	pullCmd = exec.Command(dockerBinary, "-D", "pull", repoName)
... ...
@@ -292,14 +309,15 @@ func (s *DockerTrustSuite) TestTrustedPullReadsFromReleasesRole(c *check.C) {
292 292
 	c.Assert(out, checker.Contains, "retrieving target for targets/releases role")
293 293
 
294 294
 	// Create another delegation that we'll sign with
295
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/other", s.not.keys[1].Public)
295
+	s.notaryCreateDelegation(c, repoName, "targets/other", s.not.keys[1].Public)
296 296
 	s.notaryImportKey(c, repoName, "targets/other", s.not.keys[1].Private)
297
-	s.notaryPublish(c, repoName, pwd)
297
+	s.notaryPublish(c, repoName)
298 298
 
299 299
 	dockerCmd(c, "tag", "busybox", targetName)
300 300
 	pushCmd = exec.Command(dockerBinary, "push", targetName)
301
-	s.trustedCmdWithPassphrases(pushCmd, pwd, pwd)
301
+	s.trustedCmd(pushCmd)
302 302
 	out, _, err = runCommandWithOutput(pushCmd)
303
+	s.assertTargetInRoles(c, repoName, "latest", "targets", "targets/releases", "targets/other")
303 304
 
304 305
 	// Try pull, check we retrieve from targets/releases role
305 306
 	pullCmd = exec.Command(dockerBinary, "-D", "pull", repoName)
... ...
@@ -307,3 +325,41 @@ func (s *DockerTrustSuite) TestTrustedPullReadsFromReleasesRole(c *check.C) {
307 307
 	out, _, err = runCommandWithOutput(pullCmd)
308 308
 	c.Assert(out, checker.Contains, "retrieving target for targets/releases role")
309 309
 }
310
+
311
+func (s *DockerTrustSuite) TestTrustedPullIgnoresOtherDelegationRoles(c *check.C) {
312
+	testRequires(c, NotaryHosting)
313
+	repoName := fmt.Sprintf("%v/dockerclipullotherdelegation/trusted", privateRegistryURL)
314
+	targetName := fmt.Sprintf("%s:latest", repoName)
315
+
316
+	// We'll create a repo first with a non-release delegation role, so that when we
317
+	// push we'll sign it into the delegation role
318
+	s.notaryInitRepo(c, repoName)
319
+	s.notaryCreateDelegation(c, repoName, "targets/other", s.not.keys[0].Public)
320
+	s.notaryImportKey(c, repoName, "targets/other", s.not.keys[0].Private)
321
+	s.notaryPublish(c, repoName)
322
+
323
+	// Push should write to the delegation role, not targets
324
+	dockerCmd(c, "tag", "busybox", targetName)
325
+	pushCmd := exec.Command(dockerBinary, "push", targetName)
326
+	s.trustedCmd(pushCmd)
327
+	out, _, err := runCommandWithOutput(pushCmd)
328
+	c.Assert(err, check.IsNil, check.Commentf(out))
329
+	s.assertTargetInRoles(c, repoName, "latest", "targets/other")
330
+	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
331
+
332
+	// Try pull - we should fail, since pull will only pull from the targets/releases
333
+	// role or the targets role
334
+	pullCmd := exec.Command(dockerBinary, "-D", "pull", repoName)
335
+	s.trustedCmd(pullCmd)
336
+	out, _, err = runCommandWithOutput(pullCmd)
337
+	c.Assert(err, check.NotNil, check.Commentf(out))
338
+	c.Assert(out, checker.Contains, "No trust data for")
339
+
340
+	// try a pull -a: we should fail since pull will only pull from the targets/releases
341
+	// role or the targets role
342
+	pullCmd = exec.Command(dockerBinary, "-D", "pull", "-a", repoName)
343
+	s.trustedCmd(pullCmd)
344
+	out, _, err = runCommandWithOutput(pullCmd)
345
+	c.Assert(err, check.NotNil, check.Commentf(out))
346
+	c.Assert(out, checker.Contains, "No trusted tags for")
347
+}
... ...
@@ -501,10 +501,9 @@ func (s *DockerTrustSuite) TestTrustedPushWithReleasesDelegationOnly(c *check.C)
501 501
 	testRequires(c, NotaryHosting)
502 502
 	repoName := fmt.Sprintf("%v/dockerclireleasedelegationinitfirst/trusted", privateRegistryURL)
503 503
 	targetName := fmt.Sprintf("%s:latest", repoName)
504
-	pwd := "12345678"
505
-	s.notaryInitRepo(c, repoName, pwd)
506
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/releases", s.not.keys[0].Public)
507
-	s.notaryPublish(c, repoName, pwd)
504
+	s.notaryInitRepo(c, repoName)
505
+	s.notaryCreateDelegation(c, repoName, "targets/releases", s.not.keys[0].Public)
506
+	s.notaryPublish(c, repoName)
508 507
 
509 508
 	s.notaryImportKey(c, repoName, "targets/releases", s.not.keys[0].Private)
510 509
 
... ...
@@ -512,10 +511,13 @@ func (s *DockerTrustSuite) TestTrustedPushWithReleasesDelegationOnly(c *check.C)
512 512
 	dockerCmd(c, "tag", "busybox", targetName)
513 513
 
514 514
 	pushCmd := exec.Command(dockerBinary, "push", targetName)
515
-	s.trustedCmdWithPassphrases(pushCmd, pwd, pwd)
515
+	s.trustedCmd(pushCmd)
516 516
 	out, _, err := runCommandWithOutput(pushCmd)
517 517
 	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
518 518
 	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
519
+	// check to make sure that the target has been added to targets/releases and not targets
520
+	s.assertTargetInRoles(c, repoName, "latest", "targets/releases")
521
+	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
519 522
 
520 523
 	// Try pull after push
521 524
 	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
... ...
@@ -525,103 +527,99 @@ func (s *DockerTrustSuite) TestTrustedPushWithReleasesDelegationOnly(c *check.C)
525 525
 	out, _, err = runCommandWithOutput(pullCmd)
526 526
 	c.Assert(err, check.IsNil, check.Commentf(out))
527 527
 	c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf(out))
528
-
529
-	// check to make sure that the target has been added to targets/releases and not targets
530
-	s.assertTargetInDelegationRoles(c, repoName, "latest", "targets/releases")
531 528
 }
532 529
 
533 530
 func (s *DockerTrustSuite) TestTrustedPushSignsAllFirstLevelRolesWeHaveKeysFor(c *check.C) {
534 531
 	testRequires(c, NotaryHosting)
535 532
 	repoName := fmt.Sprintf("%v/dockerclimanyroles/trusted", privateRegistryURL)
536 533
 	targetName := fmt.Sprintf("%s:latest", repoName)
537
-	pwd := "12345678"
538
-	s.notaryInitRepo(c, repoName, pwd)
539
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/role1", s.not.keys[0].Public)
540
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/role2", s.not.keys[1].Public)
541
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/role3", s.not.keys[2].Public)
534
+	s.notaryInitRepo(c, repoName)
535
+	s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public)
536
+	s.notaryCreateDelegation(c, repoName, "targets/role2", s.not.keys[1].Public)
537
+	s.notaryCreateDelegation(c, repoName, "targets/role3", s.not.keys[2].Public)
542 538
 
543 539
 	// import everything except the third key
544 540
 	s.notaryImportKey(c, repoName, "targets/role1", s.not.keys[0].Private)
545 541
 	s.notaryImportKey(c, repoName, "targets/role2", s.not.keys[1].Private)
546 542
 
547
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/role1/subrole", s.not.keys[3].Public)
543
+	s.notaryCreateDelegation(c, repoName, "targets/role1/subrole", s.not.keys[3].Public)
548 544
 	s.notaryImportKey(c, repoName, "targets/role1/subrole", s.not.keys[3].Private)
549 545
 
550
-	s.notaryPublish(c, repoName, pwd)
546
+	s.notaryPublish(c, repoName)
551 547
 
552 548
 	// tag the image and upload it to the private registry
553 549
 	dockerCmd(c, "tag", "busybox", targetName)
554 550
 
555 551
 	pushCmd := exec.Command(dockerBinary, "push", targetName)
556
-	s.trustedCmdWithPassphrases(pushCmd, pwd, pwd)
552
+	s.trustedCmd(pushCmd)
557 553
 	out, _, err := runCommandWithOutput(pushCmd)
558 554
 	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
559 555
 	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
560 556
 
557
+	// check to make sure that the target has been added to targets/role1 and targets/role2, and
558
+	// not targets (because there are delegations) or targets/role3 (due to missing key) or
559
+	// targets/role1/subrole (due to it being a second level delegation)
560
+	s.assertTargetInRoles(c, repoName, "latest", "targets/role1", "targets/role2")
561
+	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
562
+
561 563
 	// Try pull after push
562 564
 	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
563 565
 
566
+	// pull should fail because none of these are the releases role
564 567
 	pullCmd := exec.Command(dockerBinary, "pull", targetName)
565 568
 	s.trustedCmd(pullCmd)
566 569
 	out, _, err = runCommandWithOutput(pullCmd)
567
-	c.Assert(err, check.IsNil, check.Commentf(out))
568
-	c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf(out))
569
-
570
-	// check to make sure that the target has been added to targets/role1 and targets/role2, and
571
-	// not targets (because there are delegations) or targets/role3 (due to missing key) or
572
-	// targets/role1/subrole (due to it being a second level delegation)
573
-	s.assertTargetInDelegationRoles(c, repoName, "latest", "targets/role1", "targets/role2")
570
+	c.Assert(err, check.NotNil, check.Commentf(out))
574 571
 }
575 572
 
576 573
 func (s *DockerTrustSuite) TestTrustedPushSignsForRolesWithKeysAndValidPaths(c *check.C) {
577 574
 	repoName := fmt.Sprintf("%v/dockerclirolesbykeysandpaths/trusted", privateRegistryURL)
578 575
 	targetName := fmt.Sprintf("%s:latest", repoName)
579
-	pwd := "12345678"
580
-	s.notaryInitRepo(c, repoName, pwd)
581
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/role1", s.not.keys[0].Public, "l", "z")
582
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/role2", s.not.keys[1].Public, "x", "y")
583
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/role3", s.not.keys[2].Public, "latest")
584
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/role4", s.not.keys[3].Public, "latest")
576
+	s.notaryInitRepo(c, repoName)
577
+	s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public, "l", "z")
578
+	s.notaryCreateDelegation(c, repoName, "targets/role2", s.not.keys[1].Public, "x", "y")
579
+	s.notaryCreateDelegation(c, repoName, "targets/role3", s.not.keys[2].Public, "latest")
580
+	s.notaryCreateDelegation(c, repoName, "targets/role4", s.not.keys[3].Public, "latest")
585 581
 
586 582
 	// import everything except the third key
587 583
 	s.notaryImportKey(c, repoName, "targets/role1", s.not.keys[0].Private)
588 584
 	s.notaryImportKey(c, repoName, "targets/role2", s.not.keys[1].Private)
589 585
 	s.notaryImportKey(c, repoName, "targets/role4", s.not.keys[3].Private)
590 586
 
591
-	s.notaryPublish(c, repoName, pwd)
587
+	s.notaryPublish(c, repoName)
592 588
 
593 589
 	// tag the image and upload it to the private registry
594 590
 	dockerCmd(c, "tag", "busybox", targetName)
595 591
 
596 592
 	pushCmd := exec.Command(dockerBinary, "push", targetName)
597
-	s.trustedCmdWithPassphrases(pushCmd, pwd, pwd)
593
+	s.trustedCmd(pushCmd)
598 594
 	out, _, err := runCommandWithOutput(pushCmd)
599 595
 	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
600 596
 	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
601 597
 
598
+	// check to make sure that the target has been added to targets/role1 and targets/role4, and
599
+	// not targets (because there are delegations) or targets/role2 (due to path restrictions) or
600
+	// targets/role3 (due to missing key)
601
+	s.assertTargetInRoles(c, repoName, "latest", "targets/role1", "targets/role4")
602
+	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
603
+
602 604
 	// Try pull after push
603 605
 	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
604 606
 
607
+	// pull should fail because none of these are the releases role
605 608
 	pullCmd := exec.Command(dockerBinary, "pull", targetName)
606 609
 	s.trustedCmd(pullCmd)
607 610
 	out, _, err = runCommandWithOutput(pullCmd)
608
-	c.Assert(err, check.IsNil, check.Commentf(out))
609
-	c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf(out))
610
-
611
-	// check to make sure that the target has been added to targets/role1 and targets/role4, and
612
-	// not targets (because there are delegations) or targets/role2 (due to path restrictions) or
613
-	// targets/role3 (due to missing key)
614
-	s.assertTargetInDelegationRoles(c, repoName, "latest", "targets/role1", "targets/role4")
611
+	c.Assert(err, check.NotNil, check.Commentf(out))
615 612
 }
616 613
 
617 614
 func (s *DockerTrustSuite) TestTrustedPushDoesntSignTargetsIfDelegationsExist(c *check.C) {
618 615
 	testRequires(c, NotaryHosting)
619 616
 	repoName := fmt.Sprintf("%v/dockerclireleasedelegationnotsignable/trusted", privateRegistryURL)
620 617
 	targetName := fmt.Sprintf("%s:latest", repoName)
621
-	pwd := "12345678"
622
-	s.notaryInitRepo(c, repoName, pwd)
623
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/role1", s.not.keys[0].Public)
624
-	s.notaryPublish(c, repoName, pwd)
618
+	s.notaryInitRepo(c, repoName)
619
+	s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public)
620
+	s.notaryPublish(c, repoName)
625 621
 
626 622
 	// do not import any delegations key
627 623
 
... ...
@@ -629,11 +627,13 @@ func (s *DockerTrustSuite) TestTrustedPushDoesntSignTargetsIfDelegationsExist(c
629 629
 	dockerCmd(c, "tag", "busybox", targetName)
630 630
 
631 631
 	pushCmd := exec.Command(dockerBinary, "push", targetName)
632
-	s.trustedCmdWithPassphrases(pushCmd, pwd, pwd)
632
+	s.trustedCmd(pushCmd)
633 633
 	out, _, err := runCommandWithOutput(pushCmd)
634
-	c.Assert(err, check.Not(check.IsNil), check.Commentf("trusted push succeeded but should have failed:\n%s", out))
634
+	c.Assert(err, check.NotNil, check.Commentf("trusted push succeeded but should have failed:\n%s", out))
635 635
 	c.Assert(out, checker.Contains, "no valid signing keys",
636 636
 		check.Commentf("Missing expected output on trusted push without keys"))
637
+
638
+	s.assertTargetNotInRoles(c, repoName, "latest", "targets", "targets/role1")
637 639
 }
638 640
 
639 641
 func (s *DockerRegistryAuthHtpasswdSuite) TestPushNoCredentialsNoRetry(c *check.C) {
... ...
@@ -211,6 +211,7 @@ func (s *DockerTrustSuite) setupTrustedImage(c *check.C, name string) string {
211 211
 	pushCmd := exec.Command(dockerBinary, "push", repoName)
212 212
 	s.trustedCmd(pushCmd)
213 213
 	out, _, err := runCommandWithOutput(pushCmd)
214
+
214 215
 	if err != nil {
215 216
 		c.Fatalf("Error running trusted push: %s\n%s", err, out)
216 217
 	}
... ...
@@ -225,25 +226,26 @@ func (s *DockerTrustSuite) setupTrustedImage(c *check.C, name string) string {
225 225
 	return repoName
226 226
 }
227 227
 
228
-func notaryClientEnv(cmd *exec.Cmd, rootPwd, repositoryPwd string) {
228
+func notaryClientEnv(cmd *exec.Cmd) {
229
+	pwd := "12345678"
229 230
 	env := []string{
230
-		fmt.Sprintf("NOTARY_ROOT_PASSPHRASE=%s", rootPwd),
231
-		fmt.Sprintf("NOTARY_TARGETS_PASSPHRASE=%s", repositoryPwd),
232
-		fmt.Sprintf("NOTARY_SNAPSHOT_PASSPHRASE=%s", repositoryPwd),
231
+		fmt.Sprintf("NOTARY_ROOT_PASSPHRASE=%s", pwd),
232
+		fmt.Sprintf("NOTARY_TARGETS_PASSPHRASE=%s", pwd),
233
+		fmt.Sprintf("NOTARY_SNAPSHOT_PASSPHRASE=%s", pwd),
233 234
 	}
234 235
 	cmd.Env = append(os.Environ(), env...)
235 236
 }
236 237
 
237
-func (s *DockerTrustSuite) notaryInitRepo(c *check.C, repoName, pwd string) {
238
+func (s *DockerTrustSuite) notaryInitRepo(c *check.C, repoName string) {
238 239
 	initCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "init", repoName)
239
-	notaryClientEnv(initCmd, pwd, pwd)
240
+	notaryClientEnv(initCmd)
240 241
 	out, _, err := runCommandWithOutput(initCmd)
241 242
 	if err != nil {
242 243
 		c.Fatalf("Error initializing notary repository: %s\n", out)
243 244
 	}
244 245
 }
245 246
 
246
-func (s *DockerTrustSuite) notaryCreateDelegation(c *check.C, repoName, pwd, role string, pubKey string, paths ...string) {
247
+func (s *DockerTrustSuite) notaryCreateDelegation(c *check.C, repoName, role string, pubKey string, paths ...string) {
247 248
 	pathsArg := "--all-paths"
248 249
 	if len(paths) > 0 {
249 250
 		pathsArg = "--paths=" + strings.Join(paths, ",")
... ...
@@ -251,16 +253,16 @@ func (s *DockerTrustSuite) notaryCreateDelegation(c *check.C, repoName, pwd, rol
251 251
 
252 252
 	delgCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"),
253 253
 		"delegation", "add", repoName, role, pubKey, pathsArg)
254
-	notaryClientEnv(delgCmd, pwd, pwd)
254
+	notaryClientEnv(delgCmd)
255 255
 	out, _, err := runCommandWithOutput(delgCmd)
256 256
 	if err != nil {
257 257
 		c.Fatalf("Error adding %s role to notary repository: %s\n", role, out)
258 258
 	}
259 259
 }
260 260
 
261
-func (s *DockerTrustSuite) notaryPublish(c *check.C, repoName, pwd string) {
261
+func (s *DockerTrustSuite) notaryPublish(c *check.C, repoName string) {
262 262
 	pubCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "publish", repoName)
263
-	notaryClientEnv(pubCmd, pwd, pwd)
263
+	notaryClientEnv(pubCmd)
264 264
 	out, _, err := runCommandWithOutput(pubCmd)
265 265
 	if err != nil {
266 266
 		c.Fatalf("Error publishing notary repository: %s\n", out)
... ...
@@ -270,20 +272,20 @@ func (s *DockerTrustSuite) notaryPublish(c *check.C, repoName, pwd string) {
270 270
 func (s *DockerTrustSuite) notaryImportKey(c *check.C, repoName, role string, privKey string) {
271 271
 	impCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "key",
272 272
 		"import", privKey, "-g", repoName, "-r", role)
273
-	notaryClientEnv(impCmd, "", "")
273
+	notaryClientEnv(impCmd)
274 274
 	out, _, err := runCommandWithOutput(impCmd)
275 275
 	if err != nil {
276 276
 		c.Fatalf("Error importing key to notary repository: %s\n", out)
277 277
 	}
278 278
 }
279 279
 
280
-func (s *DockerTrustSuite) notaryListTargetsInRoles(c *check.C, repoName, role string) map[string]string {
280
+func (s *DockerTrustSuite) notaryListTargetsInRole(c *check.C, repoName, role string) map[string]string {
281 281
 	listCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "list",
282 282
 		repoName, "-r", role)
283
-	notaryClientEnv(listCmd, "", "")
283
+	notaryClientEnv(listCmd)
284 284
 	out, _, err := runCommandWithOutput(listCmd)
285 285
 	if err != nil {
286
-		c.Fatalf("Error importing key to notary repository: %s\n", out)
286
+		c.Fatalf("Error listing targets in notary repository: %s\n", out)
287 287
 	}
288 288
 
289 289
 	// should look something like:
... ...
@@ -291,9 +293,16 @@ func (s *DockerTrustSuite) notaryListTargetsInRoles(c *check.C, repoName, role s
291 291
 	// ------------------------------------------------------------------------------------------------------
292 292
 	//   latest   24a36bbc059b1345b7e8be0df20f1b23caa3602e85d42fff7ecd9d0bd255de56   1377           targets
293 293
 
294
+	targets := make(map[string]string)
295
+
296
+	// no target
294 297
 	lines := strings.Split(strings.TrimSpace(out), "\n")
298
+	if len(lines) == 1 && strings.Contains(out, "No targets present in this repository.") {
299
+		return targets
300
+	}
301
+
302
+	// otherwise, there is at least one target
295 303
 	c.Assert(len(lines), checker.GreaterOrEqualThan, 3)
296
-	targets := make(map[string]string)
297 304
 
298 305
 	for _, line := range lines[2:] {
299 306
 		tokens := strings.Fields(line)
... ...
@@ -304,18 +313,23 @@ func (s *DockerTrustSuite) notaryListTargetsInRoles(c *check.C, repoName, role s
304 304
 	return targets
305 305
 }
306 306
 
307
-func (s *DockerTrustSuite) assertTargetInDelegationRoles(c *check.C, repoName, target string, roles ...string) {
308
-	// assert it's not in the target role
309
-	targets := s.notaryListTargetsInRoles(c, repoName, "targets")
310
-	roleName, ok := targets[target]
311
-	c.Assert(ok, checker.True)
312
-	c.Assert(roleName, checker.Not(checker.Equals), "targets")
313
-
307
+func (s *DockerTrustSuite) assertTargetInRoles(c *check.C, repoName, target string, roles ...string) {
314 308
 	// check all the roles
315 309
 	for _, role := range roles {
316
-		targets := s.notaryListTargetsInRoles(c, repoName, role)
310
+		targets := s.notaryListTargetsInRole(c, repoName, role)
317 311
 		roleName, ok := targets[target]
318 312
 		c.Assert(ok, checker.True)
319 313
 		c.Assert(roleName, checker.Equals, role)
320 314
 	}
321 315
 }
316
+
317
+func (s *DockerTrustSuite) assertTargetNotInRoles(c *check.C, repoName, target string, roles ...string) {
318
+	targets := s.notaryListTargetsInRole(c, repoName, "targets")
319
+
320
+	roleName, ok := targets[target]
321
+	if ok {
322
+		for _, role := range roles {
323
+			c.Assert(roleName, checker.Not(checker.Equals), role)
324
+		}
325
+	}
326
+}