github.com/itscaro/cli@v0.0.0-20190705081621-c9db0fe93829/cli/command/trust/revoke.go (about)

     1  package trust
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  
     8  	"github.com/docker/cli/cli"
     9  	"github.com/docker/cli/cli/command"
    10  	"github.com/docker/cli/cli/command/image"
    11  	"github.com/docker/cli/cli/trust"
    12  	"github.com/pkg/errors"
    13  	"github.com/spf13/cobra"
    14  	"github.com/theupdateframework/notary/client"
    15  	"github.com/theupdateframework/notary/tuf/data"
    16  )
    17  
    18  type revokeOptions struct {
    19  	forceYes bool
    20  }
    21  
    22  func newRevokeCommand(dockerCli command.Cli) *cobra.Command {
    23  	options := revokeOptions{}
    24  	cmd := &cobra.Command{
    25  		Use:   "revoke [OPTIONS] IMAGE[:TAG]",
    26  		Short: "Remove trust for an image",
    27  		Args:  cli.ExactArgs(1),
    28  		RunE: func(cmd *cobra.Command, args []string) error {
    29  			return revokeTrust(dockerCli, args[0], options)
    30  		},
    31  	}
    32  	flags := cmd.Flags()
    33  	flags.BoolVarP(&options.forceYes, "yes", "y", false, "Do not prompt for confirmation")
    34  	return cmd
    35  }
    36  
    37  func revokeTrust(cli command.Cli, remote string, options revokeOptions) error {
    38  	ctx := context.Background()
    39  	imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, nil, image.AuthResolver(cli), remote)
    40  	if err != nil {
    41  		return err
    42  	}
    43  	tag := imgRefAndAuth.Tag()
    44  	if imgRefAndAuth.Tag() == "" && imgRefAndAuth.Digest() != "" {
    45  		return fmt.Errorf("cannot use a digest reference for IMAGE:TAG")
    46  	}
    47  	if imgRefAndAuth.Tag() == "" && !options.forceYes {
    48  		deleteRemote := command.PromptForConfirmation(os.Stdin, cli.Out(), fmt.Sprintf("Please confirm you would like to delete all signature data for %s?", remote))
    49  		if !deleteRemote {
    50  			fmt.Fprintf(cli.Out(), "\nAborting action.\n")
    51  			return nil
    52  		}
    53  	}
    54  
    55  	notaryRepo, err := cli.NotaryClient(imgRefAndAuth, trust.ActionsPushAndPull)
    56  	if err != nil {
    57  		return err
    58  	}
    59  
    60  	if err = clearChangeList(notaryRepo); err != nil {
    61  		return err
    62  	}
    63  	defer clearChangeList(notaryRepo)
    64  	if err := revokeSignature(notaryRepo, tag); err != nil {
    65  		return errors.Wrapf(err, "could not remove signature for %s", remote)
    66  	}
    67  	fmt.Fprintf(cli.Out(), "Successfully deleted signature for %s\n", remote)
    68  	return nil
    69  }
    70  
    71  func revokeSignature(notaryRepo client.Repository, tag string) error {
    72  	if tag != "" {
    73  		// Revoke signature for the specified tag
    74  		if err := revokeSingleSig(notaryRepo, tag); err != nil {
    75  			return err
    76  		}
    77  	} else {
    78  		// revoke all signatures for the image, as no tag was given
    79  		if err := revokeAllSigs(notaryRepo); err != nil {
    80  			return err
    81  		}
    82  	}
    83  
    84  	//  Publish change
    85  	return notaryRepo.Publish()
    86  }
    87  
    88  func revokeSingleSig(notaryRepo client.Repository, tag string) error {
    89  	releasedTargetWithRole, err := notaryRepo.GetTargetByName(tag, trust.ReleasesRole, data.CanonicalTargetsRole)
    90  	if err != nil {
    91  		return err
    92  	}
    93  	releasedTarget := releasedTargetWithRole.Target
    94  	return getSignableRolesForTargetAndRemove(releasedTarget, notaryRepo)
    95  }
    96  
    97  func revokeAllSigs(notaryRepo client.Repository) error {
    98  	releasedTargetWithRoleList, err := notaryRepo.ListTargets(trust.ReleasesRole, data.CanonicalTargetsRole)
    99  	if err != nil {
   100  		return err
   101  	}
   102  
   103  	if len(releasedTargetWithRoleList) == 0 {
   104  		return fmt.Errorf("no signed tags to remove")
   105  	}
   106  
   107  	// we need all the roles that signed each released target so we can remove from all roles.
   108  	for _, releasedTargetWithRole := range releasedTargetWithRoleList {
   109  		// remove from all roles
   110  		if err := getSignableRolesForTargetAndRemove(releasedTargetWithRole.Target, notaryRepo); err != nil {
   111  			return err
   112  		}
   113  	}
   114  	return nil
   115  }
   116  
   117  // get all the roles that signed the target and removes it from all roles.
   118  func getSignableRolesForTargetAndRemove(releasedTarget client.Target, notaryRepo client.Repository) error {
   119  	signableRoles, err := trust.GetSignableRoles(notaryRepo, &releasedTarget)
   120  	if err != nil {
   121  		return err
   122  	}
   123  	// remove from all roles
   124  	return notaryRepo.RemoveTarget(releasedTarget.Name, signableRoles...)
   125  }