diff --git a/cli/command/image/pull.go b/cli/command/image/pull.go index 9116d45840..13de492f92 100644 --- a/cli/command/image/pull.go +++ b/cli/command/image/pull.go @@ -55,16 +55,6 @@ func runPull(dockerCli *command.DockerCli, opts pullOptions) error { fmt.Fprintf(dockerCli.Out(), "Using default tag: %s\n", reference.DefaultTag) } - var tag string - switch x := distributionRef.(type) { - case reference.Canonical: - tag = x.Digest().String() - case reference.NamedTagged: - tag = x.Tag() - } - - registryRef := registry.ParseReference(tag) - // Resolve the Repository name from fqn to RepositoryInfo repoInfo, err := registry.ParseRepositoryInfo(distributionRef) if err != nil { @@ -76,9 +66,10 @@ func runPull(dockerCli *command.DockerCli, opts pullOptions) error { authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index) requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "pull") - if command.IsTrusted() && !registryRef.HasDigest() { - // Check if tag is digest - err = trustedPull(ctx, dockerCli, repoInfo, registryRef, authConfig, requestPrivilege) + // Check if reference has a digest + _, isCanonical := distributionRef.(reference.Canonical) + if command.IsTrusted() && !isCanonical { + err = trustedPull(ctx, dockerCli, repoInfo, distributionRef, authConfig, requestPrivilege) } else { err = imagePullPrivileged(ctx, dockerCli, authConfig, distributionRef.String(), requestPrivilege, opts.all) } diff --git a/cli/command/image/trust.go b/cli/command/image/trust.go index d1106b532e..8f5c76d8ca 100644 --- a/cli/command/image/trust.go +++ b/cli/command/image/trust.go @@ -46,9 +46,9 @@ var ( ) type target struct { - reference registry.Reference - digest digest.Digest - size int64 + name string + digest digest.Digest + size int64 } // trustedPush handles content trust pushing of an image @@ -81,7 +81,7 @@ func trustedPush(ctx context.Context, cli *command.DockerCli, repoInfo *registry target = nil return } - target.Name = registry.ParseReference(pushResult.Tag).String() + target.Name = pushResult.Tag target.Hashes = data.Hashes{string(pushResult.Digest.Algorithm()): h} target.Length = int64(pushResult.Size) } @@ -93,11 +93,9 @@ func trustedPush(ctx context.Context, cli *command.DockerCli, repoInfo *registry return errors.New("cannot push a digest reference") case reference.NamedTagged: tag = x.Tag() - } - - // We want trust signatures to always take an explicit tag, - // otherwise it will act as an untrusted push. - if tag == "" { + default: + // We want trust signatures to always take an explicit tag, + // otherwise it will act as an untrusted push. if err = jsonmessage.DisplayJSONMessagesToStream(responseBody, cli.Out(), nil); err != nil { return err } @@ -234,7 +232,7 @@ func imagePushPrivileged(ctx context.Context, cli *command.DockerCli, authConfig } // trustedPull handles content trust pulling of an image -func trustedPull(ctx context.Context, cli *command.DockerCli, repoInfo *registry.RepositoryInfo, ref registry.Reference, authConfig types.AuthConfig, requestPrivilege types.RequestPrivilegeFunc) error { +func trustedPull(ctx context.Context, cli *command.DockerCli, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig types.AuthConfig, requestPrivilege types.RequestPrivilegeFunc) error { var refs []target notaryRepo, err := GetNotaryRepository(cli, repoInfo, authConfig, "pull") @@ -243,7 +241,7 @@ func trustedPull(ctx context.Context, cli *command.DockerCli, repoInfo *registry return err } - if ref.String() == "" { + if tagged, isTagged := ref.(reference.NamedTagged); !isTagged { // List all targets targets, err := notaryRepo.ListTargets(releasesRole, data.CanonicalTargetsRole) if err != nil { @@ -266,14 +264,14 @@ func trustedPull(ctx context.Context, cli *command.DockerCli, repoInfo *registry return notaryError(repoInfo.FullName(), fmt.Errorf("No trusted tags for %s", repoInfo.FullName())) } } else { - t, err := notaryRepo.GetTargetByName(ref.String(), releasesRole, data.CanonicalTargetsRole) + t, err := notaryRepo.GetTargetByName(tagged.Tag(), releasesRole, data.CanonicalTargetsRole) if err != nil { return notaryError(repoInfo.FullName(), err) } // Only get the tag if it's in the top level targets role or the releases delegation role // ignore it if it's in any other delegation roles if t.Role != releasesRole && t.Role != data.CanonicalTargetsRole { - return notaryError(repoInfo.FullName(), fmt.Errorf("No trust data for %s", ref.String())) + return notaryError(repoInfo.FullName(), fmt.Errorf("No trust data for %s", tagged.Tag())) } logrus.Debugf("retrieving target for %s role\n", t.Role) @@ -286,7 +284,7 @@ func trustedPull(ctx context.Context, cli *command.DockerCli, repoInfo *registry } for i, r := range refs { - displayTag := r.reference.String() + displayTag := r.name if displayTag != "" { displayTag = ":" + displayTag } @@ -300,19 +298,16 @@ func trustedPull(ctx context.Context, cli *command.DockerCli, repoInfo *registry return err } - // If reference is not trusted, tag by trusted reference - if !r.reference.HasDigest() { - tagged, err := reference.WithTag(repoInfo, r.reference.String()) - if err != nil { - return err - } - trustedRef, err := reference.WithDigest(reference.TrimNamed(repoInfo), r.digest) - if err != nil { - return err - } - if err := TagTrusted(ctx, cli, trustedRef, tagged); err != nil { - return err - } + tagged, err := reference.WithTag(repoInfo, r.name) + if err != nil { + return err + } + trustedRef, err := reference.WithDigest(reference.TrimNamed(repoInfo), r.digest) + if err != nil { + return err + } + if err := TagTrusted(ctx, cli, trustedRef, tagged); err != nil { + return err } } return nil @@ -533,9 +528,9 @@ func convertTarget(t client.Target) (target, error) { return target{}, errors.New("no valid hash, expecting sha256") } return target{ - reference: registry.ParseReference(t.Name), - digest: digest.NewDigestFromHex("sha256", hex.EncodeToString(h)), - size: t.Length, + name: t.Name, + digest: digest.NewDigestFromHex("sha256", hex.EncodeToString(h)), + size: t.Length, }, nil } diff --git a/registry/reference.go b/registry/reference.go deleted file mode 100644 index e15f83eeeb..0000000000 --- a/registry/reference.go +++ /dev/null @@ -1,68 +0,0 @@ -package registry - -import ( - "strings" - - "github.com/docker/distribution/digest" -) - -// Reference represents a tag or digest within a repository -type Reference interface { - // HasDigest returns whether the reference has a verifiable - // content addressable reference which may be considered secure. - HasDigest() bool - - // ImageName returns an image name for the given repository - ImageName(string) string - - // Returns a string representation of the reference - String() string -} - -type tagReference struct { - tag string -} - -func (tr tagReference) HasDigest() bool { - return false -} - -func (tr tagReference) ImageName(repo string) string { - return repo + ":" + tr.tag -} - -func (tr tagReference) String() string { - return tr.tag -} - -type digestReference struct { - digest digest.Digest -} - -func (dr digestReference) HasDigest() bool { - return true -} - -func (dr digestReference) ImageName(repo string) string { - return repo + "@" + dr.String() -} - -func (dr digestReference) String() string { - return dr.digest.String() -} - -// ParseReference parses a reference into either a digest or tag reference -func ParseReference(ref string) Reference { - if strings.Contains(ref, ":") { - dgst, err := digest.ParseDigest(ref) - if err == nil { - return digestReference{digest: dgst} - } - } - return tagReference{tag: ref} -} - -// DigestReference creates a digest reference using a digest -func DigestReference(dgst digest.Digest) Reference { - return digestReference{digest: dgst} -}