github.1git.de/docker/cli@v26.1.3+incompatible/cli/command/trust/inspect.go (about)

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