github.com/justincormack/cli@v0.0.0-20201215022714-831ebeae9675/cli/command/trust/inspect.go (about)

     1  package trust
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"sort"
     7  
     8  	"github.com/docker/cli/cli"
     9  	"github.com/docker/cli/cli/command"
    10  	"github.com/docker/cli/cli/command/inspect"
    11  	"github.com/spf13/cobra"
    12  	"github.com/theupdateframework/notary/tuf/data"
    13  )
    14  
    15  type inspectOptions struct {
    16  	remotes []string
    17  	// FIXME(n4ss): this is consistent with `docker service inspect` but we should provide
    18  	// a `--format` flag too. (format and pretty-print should be exclusive)
    19  	prettyPrint bool
    20  }
    21  
    22  func newInspectCommand(dockerCli command.Cli) *cobra.Command {
    23  	options := inspectOptions{}
    24  	cmd := &cobra.Command{
    25  		Use:   "inspect IMAGE[:TAG] [IMAGE[:TAG]...]",
    26  		Short: "Return low-level information about keys and signatures",
    27  		Args:  cli.RequiresMinArgs(1),
    28  		RunE: func(cmd *cobra.Command, args []string) error {
    29  			options.remotes = args
    30  
    31  			return runInspect(dockerCli, options)
    32  		},
    33  	}
    34  
    35  	flags := cmd.Flags()
    36  	flags.BoolVar(&options.prettyPrint, "pretty", false, "Print the information in a human friendly format")
    37  
    38  	return cmd
    39  }
    40  
    41  func runInspect(dockerCli command.Cli, opts inspectOptions) error {
    42  	if opts.prettyPrint {
    43  		var err error
    44  
    45  		for index, remote := range opts.remotes {
    46  			if err = prettyPrintTrustInfo(dockerCli, remote); err != nil {
    47  				return err
    48  			}
    49  
    50  			// Additional separator between the inspection output of each image
    51  			if index < len(opts.remotes)-1 {
    52  				fmt.Fprint(dockerCli.Out(), "\n\n")
    53  			}
    54  		}
    55  
    56  		return err
    57  	}
    58  
    59  	getRefFunc := func(ref string) (interface{}, []byte, error) {
    60  		i, err := getRepoTrustInfo(dockerCli, ref)
    61  		return nil, i, err
    62  	}
    63  	return inspect.Inspect(dockerCli.Out(), opts.remotes, "", getRefFunc)
    64  }
    65  
    66  func getRepoTrustInfo(cli command.Cli, remote string) ([]byte, error) {
    67  	signatureRows, adminRolesWithSigs, delegationRoles, err := lookupTrustInfo(cli, remote)
    68  	if err != nil {
    69  		return []byte{}, err
    70  	}
    71  	// process the signatures to include repo admin if signed by the base targets role
    72  	for idx, sig := range signatureRows {
    73  		if len(sig.Signers) == 0 {
    74  			signatureRows[idx].Signers = append(sig.Signers, releasedRoleName)
    75  		}
    76  	}
    77  
    78  	signerList, adminList := []trustSigner{}, []trustSigner{}
    79  
    80  	signerRoleToKeyIDs := getDelegationRoleToKeyMap(delegationRoles)
    81  
    82  	for signerName, signerKeys := range signerRoleToKeyIDs {
    83  		signerKeyList := []trustKey{}
    84  		for _, keyID := range signerKeys {
    85  			signerKeyList = append(signerKeyList, trustKey{ID: keyID})
    86  		}
    87  		signerList = append(signerList, trustSigner{signerName, signerKeyList})
    88  	}
    89  	sort.Slice(signerList, func(i, j int) bool { return signerList[i].Name > signerList[j].Name })
    90  
    91  	for _, adminRole := range adminRolesWithSigs {
    92  		switch adminRole.Name {
    93  		case data.CanonicalRootRole:
    94  			rootKeys := []trustKey{}
    95  			for _, keyID := range adminRole.KeyIDs {
    96  				rootKeys = append(rootKeys, trustKey{ID: keyID})
    97  			}
    98  			adminList = append(adminList, trustSigner{"Root", rootKeys})
    99  		case data.CanonicalTargetsRole:
   100  			targetKeys := []trustKey{}
   101  			for _, keyID := range adminRole.KeyIDs {
   102  				targetKeys = append(targetKeys, trustKey{ID: keyID})
   103  			}
   104  			adminList = append(adminList, trustSigner{"Repository", targetKeys})
   105  		}
   106  	}
   107  	sort.Slice(adminList, func(i, j int) bool { return adminList[i].Name > adminList[j].Name })
   108  
   109  	return json.Marshal(trustRepo{
   110  		Name:               remote,
   111  		SignedTags:         signatureRows,
   112  		Signers:            signerList,
   113  		AdministrativeKeys: adminList,
   114  	})
   115  }