Browse Source

Merge pull request #20307 from HuKeping/trust

Refactor trust push
David Calavera 9 years ago
parent
commit
1ba0358a10
1 changed files with 44 additions and 30 deletions
  1. 44 30
      api/client/trust.go

+ 44 - 30
api/client/trust.go

@@ -375,34 +375,57 @@ func (cli *DockerCli) trustedPush(repoInfo *registry.RepositoryInfo, tag string,
 
 	defer responseBody.Close()
 
-	targets := []target{}
+	// If it is a trusted push we would like to find the target entry which match the
+	// tag provided in the function and then do an AddTarget later.
+	target := &client.Target{}
+	// Count the times of calling for handleTarget,
+	// if it is called more that once, that should be considered an error in a trusted push.
+	cnt := 0
 	handleTarget := func(aux *json.RawMessage) {
+		cnt++
+		if cnt > 1 {
+			// handleTarget should only be called one. This will be treated as an error.
+			return
+		}
+
 		var pushResult distribution.PushResult
 		err := json.Unmarshal(*aux, &pushResult)
 		if err == nil && pushResult.Tag != "" && pushResult.Digest.Validate() == nil {
-			targets = append(targets, target{
-				reference: registry.ParseReference(pushResult.Tag),
-				digest:    pushResult.Digest,
-				size:      int64(pushResult.Size),
-			})
+			h, err := hex.DecodeString(pushResult.Digest.Hex())
+			if err != nil {
+				target = nil
+				return
+			}
+			target.Name = registry.ParseReference(pushResult.Tag).String()
+			target.Hashes = data.Hashes{string(pushResult.Digest.Algorithm()): h}
+			target.Length = int64(pushResult.Size)
 		}
 	}
 
-	err = jsonmessage.DisplayJSONMessagesStream(responseBody, cli.out, cli.outFd, cli.isTerminalOut, handleTarget)
-	if err != nil {
+	// We want trust signatures to always take an explicit tag,
+	// otherwise it will act as an untrusted push.
+	if tag == "" {
+		if err = jsonmessage.DisplayJSONMessagesStream(responseBody, cli.out, cli.outFd, cli.isTerminalOut, nil); err != nil {
+			return err
+		}
+		fmt.Fprintln(cli.out, "No tag specified, skipping trust metadata push")
+		return nil
+	}
+
+	if err = jsonmessage.DisplayJSONMessagesStream(responseBody, cli.out, cli.outFd, cli.isTerminalOut, handleTarget); err != nil {
 		return err
 	}
 
-	if tag == "" {
-		fmt.Fprintf(cli.out, "No tag specified, skipping trust metadata push\n")
-		return nil
+	if cnt > 1 {
+		return fmt.Errorf("internal error: only one call to handleTarget expected")
 	}
-	if len(targets) == 0 {
-		fmt.Fprintf(cli.out, "No targets found, skipping trust metadata push\n")
+
+	if target == nil {
+		fmt.Fprintln(cli.out, "No targets found, please provide a specific tag in order to sign it")
 		return nil
 	}
 
-	fmt.Fprintf(cli.out, "Signing and pushing trust metadata\n")
+	fmt.Fprintln(cli.out, "Signing and pushing trust metadata")
 
 	repo, err := cli.getNotaryRepository(repoInfo, authConfig, "push", "pull")
 	if err != nil {
@@ -410,25 +433,16 @@ func (cli *DockerCli) trustedPush(repoInfo *registry.RepositoryInfo, tag string,
 		return err
 	}
 
-	for _, target := range targets {
-		h, err := hex.DecodeString(target.digest.Hex())
-		if err != nil {
-			return err
-		}
-		t := &client.Target{
-			Name: target.reference.String(),
-			Hashes: data.Hashes{
-				string(target.digest.Algorithm()): h,
-			},
-			Length: int64(target.size),
-		}
-		if err := repo.AddTarget(t, releasesRole); err != nil {
-			return err
-		}
+	if err := repo.AddTarget(target, releasesRole); err != nil {
+		return err
 	}
 
 	err = repo.Publish()
-	if _, ok := err.(client.ErrRepoNotInitialized); !ok {
+	if err == nil {
+		fmt.Fprintf(cli.out, "Successfully signed %q:%s\n", repoInfo.FullName(), tag)
+		return nil
+	} else if _, ok := err.(client.ErrRepoNotInitialized); !ok {
+		fmt.Fprintf(cli.out, "Failed to sign %q:%s - %s\n", repoInfo.FullName(), tag, err.Error())
 		return notaryError(repoInfo.FullName(), err)
 	}