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 }