Pārlūkot izejas kodu

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 9 gadi atpakaļ
vecāks
revīzija
623ccc2f31

+ 30 - 3
api/client/trust.go

@@ -259,6 +259,11 @@ func (cli *DockerCli) trustedReference(ref reference.NamedTagged) (reference.Can
 	if err != nil {
 		return nil, err
 	}
+	// Only list tags in the top level targets role or the releases delegation role - ignore
+	// all other delegation roles
+	if t.Role != releasesRole && t.Role != data.CanonicalTargetsRole {
+		return nil, notaryError(repoInfo.FullName(), fmt.Errorf("No trust data for %s", ref.Tag()))
+	}
 	r, err := convertTarget(t.Target)
 	if err != nil {
 		return nil, err
@@ -332,13 +337,27 @@ func (cli *DockerCli) trustedPull(repoInfo *registry.RepositoryInfo, ref registr
 				fmt.Fprintf(cli.out, "Skipping target for %q\n", repoInfo.Name())
 				continue
 			}
+			// Only list tags in the top level targets role or the releases delegation role - ignore
+			// all other delegation roles
+			if tgt.Role != releasesRole && tgt.Role != data.CanonicalTargetsRole {
+				continue
+			}
 			refs = append(refs, t)
 		}
+		if len(refs) == 0 {
+			return notaryError(repoInfo.FullName(), fmt.Errorf("No trusted tags for %s", repoInfo.FullName()))
+		}
 	} else {
 		t, err := notaryRepo.GetTargetByName(ref.String(), releasesRole, data.CanonicalTargetsRole)
 		if err != nil {
 			return notaryError(repoInfo.FullName(), err)
 		}
+		// Only get the tag if it's in the top level targets role or the releases delegation role
+		// ignore it if it's in any other delegation roles
+		if t.Role != releasesRole && t.Role != data.CanonicalTargetsRole {
+			return notaryError(repoInfo.FullName(), fmt.Errorf("No trust data for %s", ref.String()))
+		}
+
 		logrus.Debugf("retrieving target for %s role\n", t.Role)
 		r, err := convertTarget(t.Target)
 		if err != nil {
@@ -496,9 +515,9 @@ func (cli *DockerCli) addTargetToAllSignableRoles(repo *client.NotaryRepository,
 	var signableRoles []string
 
 	// translate the full key names, which includes the GUN, into just the key IDs
-	allCanonicalKeyIDs := make(map[string]string)
+	allCanonicalKeyIDs := make(map[string]struct{})
 	for fullKeyID := range repo.CryptoService.ListAllKeys() {
-		allCanonicalKeyIDs[path.Base(fullKeyID)] = ""
+		allCanonicalKeyIDs[path.Base(fullKeyID)] = struct{}{}
 	}
 
 	allDelegationRoles, err := repo.GetDelegationRoles()
@@ -506,6 +525,13 @@ func (cli *DockerCli) addTargetToAllSignableRoles(repo *client.NotaryRepository,
 		return err
 	}
 
+	// if there are no delegation roles, then just try to sign it into the targets role
+	if len(allDelegationRoles) == 0 {
+		return repo.AddTarget(target, data.CanonicalTargetsRole)
+	}
+
+	// there are delegation roles, find every delegation role we have a key for, and
+	// attempt to sign into into all those roles.
 	for _, delegationRole := range allDelegationRoles {
 		// We do not support signing any delegation role that isn't a direct child of the targets role.
 		// 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,
 		for _, canonicalKeyID := range delegationRole.KeyIDs {
 			if _, ok := allCanonicalKeyIDs[canonicalKeyID]; ok {
 				signableRoles = append(signableRoles, delegationRole.Name)
+				break
 			}
 		}
 	}
 
-	if len(allDelegationRoles) > 0 && len(signableRoles) == 0 {
+	if len(signableRoles) == 0 {
 		return fmt.Errorf("no valid signing keys for delegation roles")
 	}
 

+ 77 - 0
integration-cli/docker_cli_build_test.go

@@ -5799,6 +5799,83 @@ func (s *DockerTrustSuite) TestBuildContextDirIsSymlink(c *check.C) {
 	}
 }
 
+func (s *DockerTrustSuite) TestTrustedBuildTagFromReleasesRole(c *check.C) {
+	testRequires(c, NotaryHosting)
+
+	latestTag := s.setupTrustedImage(c, "trusted-build-releases-role")
+	repoName := strings.TrimSuffix(latestTag, ":latest")
+
+	// Now create the releases role
+	s.notaryCreateDelegation(c, repoName, "targets/releases", s.not.keys[0].Public)
+	s.notaryImportKey(c, repoName, "targets/releases", s.not.keys[0].Private)
+	s.notaryPublish(c, repoName)
+
+	// push a different tag to the releases role
+	otherTag := fmt.Sprintf("%s:other", repoName)
+	dockerCmd(c, "tag", "busybox", otherTag)
+
+	pushCmd := exec.Command(dockerBinary, "push", otherTag)
+	s.trustedCmd(pushCmd)
+	out, _, err := runCommandWithOutput(pushCmd)
+	c.Assert(err, check.IsNil, check.Commentf("Trusted push failed: %s", out))
+	s.assertTargetInRoles(c, repoName, "other", "targets/releases")
+	s.assertTargetNotInRoles(c, repoName, "other", "targets")
+
+	out, status := dockerCmd(c, "rmi", otherTag)
+	c.Assert(status, check.Equals, 0, check.Commentf("docker rmi failed: %s", out))
+
+	dockerFile := fmt.Sprintf(`
+  FROM %s
+  RUN []
+    `, otherTag)
+
+	name := "testtrustedbuildreleasesrole"
+
+	buildCmd := buildImageCmd(name, dockerFile, true)
+	s.trustedCmd(buildCmd)
+	out, _, err = runCommandWithOutput(buildCmd)
+	c.Assert(err, check.IsNil, check.Commentf("Trusted build failed: %s", out))
+	c.Assert(out, checker.Contains, fmt.Sprintf("FROM %s@sha", repoName))
+}
+
+func (s *DockerTrustSuite) TestTrustedBuildTagIgnoresOtherDelegationRoles(c *check.C) {
+	testRequires(c, NotaryHosting)
+
+	latestTag := s.setupTrustedImage(c, "trusted-build-releases-role")
+	repoName := strings.TrimSuffix(latestTag, ":latest")
+
+	// Now create a non-releases delegation role
+	s.notaryCreateDelegation(c, repoName, "targets/other", s.not.keys[0].Public)
+	s.notaryImportKey(c, repoName, "targets/other", s.not.keys[0].Private)
+	s.notaryPublish(c, repoName)
+
+	// push a different tag to the other role
+	otherTag := fmt.Sprintf("%s:other", repoName)
+	dockerCmd(c, "tag", "busybox", otherTag)
+
+	pushCmd := exec.Command(dockerBinary, "push", otherTag)
+	s.trustedCmd(pushCmd)
+	out, _, err := runCommandWithOutput(pushCmd)
+	c.Assert(err, check.IsNil, check.Commentf("Trusted push failed: %s", out))
+	s.assertTargetInRoles(c, repoName, "other", "targets/other")
+	s.assertTargetNotInRoles(c, repoName, "other", "targets")
+
+	out, status := dockerCmd(c, "rmi", otherTag)
+	c.Assert(status, check.Equals, 0, check.Commentf("docker rmi failed: %s", out))
+
+	dockerFile := fmt.Sprintf(`
+  FROM %s
+  RUN []
+    `, otherTag)
+
+	name := "testtrustedbuildotherrole"
+
+	buildCmd := buildImageCmd(name, dockerFile, true)
+	s.trustedCmd(buildCmd)
+	out, _, err = runCommandWithOutput(buildCmd)
+	c.Assert(err, check.NotNil, check.Commentf("Trusted build expected to fail: %s", out))
+}
+
 // Issue #15634: COPY fails when path starts with "null"
 func (s *DockerSuite) TestBuildNullStringInAddCopyVolume(c *check.C) {
 	name := "testbuildnullstringinaddcopyvolume"

+ 64 - 8
integration-cli/docker_cli_pull_trusted_test.go

@@ -256,16 +256,17 @@ func (s *DockerTrustSuite) TestTrustedPullDelete(c *check.C) {
 }
 
 func (s *DockerTrustSuite) TestTrustedPullReadsFromReleasesRole(c *check.C) {
+	testRequires(c, NotaryHosting)
 	repoName := fmt.Sprintf("%v/dockerclireleasesdelegationpulling/trusted", privateRegistryURL)
 	targetName := fmt.Sprintf("%s:latest", repoName)
-	pwd := "12345678"
 
 	// Push with targets first, initializing the repo
 	dockerCmd(c, "tag", "busybox", targetName)
 	pushCmd := exec.Command(dockerBinary, "push", targetName)
-	s.trustedCmdWithPassphrases(pushCmd, pwd, pwd)
+	s.trustedCmd(pushCmd)
 	out, _, err := runCommandWithOutput(pushCmd)
 	c.Assert(err, check.IsNil, check.Commentf(out))
+	s.assertTargetInRoles(c, repoName, "latest", "targets")
 
 	// Try pull, check we retrieve from targets role
 	pullCmd := exec.Command(dockerBinary, "-D", "pull", repoName)
@@ -275,15 +276,31 @@ func (s *DockerTrustSuite) TestTrustedPullReadsFromReleasesRole(c *check.C) {
 	c.Assert(out, checker.Contains, "retrieving target for targets role")
 
 	// Now we'll create the releases role, and try pushing and pulling
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/releases", s.not.keys[0].Public)
+	s.notaryCreateDelegation(c, repoName, "targets/releases", s.not.keys[0].Public)
 	s.notaryImportKey(c, repoName, "targets/releases", s.not.keys[0].Private)
-	s.notaryPublish(c, repoName, pwd)
+	s.notaryPublish(c, repoName)
+
+	// try a pull, check that we can still pull because we can still read the
+	// old tag in the targets role
+	pullCmd = exec.Command(dockerBinary, "-D", "pull", repoName)
+	s.trustedCmd(pullCmd)
+	out, _, err = runCommandWithOutput(pullCmd)
+	c.Assert(err, check.IsNil, check.Commentf(out))
+	c.Assert(out, checker.Contains, "retrieving target for targets role")
+
+	// try a pull -a, check that it succeeds because we can still pull from the
+	// targets role
+	pullCmd = exec.Command(dockerBinary, "-D", "pull", "-a", repoName)
+	s.trustedCmd(pullCmd)
+	out, _, err = runCommandWithOutput(pullCmd)
+	c.Assert(err, check.IsNil, check.Commentf(out))
 
 	// Push, should sign with targets/releases
 	dockerCmd(c, "tag", "busybox", targetName)
 	pushCmd = exec.Command(dockerBinary, "push", targetName)
-	s.trustedCmdWithPassphrases(pushCmd, pwd, pwd)
+	s.trustedCmd(pushCmd)
 	out, _, err = runCommandWithOutput(pushCmd)
+	s.assertTargetInRoles(c, repoName, "latest", "targets", "targets/releases")
 
 	// Try pull, check we retrieve from targets/releases role
 	pullCmd = exec.Command(dockerBinary, "-D", "pull", repoName)
@@ -292,14 +309,15 @@ func (s *DockerTrustSuite) TestTrustedPullReadsFromReleasesRole(c *check.C) {
 	c.Assert(out, checker.Contains, "retrieving target for targets/releases role")
 
 	// Create another delegation that we'll sign with
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/other", s.not.keys[1].Public)
+	s.notaryCreateDelegation(c, repoName, "targets/other", s.not.keys[1].Public)
 	s.notaryImportKey(c, repoName, "targets/other", s.not.keys[1].Private)
-	s.notaryPublish(c, repoName, pwd)
+	s.notaryPublish(c, repoName)
 
 	dockerCmd(c, "tag", "busybox", targetName)
 	pushCmd = exec.Command(dockerBinary, "push", targetName)
-	s.trustedCmdWithPassphrases(pushCmd, pwd, pwd)
+	s.trustedCmd(pushCmd)
 	out, _, err = runCommandWithOutput(pushCmd)
+	s.assertTargetInRoles(c, repoName, "latest", "targets", "targets/releases", "targets/other")
 
 	// Try pull, check we retrieve from targets/releases role
 	pullCmd = exec.Command(dockerBinary, "-D", "pull", repoName)
@@ -307,3 +325,41 @@ func (s *DockerTrustSuite) TestTrustedPullReadsFromReleasesRole(c *check.C) {
 	out, _, err = runCommandWithOutput(pullCmd)
 	c.Assert(out, checker.Contains, "retrieving target for targets/releases role")
 }
+
+func (s *DockerTrustSuite) TestTrustedPullIgnoresOtherDelegationRoles(c *check.C) {
+	testRequires(c, NotaryHosting)
+	repoName := fmt.Sprintf("%v/dockerclipullotherdelegation/trusted", privateRegistryURL)
+	targetName := fmt.Sprintf("%s:latest", repoName)
+
+	// We'll create a repo first with a non-release delegation role, so that when we
+	// push we'll sign it into the delegation role
+	s.notaryInitRepo(c, repoName)
+	s.notaryCreateDelegation(c, repoName, "targets/other", s.not.keys[0].Public)
+	s.notaryImportKey(c, repoName, "targets/other", s.not.keys[0].Private)
+	s.notaryPublish(c, repoName)
+
+	// Push should write to the delegation role, not targets
+	dockerCmd(c, "tag", "busybox", targetName)
+	pushCmd := exec.Command(dockerBinary, "push", targetName)
+	s.trustedCmd(pushCmd)
+	out, _, err := runCommandWithOutput(pushCmd)
+	c.Assert(err, check.IsNil, check.Commentf(out))
+	s.assertTargetInRoles(c, repoName, "latest", "targets/other")
+	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
+
+	// Try pull - we should fail, since pull will only pull from the targets/releases
+	// role or the targets role
+	pullCmd := exec.Command(dockerBinary, "-D", "pull", repoName)
+	s.trustedCmd(pullCmd)
+	out, _, err = runCommandWithOutput(pullCmd)
+	c.Assert(err, check.NotNil, check.Commentf(out))
+	c.Assert(out, checker.Contains, "No trust data for")
+
+	// try a pull -a: we should fail since pull will only pull from the targets/releases
+	// role or the targets role
+	pullCmd = exec.Command(dockerBinary, "-D", "pull", "-a", repoName)
+	s.trustedCmd(pullCmd)
+	out, _, err = runCommandWithOutput(pullCmd)
+	c.Assert(err, check.NotNil, check.Commentf(out))
+	c.Assert(out, checker.Contains, "No trusted tags for")
+}

+ 44 - 44
integration-cli/docker_cli_push_test.go

@@ -501,10 +501,9 @@ func (s *DockerTrustSuite) TestTrustedPushWithReleasesDelegationOnly(c *check.C)
 	testRequires(c, NotaryHosting)
 	repoName := fmt.Sprintf("%v/dockerclireleasedelegationinitfirst/trusted", privateRegistryURL)
 	targetName := fmt.Sprintf("%s:latest", repoName)
-	pwd := "12345678"
-	s.notaryInitRepo(c, repoName, pwd)
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/releases", s.not.keys[0].Public)
-	s.notaryPublish(c, repoName, pwd)
+	s.notaryInitRepo(c, repoName)
+	s.notaryCreateDelegation(c, repoName, "targets/releases", s.not.keys[0].Public)
+	s.notaryPublish(c, repoName)
 
 	s.notaryImportKey(c, repoName, "targets/releases", s.not.keys[0].Private)
 
@@ -512,10 +511,13 @@ func (s *DockerTrustSuite) TestTrustedPushWithReleasesDelegationOnly(c *check.C)
 	dockerCmd(c, "tag", "busybox", targetName)
 
 	pushCmd := exec.Command(dockerBinary, "push", targetName)
-	s.trustedCmdWithPassphrases(pushCmd, pwd, pwd)
+	s.trustedCmd(pushCmd)
 	out, _, err := runCommandWithOutput(pushCmd)
 	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
 	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
+	// check to make sure that the target has been added to targets/releases and not targets
+	s.assertTargetInRoles(c, repoName, "latest", "targets/releases")
+	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
 
 	// Try pull after push
 	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
@@ -525,103 +527,99 @@ func (s *DockerTrustSuite) TestTrustedPushWithReleasesDelegationOnly(c *check.C)
 	out, _, err = runCommandWithOutput(pullCmd)
 	c.Assert(err, check.IsNil, check.Commentf(out))
 	c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf(out))
-
-	// check to make sure that the target has been added to targets/releases and not targets
-	s.assertTargetInDelegationRoles(c, repoName, "latest", "targets/releases")
 }
 
 func (s *DockerTrustSuite) TestTrustedPushSignsAllFirstLevelRolesWeHaveKeysFor(c *check.C) {
 	testRequires(c, NotaryHosting)
 	repoName := fmt.Sprintf("%v/dockerclimanyroles/trusted", privateRegistryURL)
 	targetName := fmt.Sprintf("%s:latest", repoName)
-	pwd := "12345678"
-	s.notaryInitRepo(c, repoName, pwd)
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/role1", s.not.keys[0].Public)
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/role2", s.not.keys[1].Public)
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/role3", s.not.keys[2].Public)
+	s.notaryInitRepo(c, repoName)
+	s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public)
+	s.notaryCreateDelegation(c, repoName, "targets/role2", s.not.keys[1].Public)
+	s.notaryCreateDelegation(c, repoName, "targets/role3", s.not.keys[2].Public)
 
 	// import everything except the third key
 	s.notaryImportKey(c, repoName, "targets/role1", s.not.keys[0].Private)
 	s.notaryImportKey(c, repoName, "targets/role2", s.not.keys[1].Private)
 
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/role1/subrole", s.not.keys[3].Public)
+	s.notaryCreateDelegation(c, repoName, "targets/role1/subrole", s.not.keys[3].Public)
 	s.notaryImportKey(c, repoName, "targets/role1/subrole", s.not.keys[3].Private)
 
-	s.notaryPublish(c, repoName, pwd)
+	s.notaryPublish(c, repoName)
 
 	// tag the image and upload it to the private registry
 	dockerCmd(c, "tag", "busybox", targetName)
 
 	pushCmd := exec.Command(dockerBinary, "push", targetName)
-	s.trustedCmdWithPassphrases(pushCmd, pwd, pwd)
+	s.trustedCmd(pushCmd)
 	out, _, err := runCommandWithOutput(pushCmd)
 	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
 	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
 
+	// check to make sure that the target has been added to targets/role1 and targets/role2, and
+	// not targets (because there are delegations) or targets/role3 (due to missing key) or
+	// targets/role1/subrole (due to it being a second level delegation)
+	s.assertTargetInRoles(c, repoName, "latest", "targets/role1", "targets/role2")
+	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
+
 	// Try pull after push
 	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
 
+	// pull should fail because none of these are the releases role
 	pullCmd := exec.Command(dockerBinary, "pull", targetName)
 	s.trustedCmd(pullCmd)
 	out, _, err = runCommandWithOutput(pullCmd)
-	c.Assert(err, check.IsNil, check.Commentf(out))
-	c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf(out))
-
-	// check to make sure that the target has been added to targets/role1 and targets/role2, and
-	// not targets (because there are delegations) or targets/role3 (due to missing key) or
-	// targets/role1/subrole (due to it being a second level delegation)
-	s.assertTargetInDelegationRoles(c, repoName, "latest", "targets/role1", "targets/role2")
+	c.Assert(err, check.NotNil, check.Commentf(out))
 }
 
 func (s *DockerTrustSuite) TestTrustedPushSignsForRolesWithKeysAndValidPaths(c *check.C) {
 	repoName := fmt.Sprintf("%v/dockerclirolesbykeysandpaths/trusted", privateRegistryURL)
 	targetName := fmt.Sprintf("%s:latest", repoName)
-	pwd := "12345678"
-	s.notaryInitRepo(c, repoName, pwd)
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/role1", s.not.keys[0].Public, "l", "z")
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/role2", s.not.keys[1].Public, "x", "y")
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/role3", s.not.keys[2].Public, "latest")
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/role4", s.not.keys[3].Public, "latest")
+	s.notaryInitRepo(c, repoName)
+	s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public, "l", "z")
+	s.notaryCreateDelegation(c, repoName, "targets/role2", s.not.keys[1].Public, "x", "y")
+	s.notaryCreateDelegation(c, repoName, "targets/role3", s.not.keys[2].Public, "latest")
+	s.notaryCreateDelegation(c, repoName, "targets/role4", s.not.keys[3].Public, "latest")
 
 	// import everything except the third key
 	s.notaryImportKey(c, repoName, "targets/role1", s.not.keys[0].Private)
 	s.notaryImportKey(c, repoName, "targets/role2", s.not.keys[1].Private)
 	s.notaryImportKey(c, repoName, "targets/role4", s.not.keys[3].Private)
 
-	s.notaryPublish(c, repoName, pwd)
+	s.notaryPublish(c, repoName)
 
 	// tag the image and upload it to the private registry
 	dockerCmd(c, "tag", "busybox", targetName)
 
 	pushCmd := exec.Command(dockerBinary, "push", targetName)
-	s.trustedCmdWithPassphrases(pushCmd, pwd, pwd)
+	s.trustedCmd(pushCmd)
 	out, _, err := runCommandWithOutput(pushCmd)
 	c.Assert(err, check.IsNil, check.Commentf("trusted push failed: %s\n%s", err, out))
 	c.Assert(out, checker.Contains, "Signing and pushing trust metadata", check.Commentf("Missing expected output on trusted push with existing tag"))
 
+	// check to make sure that the target has been added to targets/role1 and targets/role4, and
+	// not targets (because there are delegations) or targets/role2 (due to path restrictions) or
+	// targets/role3 (due to missing key)
+	s.assertTargetInRoles(c, repoName, "latest", "targets/role1", "targets/role4")
+	s.assertTargetNotInRoles(c, repoName, "latest", "targets")
+
 	// Try pull after push
 	os.RemoveAll(filepath.Join(cliconfig.ConfigDir(), "trust"))
 
+	// pull should fail because none of these are the releases role
 	pullCmd := exec.Command(dockerBinary, "pull", targetName)
 	s.trustedCmd(pullCmd)
 	out, _, err = runCommandWithOutput(pullCmd)
-	c.Assert(err, check.IsNil, check.Commentf(out))
-	c.Assert(string(out), checker.Contains, "Status: Downloaded", check.Commentf(out))
-
-	// check to make sure that the target has been added to targets/role1 and targets/role4, and
-	// not targets (because there are delegations) or targets/role2 (due to path restrictions) or
-	// targets/role3 (due to missing key)
-	s.assertTargetInDelegationRoles(c, repoName, "latest", "targets/role1", "targets/role4")
+	c.Assert(err, check.NotNil, check.Commentf(out))
 }
 
 func (s *DockerTrustSuite) TestTrustedPushDoesntSignTargetsIfDelegationsExist(c *check.C) {
 	testRequires(c, NotaryHosting)
 	repoName := fmt.Sprintf("%v/dockerclireleasedelegationnotsignable/trusted", privateRegistryURL)
 	targetName := fmt.Sprintf("%s:latest", repoName)
-	pwd := "12345678"
-	s.notaryInitRepo(c, repoName, pwd)
-	s.notaryCreateDelegation(c, repoName, pwd, "targets/role1", s.not.keys[0].Public)
-	s.notaryPublish(c, repoName, pwd)
+	s.notaryInitRepo(c, repoName)
+	s.notaryCreateDelegation(c, repoName, "targets/role1", s.not.keys[0].Public)
+	s.notaryPublish(c, repoName)
 
 	// do not import any delegations key
 
@@ -629,11 +627,13 @@ func (s *DockerTrustSuite) TestTrustedPushDoesntSignTargetsIfDelegationsExist(c
 	dockerCmd(c, "tag", "busybox", targetName)
 
 	pushCmd := exec.Command(dockerBinary, "push", targetName)
-	s.trustedCmdWithPassphrases(pushCmd, pwd, pwd)
+	s.trustedCmd(pushCmd)
 	out, _, err := runCommandWithOutput(pushCmd)
-	c.Assert(err, check.Not(check.IsNil), check.Commentf("trusted push succeeded but should have failed:\n%s", out))
+	c.Assert(err, check.NotNil, check.Commentf("trusted push succeeded but should have failed:\n%s", out))
 	c.Assert(out, checker.Contains, "no valid signing keys",
 		check.Commentf("Missing expected output on trusted push without keys"))
+
+	s.assertTargetNotInRoles(c, repoName, "latest", "targets", "targets/role1")
 }
 
 func (s *DockerRegistryAuthHtpasswdSuite) TestPushNoCredentialsNoRetry(c *check.C) {

+ 37 - 23
integration-cli/trust_server.go

@@ -211,6 +211,7 @@ func (s *DockerTrustSuite) setupTrustedImage(c *check.C, name string) string {
 	pushCmd := exec.Command(dockerBinary, "push", repoName)
 	s.trustedCmd(pushCmd)
 	out, _, err := runCommandWithOutput(pushCmd)
+
 	if err != nil {
 		c.Fatalf("Error running trusted push: %s\n%s", err, out)
 	}
@@ -225,25 +226,26 @@ func (s *DockerTrustSuite) setupTrustedImage(c *check.C, name string) string {
 	return repoName
 }
 
-func notaryClientEnv(cmd *exec.Cmd, rootPwd, repositoryPwd string) {
+func notaryClientEnv(cmd *exec.Cmd) {
+	pwd := "12345678"
 	env := []string{
-		fmt.Sprintf("NOTARY_ROOT_PASSPHRASE=%s", rootPwd),
-		fmt.Sprintf("NOTARY_TARGETS_PASSPHRASE=%s", repositoryPwd),
-		fmt.Sprintf("NOTARY_SNAPSHOT_PASSPHRASE=%s", repositoryPwd),
+		fmt.Sprintf("NOTARY_ROOT_PASSPHRASE=%s", pwd),
+		fmt.Sprintf("NOTARY_TARGETS_PASSPHRASE=%s", pwd),
+		fmt.Sprintf("NOTARY_SNAPSHOT_PASSPHRASE=%s", pwd),
 	}
 	cmd.Env = append(os.Environ(), env...)
 }
 
-func (s *DockerTrustSuite) notaryInitRepo(c *check.C, repoName, pwd string) {
+func (s *DockerTrustSuite) notaryInitRepo(c *check.C, repoName string) {
 	initCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "init", repoName)
-	notaryClientEnv(initCmd, pwd, pwd)
+	notaryClientEnv(initCmd)
 	out, _, err := runCommandWithOutput(initCmd)
 	if err != nil {
 		c.Fatalf("Error initializing notary repository: %s\n", out)
 	}
 }
 
-func (s *DockerTrustSuite) notaryCreateDelegation(c *check.C, repoName, pwd, role string, pubKey string, paths ...string) {
+func (s *DockerTrustSuite) notaryCreateDelegation(c *check.C, repoName, role string, pubKey string, paths ...string) {
 	pathsArg := "--all-paths"
 	if len(paths) > 0 {
 		pathsArg = "--paths=" + strings.Join(paths, ",")
@@ -251,16 +253,16 @@ func (s *DockerTrustSuite) notaryCreateDelegation(c *check.C, repoName, pwd, rol
 
 	delgCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"),
 		"delegation", "add", repoName, role, pubKey, pathsArg)
-	notaryClientEnv(delgCmd, pwd, pwd)
+	notaryClientEnv(delgCmd)
 	out, _, err := runCommandWithOutput(delgCmd)
 	if err != nil {
 		c.Fatalf("Error adding %s role to notary repository: %s\n", role, out)
 	}
 }
 
-func (s *DockerTrustSuite) notaryPublish(c *check.C, repoName, pwd string) {
+func (s *DockerTrustSuite) notaryPublish(c *check.C, repoName string) {
 	pubCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "publish", repoName)
-	notaryClientEnv(pubCmd, pwd, pwd)
+	notaryClientEnv(pubCmd)
 	out, _, err := runCommandWithOutput(pubCmd)
 	if err != nil {
 		c.Fatalf("Error publishing notary repository: %s\n", out)
@@ -270,20 +272,20 @@ func (s *DockerTrustSuite) notaryPublish(c *check.C, repoName, pwd string) {
 func (s *DockerTrustSuite) notaryImportKey(c *check.C, repoName, role string, privKey string) {
 	impCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "key",
 		"import", privKey, "-g", repoName, "-r", role)
-	notaryClientEnv(impCmd, "", "")
+	notaryClientEnv(impCmd)
 	out, _, err := runCommandWithOutput(impCmd)
 	if err != nil {
 		c.Fatalf("Error importing key to notary repository: %s\n", out)
 	}
 }
 
-func (s *DockerTrustSuite) notaryListTargetsInRoles(c *check.C, repoName, role string) map[string]string {
+func (s *DockerTrustSuite) notaryListTargetsInRole(c *check.C, repoName, role string) map[string]string {
 	listCmd := exec.Command(notaryBinary, "-c", filepath.Join(s.not.dir, "client-config.json"), "list",
 		repoName, "-r", role)
-	notaryClientEnv(listCmd, "", "")
+	notaryClientEnv(listCmd)
 	out, _, err := runCommandWithOutput(listCmd)
 	if err != nil {
-		c.Fatalf("Error importing key to notary repository: %s\n", out)
+		c.Fatalf("Error listing targets in notary repository: %s\n", out)
 	}
 
 	// should look something like:
@@ -291,9 +293,16 @@ func (s *DockerTrustSuite) notaryListTargetsInRoles(c *check.C, repoName, role s
 	// ------------------------------------------------------------------------------------------------------
 	//   latest   24a36bbc059b1345b7e8be0df20f1b23caa3602e85d42fff7ecd9d0bd255de56   1377           targets
 
+	targets := make(map[string]string)
+
+	// no target
 	lines := strings.Split(strings.TrimSpace(out), "\n")
+	if len(lines) == 1 && strings.Contains(out, "No targets present in this repository.") {
+		return targets
+	}
+
+	// otherwise, there is at least one target
 	c.Assert(len(lines), checker.GreaterOrEqualThan, 3)
-	targets := make(map[string]string)
 
 	for _, line := range lines[2:] {
 		tokens := strings.Fields(line)
@@ -304,18 +313,23 @@ func (s *DockerTrustSuite) notaryListTargetsInRoles(c *check.C, repoName, role s
 	return targets
 }
 
-func (s *DockerTrustSuite) assertTargetInDelegationRoles(c *check.C, repoName, target string, roles ...string) {
-	// assert it's not in the target role
-	targets := s.notaryListTargetsInRoles(c, repoName, "targets")
-	roleName, ok := targets[target]
-	c.Assert(ok, checker.True)
-	c.Assert(roleName, checker.Not(checker.Equals), "targets")
-
+func (s *DockerTrustSuite) assertTargetInRoles(c *check.C, repoName, target string, roles ...string) {
 	// check all the roles
 	for _, role := range roles {
-		targets := s.notaryListTargetsInRoles(c, repoName, role)
+		targets := s.notaryListTargetsInRole(c, repoName, role)
 		roleName, ok := targets[target]
 		c.Assert(ok, checker.True)
 		c.Assert(roleName, checker.Equals, role)
 	}
 }
+
+func (s *DockerTrustSuite) assertTargetNotInRoles(c *check.C, repoName, target string, roles ...string) {
+	targets := s.notaryListTargetsInRole(c, repoName, "targets")
+
+	roleName, ok := targets[target]
+	if ok {
+		for _, role := range roles {
+			c.Assert(roleName, checker.Not(checker.Equals), role)
+		}
+	}
+}