github.com/panekj/cli@v0.0.0-20230304125325-467dd2f3797e/cli/command/service/trust.go (about)

     1  package service
     2  
     3  import (
     4  	"context"
     5  	"encoding/hex"
     6  
     7  	"github.com/docker/cli/cli/command"
     8  	"github.com/docker/cli/cli/trust"
     9  	"github.com/docker/distribution/reference"
    10  	"github.com/docker/docker/api/types/swarm"
    11  	"github.com/docker/docker/registry"
    12  	"github.com/opencontainers/go-digest"
    13  	"github.com/pkg/errors"
    14  	"github.com/sirupsen/logrus"
    15  	"github.com/theupdateframework/notary/tuf/data"
    16  )
    17  
    18  func resolveServiceImageDigestContentTrust(dockerCli command.Cli, service *swarm.ServiceSpec) error {
    19  	if !dockerCli.ContentTrustEnabled() {
    20  		// When not using content trust, digest resolution happens later when
    21  		// contacting the registry to retrieve image information.
    22  		return nil
    23  	}
    24  
    25  	ref, err := reference.ParseAnyReference(service.TaskTemplate.ContainerSpec.Image)
    26  	if err != nil {
    27  		return errors.Wrapf(err, "invalid reference %s", service.TaskTemplate.ContainerSpec.Image)
    28  	}
    29  
    30  	// If reference does not have digest (is not canonical nor image id)
    31  	if _, ok := ref.(reference.Digested); !ok {
    32  		namedRef, ok := ref.(reference.Named)
    33  		if !ok {
    34  			return errors.New("failed to resolve image digest using content trust: reference is not named")
    35  		}
    36  		namedRef = reference.TagNameOnly(namedRef)
    37  		taggedRef, ok := namedRef.(reference.NamedTagged)
    38  		if !ok {
    39  			return errors.New("failed to resolve image digest using content trust: reference is not tagged")
    40  		}
    41  
    42  		resolvedImage, err := trustedResolveDigest(context.Background(), dockerCli, taggedRef)
    43  		if err != nil {
    44  			return errors.Wrap(err, "failed to resolve image digest using content trust")
    45  		}
    46  		resolvedFamiliar := reference.FamiliarString(resolvedImage)
    47  		logrus.Debugf("resolved image tag to %s using content trust", resolvedFamiliar)
    48  		service.TaskTemplate.ContainerSpec.Image = resolvedFamiliar
    49  	}
    50  
    51  	return nil
    52  }
    53  
    54  func trustedResolveDigest(ctx context.Context, cli command.Cli, ref reference.NamedTagged) (reference.Canonical, error) {
    55  	repoInfo, err := registry.ParseRepositoryInfo(ref)
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	authConfig := command.ResolveAuthConfig(ctx, cli, repoInfo.Index)
    61  
    62  	notaryRepo, err := trust.GetNotaryRepository(cli.In(), cli.Out(), command.UserAgent(), repoInfo, &authConfig, "pull")
    63  	if err != nil {
    64  		return nil, errors.Wrap(err, "error establishing connection to trust repository")
    65  	}
    66  
    67  	t, err := notaryRepo.GetTargetByName(ref.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole)
    68  	if err != nil {
    69  		return nil, trust.NotaryError(repoInfo.Name.Name(), err)
    70  	}
    71  	// Only get the tag if it's in the top level targets role or the releases delegation role
    72  	// ignore it if it's in any other delegation roles
    73  	if t.Role != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole {
    74  		return nil, trust.NotaryError(repoInfo.Name.Name(), errors.Errorf("No trust data for %s", reference.FamiliarString(ref)))
    75  	}
    76  
    77  	logrus.Debugf("retrieving target for %s role\n", t.Role)
    78  	h, ok := t.Hashes["sha256"]
    79  	if !ok {
    80  		return nil, errors.New("no valid hash, expecting sha256")
    81  	}
    82  
    83  	dgst := digest.NewDigestFromHex("sha256", hex.EncodeToString(h))
    84  
    85  	// Allow returning canonical reference with tag
    86  	return reference.WithDigest(ref, dgst)
    87  }