Merge pull request #562 from dnephin/update-gometalinter

Update gometalinter
This commit is contained in:
Vincent Demeester 2017-09-27 09:42:37 +02:00 committed by GitHub
commit feb4d79935
19 changed files with 180 additions and 150 deletions

View File

@ -185,6 +185,7 @@ func setRawTerminal(streams command.Streams) error {
return streams.Out().SetRawTerminal() return streams.Out().SetRawTerminal()
} }
// nolint: unparam
func restoreTerminal(streams command.Streams, in io.Closer) error { func restoreTerminal(streams command.Streams, in io.Closer) error {
streams.In().RestoreTerminal() streams.In().RestoreTerminal()
streams.Out().RestoreTerminal() streams.Out().RestoreTerminal()

View File

@ -43,6 +43,7 @@ func TestValidateAttach(t *testing.T) {
} }
} }
// nolint: unparam
func parseRun(args []string) (*container.Config, *container.HostConfig, *networktypes.NetworkingConfig, error) { func parseRun(args []string) (*container.Config, *container.HostConfig, *networktypes.NetworkingConfig, error) {
flags := pflag.NewFlagSet("run", pflag.ContinueOnError) flags := pflag.NewFlagSet("run", pflag.ContinueOnError)
flags.SetOutput(ioutil.Discard) flags.SetOutput(ioutil.Discard)

View File

@ -6,8 +6,8 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/trust"
"github.com/docker/distribution/reference" "github.com/docker/distribution/reference"
"github.com/docker/docker/registry"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"golang.org/x/net/context" "golang.org/x/net/context"
@ -40,11 +40,14 @@ func NewPullCommand(dockerCli command.Cli) *cobra.Command {
return cmd return cmd
} }
func runPull(dockerCli command.Cli, opts pullOptions) error { func runPull(cli command.Cli, opts pullOptions) error {
distributionRef, err := reference.ParseNormalizedNamed(opts.remote) ctx := context.Background()
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, AuthResolver(cli), opts.remote)
if err != nil { if err != nil {
return err return err
} }
distributionRef := imgRefAndAuth.Reference()
if opts.all && !reference.IsNameOnly(distributionRef) { if opts.all && !reference.IsNameOnly(distributionRef) {
return errors.New("tag can't be used with --all-tags/-a") return errors.New("tag can't be used with --all-tags/-a")
} }
@ -52,27 +55,16 @@ func runPull(dockerCli command.Cli, opts pullOptions) error {
if !opts.all && reference.IsNameOnly(distributionRef) { if !opts.all && reference.IsNameOnly(distributionRef) {
distributionRef = reference.TagNameOnly(distributionRef) distributionRef = reference.TagNameOnly(distributionRef)
if tagged, ok := distributionRef.(reference.Tagged); ok { if tagged, ok := distributionRef.(reference.Tagged); ok {
fmt.Fprintf(dockerCli.Out(), "Using default tag: %s\n", tagged.Tag()) fmt.Fprintf(cli.Out(), "Using default tag: %s\n", tagged.Tag())
} }
} }
// Resolve the Repository name from fqn to RepositoryInfo
repoInfo, err := registry.ParseRepositoryInfo(distributionRef)
if err != nil {
return err
}
ctx := context.Background()
authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index)
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "pull")
// Check if reference has a digest // Check if reference has a digest
_, isCanonical := distributionRef.(reference.Canonical) _, isCanonical := distributionRef.(reference.Canonical)
if command.IsTrusted() && !isCanonical { if command.IsTrusted() && !isCanonical {
err = trustedPull(ctx, dockerCli, repoInfo, distributionRef, authConfig, requestPrivilege) err = trustedPull(ctx, cli, imgRefAndAuth)
} else { } else {
err = imagePullPrivileged(ctx, dockerCli, authConfig, reference.FamiliarString(distributionRef), requestPrivilege, opts.all) err = imagePullPrivileged(ctx, cli, imgRefAndAuth, opts.all)
} }
if err != nil { if err != nil {
if strings.Contains(err.Error(), "when fetching 'plugin'") { if strings.Contains(err.Error(), "when fetching 'plugin'") {
@ -80,6 +72,5 @@ func runPull(dockerCli command.Cli, opts pullOptions) error {
} }
return err return err
} }
return nil return nil
} }

View File

@ -32,11 +32,6 @@ func TestNewPullCommandErrors(t *testing.T) {
expectedError: "tag can't be used with --all-tags/-a", expectedError: "tag can't be used with --all-tags/-a",
args: []string{"--all-tags", "image:tag"}, args: []string{"--all-tags", "image:tag"},
}, },
{
name: "pull-error",
args: []string{"--disable-content-trust=false", "image:tag"},
expectedError: "you are not authorized to perform this operation: server returned 401.",
},
} }
for _, tc := range testCases { for _, tc := range testCases {
cli := test.NewFakeCli(&fakeClient{}) cli := test.NewFakeCli(&fakeClient{})

View File

@ -11,11 +11,12 @@ import (
"github.com/docker/cli/cli/trust" "github.com/docker/cli/cli/trust"
"github.com/docker/distribution/reference" "github.com/docker/distribution/reference"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/registry" "github.com/docker/docker/registry"
"github.com/docker/notary/client" "github.com/docker/notary/client"
"github.com/docker/notary/tuf/data" "github.com/docker/notary/tuf/data"
"github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/net/context" "golang.org/x/net/context"
@ -181,57 +182,13 @@ func imagePushPrivileged(ctx context.Context, cli command.Cli, authConfig types.
} }
// trustedPull handles content trust pulling of an image // trustedPull handles content trust pulling of an image
func trustedPull(ctx context.Context, cli command.Cli, repoInfo *registry.RepositoryInfo, ref reference.Named, authConfig types.AuthConfig, requestPrivilege types.RequestPrivilegeFunc) error { func trustedPull(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth) error {
var refs []target refs, err := getTrustedPullTargets(cli, imgRefAndAuth)
notaryRepo, err := trust.GetNotaryRepository(cli.In(), cli.Out(), command.UserAgent(), repoInfo, &authConfig, "pull")
if err != nil {
fmt.Fprintf(cli.Out(), "Error establishing connection to trust repository: %s\n", err)
return err
}
if tagged, isTagged := ref.(reference.NamedTagged); !isTagged {
// List all targets
targets, err := notaryRepo.ListTargets(trust.ReleasesRole, data.CanonicalTargetsRole)
if err != nil {
return trust.NotaryError(ref.Name(), err)
}
for _, tgt := range targets {
t, err := convertTarget(tgt.Target)
if err != nil {
fmt.Fprintf(cli.Out(), "Skipping target for %q\n", reference.FamiliarName(ref))
continue
}
// Only list tags in the top level targets role or the releases delegation role - ignore
// all other delegation roles
if tgt.Role != trust.ReleasesRole && tgt.Role != data.CanonicalTargetsRole {
continue
}
refs = append(refs, t)
}
if len(refs) == 0 {
return trust.NotaryError(ref.Name(), errors.Errorf("No trusted tags for %s", ref.Name()))
}
} else {
t, err := notaryRepo.GetTargetByName(tagged.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole)
if err != nil {
return trust.NotaryError(ref.Name(), 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 != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole {
return trust.NotaryError(ref.Name(), errors.Errorf("No trust data for %s", tagged.Tag()))
}
logrus.Debugf("retrieving target for %s role\n", t.Role)
r, err := convertTarget(t.Target)
if err != nil { if err != nil {
return err return err
}
refs = append(refs, r)
} }
ref := imgRefAndAuth.Reference()
for i, r := range refs { for i, r := range refs {
displayTag := r.name displayTag := r.name
if displayTag != "" { if displayTag != "" {
@ -243,7 +200,7 @@ func trustedPull(ctx context.Context, cli command.Cli, repoInfo *registry.Reposi
if err != nil { if err != nil {
return err return err
} }
if err := imagePullPrivileged(ctx, cli, authConfig, reference.FamiliarString(trustedRef), requestPrivilege, false); err != nil { if err := imagePullPrivileged(ctx, cli, imgRefAndAuth, false); err != nil {
return err return err
} }
@ -259,13 +216,65 @@ func trustedPull(ctx context.Context, cli command.Cli, repoInfo *registry.Reposi
return nil return nil
} }
// imagePullPrivileged pulls the image and displays it to the output func getTrustedPullTargets(cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth) ([]target, error) {
func imagePullPrivileged(ctx context.Context, cli command.Cli, authConfig types.AuthConfig, ref string, requestPrivilege types.RequestPrivilegeFunc, all bool) error { notaryRepo, err := cli.NotaryClient(imgRefAndAuth, trust.ActionsPullOnly)
if err != nil {
fmt.Fprintf(cli.Out(), "Error establishing connection to trust repository: %s\n", err)
return nil, err
}
encodedAuth, err := command.EncodeAuthToBase64(authConfig) ref := imgRefAndAuth.Reference()
tagged, isTagged := ref.(reference.NamedTagged)
if !isTagged {
// List all targets
targets, err := notaryRepo.ListTargets(trust.ReleasesRole, data.CanonicalTargetsRole)
if err != nil {
return nil, trust.NotaryError(ref.Name(), err)
}
var refs []target
for _, tgt := range targets {
t, err := convertTarget(tgt.Target)
if err != nil {
fmt.Fprintf(cli.Out(), "Skipping target for %q\n", reference.FamiliarName(ref))
continue
}
// Only list tags in the top level targets role or the releases delegation role - ignore
// all other delegation roles
if tgt.Role != trust.ReleasesRole && tgt.Role != data.CanonicalTargetsRole {
continue
}
refs = append(refs, t)
}
if len(refs) == 0 {
return nil, trust.NotaryError(ref.Name(), errors.Errorf("No trusted tags for %s", ref.Name()))
}
return refs, nil
}
t, err := notaryRepo.GetTargetByName(tagged.Tag(), trust.ReleasesRole, data.CanonicalTargetsRole)
if err != nil {
return nil, trust.NotaryError(ref.Name(), 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 != trust.ReleasesRole && t.Role != data.CanonicalTargetsRole {
return nil, trust.NotaryError(ref.Name(), errors.Errorf("No trust data for %s", tagged.Tag()))
}
logrus.Debugf("retrieving target for %s role\n", t.Role)
r, err := convertTarget(t.Target)
return []target{r}, err
}
// imagePullPrivileged pulls the image and displays it to the output
func imagePullPrivileged(ctx context.Context, cli command.Cli, imgRefAndAuth trust.ImageRefAndAuth, all bool) error {
ref := reference.FamiliarString(imgRefAndAuth.Reference())
encodedAuth, err := command.EncodeAuthToBase64(*imgRefAndAuth.AuthConfig())
if err != nil { if err != nil {
return err return err
} }
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(cli, imgRefAndAuth.RepoInfo().Index, "pull")
options := types.ImagePullOptions{ options := types.ImagePullOptions{
RegistryAuth: encodedAuth, RegistryAuth: encodedAuth,
PrivilegeFunc: requestPrivilege, PrivilegeFunc: requestPrivilege,
@ -346,3 +355,10 @@ func TagTrusted(ctx context.Context, cli command.Cli, trustedRef reference.Canon
return cli.Client().ImageTag(ctx, trustedFamiliarRef, familiarRef) return cli.Client().ImageTag(ctx, trustedFamiliarRef, familiarRef)
} }
// AuthResolver returns an auth resolver function from a command.Cli
func AuthResolver(cli command.Cli) func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig {
return func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig {
return command.ResolveAuthConfig(ctx, cli, index)
}
}

View File

@ -12,6 +12,7 @@ import (
"github.com/docker/notary/passphrase" "github.com/docker/notary/passphrase"
"github.com/docker/notary/trustpinning" "github.com/docker/notary/trustpinning"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func unsetENV() { func unsetENV() {
@ -67,6 +68,7 @@ func TestAddTargetToAllSignableRolesError(t *testing.T) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
notaryRepo, err := client.NewFileCachedRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever("password"), trustpinning.TrustPinConfig{}) notaryRepo, err := client.NewFileCachedRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever("password"), trustpinning.TrustPinConfig{})
require.NoError(t, err)
target := client.Target{} target := client.Target{}
err = AddTargetToAllSignableRoles(notaryRepo, &target) err = AddTargetToAllSignableRoles(notaryRepo, &target)
assert.EqualError(t, err, "client is offline") assert.EqualError(t, err, "client is offline")

View File

@ -104,13 +104,12 @@ func checkDaemonIsSwarmManager(ctx context.Context, dockerCli command.Cli) error
} }
// pruneServices removes services that are no longer referenced in the source // pruneServices removes services that are no longer referenced in the source
func pruneServices(ctx context.Context, dockerCli command.Cli, namespace convert.Namespace, services map[string]struct{}) bool { func pruneServices(ctx context.Context, dockerCli command.Cli, namespace convert.Namespace, services map[string]struct{}) {
client := dockerCli.Client() client := dockerCli.Client()
oldServices, err := getServices(ctx, client, namespace.Name()) oldServices, err := getServices(ctx, client, namespace.Name())
if err != nil { if err != nil {
fmt.Fprintf(dockerCli.Err(), "Failed to list services: %s", err) fmt.Fprintf(dockerCli.Err(), "Failed to list services: %s", err)
return true
} }
pruneServices := []swarm.Service{} pruneServices := []swarm.Service{}
@ -119,5 +118,5 @@ func pruneServices(ctx context.Context, dockerCli command.Cli, namespace convert
pruneServices = append(pruneServices, service) pruneServices = append(pruneServices, service)
} }
} }
return removeServices(ctx, dockerCli, pruneServices) removeServices(ctx, dockerCli, pruneServices)
} }

View File

@ -59,6 +59,7 @@ func TestStackPsEmptyStack(t *testing.T) {
}) })
cmd := newPsCommand(fakeCli) cmd := newPsCommand(fakeCli)
cmd.SetArgs([]string{"foo"}) cmd.SetArgs([]string{"foo"})
cmd.SetOutput(ioutil.Discard)
assert.Error(t, cmd.Execute()) assert.Error(t, cmd.Execute())
assert.EqualError(t, cmd.Execute(), "nothing found in stack: foo") assert.EqualError(t, cmd.Execute(), "nothing found in stack: foo")

View File

@ -15,24 +15,20 @@ import (
"golang.org/x/net/context" "golang.org/x/net/context"
) )
type unlockOptions struct{}
func newUnlockCommand(dockerCli command.Cli) *cobra.Command { func newUnlockCommand(dockerCli command.Cli) *cobra.Command {
opts := unlockOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "unlock", Use: "unlock",
Short: "Unlock swarm", Short: "Unlock swarm",
Args: cli.NoArgs, Args: cli.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return runUnlock(dockerCli, opts) return runUnlock(dockerCli)
}, },
} }
return cmd return cmd
} }
func runUnlock(dockerCli command.Cli, opts unlockOptions) error { func runUnlock(dockerCli command.Cli) error {
client := dockerCli.Client() client := dockerCli.Client()
ctx := context.Background() ctx := context.Background()

View File

@ -5,15 +5,13 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/docker/docker/api/types" "github.com/docker/cli/cli"
registrytypes "github.com/docker/docker/api/types/registry" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/image"
"github.com/docker/cli/cli/trust"
"github.com/docker/notary/client" "github.com/docker/notary/client"
"github.com/docker/notary/tuf/data" "github.com/docker/notary/tuf/data"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/trust"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -38,10 +36,7 @@ func newRevokeCommand(dockerCli command.Cli) *cobra.Command {
func revokeTrust(cli command.Cli, remote string, options revokeOptions) error { func revokeTrust(cli command.Cli, remote string, options revokeOptions) error {
ctx := context.Background() ctx := context.Background()
authResolver := func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig { imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, image.AuthResolver(cli), remote)
return command.ResolveAuthConfig(ctx, cli, index)
}
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, authResolver, remote)
if err != nil { if err != nil {
return err return err
} }
@ -57,7 +52,7 @@ func revokeTrust(cli command.Cli, remote string, options revokeOptions) error {
} }
} }
notaryRepo, err := cli.NotaryClient(*imgRefAndAuth, trust.ActionsPushAndPull) notaryRepo, err := cli.NotaryClient(imgRefAndAuth, trust.ActionsPushAndPull)
if err != nil { if err != nil {
return err return err
} }

View File

@ -11,6 +11,7 @@ import (
"github.com/docker/notary/passphrase" "github.com/docker/notary/passphrase"
"github.com/docker/notary/trustpinning" "github.com/docker/notary/trustpinning"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestTrustRevokeCommandErrors(t *testing.T) { func TestTrustRevokeCommandErrors(t *testing.T) {
@ -140,6 +141,7 @@ func TestGetSignableRolesForTargetAndRemoveError(t *testing.T) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
notaryRepo, err := client.NewFileCachedRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever("password"), trustpinning.TrustPinConfig{}) notaryRepo, err := client.NewFileCachedRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever("password"), trustpinning.TrustPinConfig{})
require.NoError(t, err)
target := client.Target{} target := client.Target{}
err = getSignableRolesForTargetAndRemove(target, notaryRepo) err = getSignableRolesForTargetAndRemove(target, notaryRepo)
assert.EqualError(t, err, "client is offline") assert.EqualError(t, err, "client is offline")

View File

@ -3,6 +3,7 @@ package trust
import ( import (
"context" "context"
"fmt" "fmt"
"io"
"path" "path"
"sort" "sort"
"strings" "strings"
@ -11,8 +12,6 @@ import (
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/image" "github.com/docker/cli/cli/command/image"
"github.com/docker/cli/cli/trust" "github.com/docker/cli/cli/trust"
"github.com/docker/docker/api/types"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/notary/client" "github.com/docker/notary/client"
"github.com/docker/notary/tuf/data" "github.com/docker/notary/tuf/data"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -25,30 +24,23 @@ func newSignCommand(dockerCli command.Cli) *cobra.Command {
Short: "Sign an image", Short: "Sign an image",
Args: cli.ExactArgs(1), Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return signImage(dockerCli, args[0]) return runSignImage(dockerCli, args[0])
}, },
} }
return cmd return cmd
} }
func signImage(cli command.Cli, imageName string) error { func runSignImage(cli command.Cli, imageName string) error {
ctx := context.Background() ctx := context.Background()
authResolver := func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig { imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, image.AuthResolver(cli), imageName)
return command.ResolveAuthConfig(ctx, cli, index)
}
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, authResolver, imageName)
if err != nil { if err != nil {
return err return err
} }
tag := imgRefAndAuth.Tag() if err := validateTag(imgRefAndAuth); err != nil {
if tag == "" { return err
if imgRefAndAuth.Digest() != "" {
return fmt.Errorf("cannot use a digest reference for IMAGE:TAG")
}
return fmt.Errorf("No tag specified for %s", imageName)
} }
notaryRepo, err := cli.NotaryClient(*imgRefAndAuth, trust.ActionsPushAndPull) notaryRepo, err := cli.NotaryClient(imgRefAndAuth, trust.ActionsPushAndPull)
if err != nil { if err != nil {
return trust.NotaryError(imgRefAndAuth.Reference().Name(), err) return trust.NotaryError(imgRefAndAuth.Reference().Name(), err)
} }
@ -78,7 +70,7 @@ func signImage(cli command.Cli, imageName string) error {
} }
} }
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(cli, imgRefAndAuth.RepoInfo().Index, "push") requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(cli, imgRefAndAuth.RepoInfo().Index, "push")
target, err := createTarget(notaryRepo, tag) target, err := createTarget(notaryRepo, imgRefAndAuth.Tag())
if err != nil { if err != nil {
switch err := err.(type) { switch err := err.(type) {
case client.ErrNoSuchTarget, client.ErrRepositoryNotExist: case client.ErrNoSuchTarget, client.ErrRepositoryNotExist:
@ -91,21 +83,36 @@ func signImage(cli command.Cli, imageName string) error {
return err return err
} }
} }
return signAndPublishToTarget(cli.Out(), imgRefAndAuth, notaryRepo, target)
}
fmt.Fprintf(cli.Out(), "Signing and pushing trust metadata for %s\n", imageName) func signAndPublishToTarget(out io.Writer, imgRefAndAuth trust.ImageRefAndAuth, notaryRepo client.Repository, target client.Target) error {
tag := imgRefAndAuth.Tag()
fmt.Fprintf(out, "Signing and pushing trust metadata for %s\n", imgRefAndAuth.Name())
existingSigInfo, err := getExistingSignatureInfoForReleasedTag(notaryRepo, tag) existingSigInfo, err := getExistingSignatureInfoForReleasedTag(notaryRepo, tag)
if err != nil { if err != nil {
return err return err
} }
err = image.AddTargetToAllSignableRoles(notaryRepo, &target) err = image.AddTargetToAllSignableRoles(notaryRepo, &target)
if err == nil { if err == nil {
prettyPrintExistingSignatureInfo(cli, existingSigInfo) prettyPrintExistingSignatureInfo(out, existingSigInfo)
err = notaryRepo.Publish() err = notaryRepo.Publish()
} }
if err != nil { if err != nil {
return errors.Wrapf(err, "failed to sign %q:%s", imgRefAndAuth.RepoInfo().Name.Name(), tag) return errors.Wrapf(err, "failed to sign %q:%s", imgRefAndAuth.RepoInfo().Name.Name(), tag)
} }
fmt.Fprintf(cli.Out(), "Successfully signed %q:%s\n", imgRefAndAuth.RepoInfo().Name.Name(), tag) fmt.Fprintf(out, "Successfully signed %q:%s\n", imgRefAndAuth.RepoInfo().Name.Name(), tag)
return nil
}
func validateTag(imgRefAndAuth trust.ImageRefAndAuth) error {
tag := imgRefAndAuth.Tag()
if tag == "" {
if imgRefAndAuth.Digest() != "" {
return fmt.Errorf("cannot use a digest reference for IMAGE:TAG")
}
return fmt.Errorf("No tag specified for %s", imgRefAndAuth.Name())
}
return nil return nil
} }
@ -154,10 +161,10 @@ func getExistingSignatureInfoForReleasedTag(notaryRepo client.Repository, tag st
return releasedTargetInfoList[0], nil return releasedTargetInfoList[0], nil
} }
func prettyPrintExistingSignatureInfo(cli command.Cli, existingSigInfo trustTagRow) { func prettyPrintExistingSignatureInfo(out io.Writer, existingSigInfo trustTagRow) {
sort.Strings(existingSigInfo.Signers) sort.Strings(existingSigInfo.Signers)
joinedSigners := strings.Join(existingSigInfo.Signers, ", ") joinedSigners := strings.Join(existingSigInfo.Signers, ", ")
fmt.Fprintf(cli.Out(), "Existing signatures for tag %s digest %s from:\n%s\n", existingSigInfo.TagName, existingSigInfo.HashHex, joinedSigners) fmt.Fprintf(out, "Existing signatures for tag %s digest %s from:\n%s\n", existingSigInfo.TagName, existingSigInfo.HashHex, joinedSigners)
} }
func initNotaryRepoWithSigners(notaryRepo client.Repository, newSigner data.RoleName) error { func initNotaryRepoWithSigners(notaryRepo client.Repository, newSigner data.RoleName) error {

View File

@ -6,6 +6,8 @@ import (
"os" "os"
"testing" "testing"
"bytes"
"github.com/docker/cli/cli/config" "github.com/docker/cli/cli/config"
"github.com/docker/cli/cli/trust" "github.com/docker/cli/cli/trust"
"github.com/docker/cli/internal/test" "github.com/docker/cli/internal/test"
@ -17,6 +19,7 @@ import (
"github.com/docker/notary/trustpinning" "github.com/docker/notary/trustpinning"
"github.com/docker/notary/tuf/data" "github.com/docker/notary/tuf/data"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
const passwd = "password" const passwd = "password"
@ -151,6 +154,7 @@ func TestAddStageSigners(t *testing.T) {
NewThreshold: notary.MinThreshold, NewThreshold: notary.MinThreshold,
AddKeys: data.KeyList([]data.PublicKey{userKey}), AddKeys: data.KeyList([]data.PublicKey{userKey}),
}) })
require.NoError(t, err)
expectedChange := changelist.NewTUFChange( expectedChange := changelist.NewTUFChange(
changelist.ActionCreate, changelist.ActionCreate,
userRole, userRole,
@ -165,6 +169,7 @@ func TestAddStageSigners(t *testing.T) {
expectedJSON, err = json.Marshal(&changelist.TUFDelegation{ expectedJSON, err = json.Marshal(&changelist.TUFDelegation{
AddPaths: []string{""}, AddPaths: []string{""},
}) })
require.NoError(t, err)
expectedChange = changelist.NewTUFChange( expectedChange = changelist.NewTUFChange(
changelist.ActionCreate, changelist.ActionCreate,
userRole, userRole,
@ -182,6 +187,7 @@ func TestAddStageSigners(t *testing.T) {
NewThreshold: notary.MinThreshold, NewThreshold: notary.MinThreshold,
AddKeys: data.KeyList([]data.PublicKey{userKey}), AddKeys: data.KeyList([]data.PublicKey{userKey}),
}) })
require.NoError(t, err)
expectedChange = changelist.NewTUFChange( expectedChange = changelist.NewTUFChange(
changelist.ActionCreate, changelist.ActionCreate,
releasesRole, releasesRole,
@ -196,6 +202,7 @@ func TestAddStageSigners(t *testing.T) {
expectedJSON, err = json.Marshal(&changelist.TUFDelegation{ expectedJSON, err = json.Marshal(&changelist.TUFDelegation{
AddPaths: []string{""}, AddPaths: []string{""},
}) })
require.NoError(t, err)
expectedChange = changelist.NewTUFChange( expectedChange = changelist.NewTUFChange(
changelist.ActionCreate, changelist.ActionCreate,
releasesRole, releasesRole,
@ -259,27 +266,32 @@ func TestGetExistingSignatureInfoForReleasedTag(t *testing.T) {
} }
func TestPrettyPrintExistingSignatureInfo(t *testing.T) { func TestPrettyPrintExistingSignatureInfo(t *testing.T) {
fakeCli := test.NewFakeCli(&fakeClient{}) buf := bytes.NewBuffer(nil)
signers := []string{"Bob", "Alice", "Carol"} signers := []string{"Bob", "Alice", "Carol"}
existingSig := trustTagRow{trustTagKey{"tagName", "abc123"}, signers} existingSig := trustTagRow{trustTagKey{"tagName", "abc123"}, signers}
prettyPrintExistingSignatureInfo(fakeCli, existingSig) prettyPrintExistingSignatureInfo(buf, existingSig)
assert.Contains(t, fakeCli.OutBuffer().String(), "Existing signatures for tag tagName digest abc123 from:\nAlice, Bob, Carol") assert.Contains(t, buf.String(), "Existing signatures for tag tagName digest abc123 from:\nAlice, Bob, Carol")
} }
func TestChangeList(t *testing.T) { func TestSignCommandChangeListIsCleanedOnError(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "docker-sign-test-") tmpDir, err := ioutil.TempDir("", "docker-sign-test-")
assert.NoError(t, err) assert.NoError(t, err)
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
config.SetDir(tmpDir) config.SetDir(tmpDir)
cmd := newSignCommand( cli := test.NewFakeCli(&fakeClient{})
test.NewFakeCli(&fakeClient{})) cli.SetNotaryClient(getLoadedNotaryRepository)
cmd := newSignCommand(cli)
cmd.SetArgs([]string{"ubuntu:latest"}) cmd.SetArgs([]string{"ubuntu:latest"})
cmd.SetOutput(ioutil.Discard) cmd.SetOutput(ioutil.Discard)
err = cmd.Execute() err = cmd.Execute()
require.Error(t, err)
notaryRepo, err := client.NewFileCachedRepository(tmpDir, "docker.io/library/ubuntu", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{}) notaryRepo, err := client.NewFileCachedRepository(tmpDir, "docker.io/library/ubuntu", "https://localhost", nil, passphrase.ConstantRetriever(passwd), trustpinning.TrustPinConfig{})
assert.NoError(t, err) assert.NoError(t, err)
cl, err := notaryRepo.GetChangelist() cl, err := notaryRepo.GetChangelist()
require.NoError(t, err)
assert.Equal(t, len(cl.List()), 0) assert.Equal(t, len(cl.List()), 0)
} }

View File

@ -11,9 +11,8 @@ import (
"github.com/docker/cli/cli" "github.com/docker/cli/cli"
"github.com/docker/cli/cli/command" "github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/formatter" "github.com/docker/cli/cli/command/formatter"
"github.com/docker/cli/cli/command/image"
"github.com/docker/cli/cli/trust" "github.com/docker/cli/cli/trust"
"github.com/docker/docker/api/types"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/notary" "github.com/docker/notary"
"github.com/docker/notary/client" "github.com/docker/notary/client"
"github.com/docker/notary/tuf/data" "github.com/docker/notary/tuf/data"
@ -61,15 +60,12 @@ func newViewCommand(dockerCli command.Cli) *cobra.Command {
func lookupTrustInfo(cli command.Cli, remote string) error { func lookupTrustInfo(cli command.Cli, remote string) error {
ctx := context.Background() ctx := context.Background()
authResolver := func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig { imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, image.AuthResolver(cli), remote)
return command.ResolveAuthConfig(ctx, cli, index)
}
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, authResolver, remote)
if err != nil { if err != nil {
return err return err
} }
tag := imgRefAndAuth.Tag() tag := imgRefAndAuth.Tag()
notaryRepo, err := cli.NotaryClient(*imgRefAndAuth, trust.ActionsPullOnly) notaryRepo, err := cli.NotaryClient(imgRefAndAuth, trust.ActionsPullOnly)
if err != nil { if err != nil {
return trust.NotaryError(imgRefAndAuth.Reference().Name(), err) return trust.NotaryError(imgRefAndAuth.Reference().Name(), err)
} }
@ -113,7 +109,9 @@ func lookupTrustInfo(cli command.Cli, remote string) error {
// If we do not have additional signers, do not display // If we do not have additional signers, do not display
if len(signerRoleToKeyIDs) > 0 { if len(signerRoleToKeyIDs) > 0 {
fmt.Fprintf(cli.Out(), "\nList of signers and their keys for %s:\n\n", strings.Split(remote, ":")[0]) fmt.Fprintf(cli.Out(), "\nList of signers and their keys for %s:\n\n", strings.Split(remote, ":")[0])
printSignerInfo(cli.Out(), signerRoleToKeyIDs) if err := printSignerInfo(cli.Out(), signerRoleToKeyIDs); err != nil {
return err
}
} }
// This will always have the root and targets information // This will always have the root and targets information

View File

@ -1,7 +1,6 @@
package trust package trust
import ( import (
"context"
"encoding/json" "encoding/json"
"io" "io"
"net" "net"
@ -32,6 +31,7 @@ import (
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"golang.org/x/net/context"
) )
var ( var (
@ -288,6 +288,7 @@ func GetSignableRoles(repo client.Repository, target *client.Target) ([]data.Rol
// ImageRefAndAuth contains all reference information and the auth config for an image request // ImageRefAndAuth contains all reference information and the auth config for an image request
type ImageRefAndAuth struct { type ImageRefAndAuth struct {
original string
authConfig *types.AuthConfig authConfig *types.AuthConfig
reference reference.Named reference reference.Named
repoInfo *registry.RepositoryInfo repoInfo *registry.RepositoryInfo
@ -295,27 +296,29 @@ type ImageRefAndAuth struct {
digest digest.Digest digest digest.Digest
} }
// NewImageRefAndAuth creates a new ImageRefAndAuth struct
func NewImageRefAndAuth(authConfig *types.AuthConfig, reference reference.Named, repoInfo *registry.RepositoryInfo, tag string, digest digest.Digest) *ImageRefAndAuth {
return &ImageRefAndAuth{authConfig, reference, repoInfo, tag, digest}
}
// GetImageReferencesAndAuth retrieves the necessary reference and auth information for an image name // GetImageReferencesAndAuth retrieves the necessary reference and auth information for an image name
// as a ImageRefAndAuth struct // as a ImageRefAndAuth struct
func GetImageReferencesAndAuth(ctx context.Context, authResolver func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig, imgName string) (*ImageRefAndAuth, error) { func GetImageReferencesAndAuth(ctx context.Context, authResolver func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig, imgName string) (ImageRefAndAuth, error) {
ref, err := reference.ParseNormalizedNamed(imgName) ref, err := reference.ParseNormalizedNamed(imgName)
if err != nil { if err != nil {
return nil, err return ImageRefAndAuth{}, err
} }
// Resolve the Repository name from fqn to RepositoryInfo // Resolve the Repository name from fqn to RepositoryInfo
repoInfo, err := registry.ParseRepositoryInfo(ref) repoInfo, err := registry.ParseRepositoryInfo(ref)
if err != nil { if err != nil {
return nil, err return ImageRefAndAuth{}, err
} }
authConfig := authResolver(ctx, repoInfo.Index) authConfig := authResolver(ctx, repoInfo.Index)
return NewImageRefAndAuth(&authConfig, ref, repoInfo, getTag(ref), getDigest(ref)), nil return ImageRefAndAuth{
original: imgName,
authConfig: &authConfig,
reference: ref,
repoInfo: repoInfo,
tag: getTag(ref),
digest: getDigest(ref),
}, nil
} }
func getTag(ref reference.Named) string { func getTag(ref reference.Named) string {
@ -364,3 +367,9 @@ func (imgRefAuth *ImageRefAndAuth) Tag() string {
func (imgRefAuth *ImageRefAndAuth) Digest() digest.Digest { func (imgRefAuth *ImageRefAndAuth) Digest() digest.Digest {
return imgRefAuth.digest return imgRefAuth.digest
} }
// Name returns the image name used to initialize the ImageRefAndAuth
func (imgRefAuth *ImageRefAndAuth) Name() string {
return imgRefAuth.original
}

View File

@ -11,6 +11,7 @@ import (
"github.com/docker/notary/trustpinning" "github.com/docker/notary/trustpinning"
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestGetTag(t *testing.T) { func TestGetTag(t *testing.T) {
@ -53,6 +54,7 @@ func TestGetSignableRolesError(t *testing.T) {
defer os.RemoveAll(tmpDir) defer os.RemoveAll(tmpDir)
notaryRepo, err := client.NewFileCachedRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever("password"), trustpinning.TrustPinConfig{}) notaryRepo, err := client.NewFileCachedRepository(tmpDir, "gun", "https://localhost", nil, passphrase.ConstantRetriever("password"), trustpinning.TrustPinConfig{})
require.NoError(t, err)
target := client.Target{} target := client.Target{}
_, err = GetSignableRoles(notaryRepo, &target) _, err = GetSignableRoles(notaryRepo, &target)
assert.EqualError(t, err, "client is offline") assert.EqualError(t, err, "client is offline")

View File

@ -2,7 +2,7 @@ FROM golang:1.8.3-alpine
RUN apk add -U git RUN apk add -U git
ARG GOMETALINTER_SHA=4306381615a2ba2a207f8fcea02c08c6b2b0803f ARG GOMETALINTER_SHA=8eca55135021737bbc65ed68b548b3336853274c
RUN go get -d github.com/alecthomas/gometalinter && \ RUN go get -d github.com/alecthomas/gometalinter && \
cd /go/src/github.com/alecthomas/gometalinter && \ cd /go/src/github.com/alecthomas/gometalinter && \
git checkout -q "$GOMETALINTER_SHA" && \ git checkout -q "$GOMETALINTER_SHA" && \

View File

@ -10,7 +10,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
) )
type cmdOption struct { type cmdOption struct {
@ -46,18 +46,17 @@ type cmdDoc struct {
// GenYamlTree creates yaml structured ref files // GenYamlTree creates yaml structured ref files
func GenYamlTree(cmd *cobra.Command, dir string) error { func GenYamlTree(cmd *cobra.Command, dir string) error {
identity := func(s string) string { return s }
emptyStr := func(s string) string { return "" } emptyStr := func(s string) string { return "" }
return GenYamlTreeCustom(cmd, dir, emptyStr, identity) return GenYamlTreeCustom(cmd, dir, emptyStr)
} }
// GenYamlTreeCustom creates yaml structured ref files // GenYamlTreeCustom creates yaml structured ref files
func GenYamlTreeCustom(cmd *cobra.Command, dir string, filePrepender, linkHandler func(string) string) error { func GenYamlTreeCustom(cmd *cobra.Command, dir string, filePrepender func(string) string) error {
for _, c := range cmd.Commands() { for _, c := range cmd.Commands() {
if !c.IsAvailableCommand() || c.IsHelpCommand() { if !c.IsAvailableCommand() || c.IsHelpCommand() {
continue continue
} }
if err := GenYamlTreeCustom(c, dir, filePrepender, linkHandler); err != nil { if err := GenYamlTreeCustom(c, dir, filePrepender); err != nil {
return err return err
} }
} }

View File

@ -1,8 +1,12 @@
{ {
"Vendor": true, "Vendor": true,
"Deadline": "2m", "Deadline": "2m",
"Sort": ["linter", "severity", "path"], "Sort": ["linter", "severity", "path", "line"],
"Exclude": ["cli/compose/schema/bindata.go"], "Exclude": [
"cli/compose/schema/bindata.go",
"parameter .* always receives"
],
"EnableGC": true,
"DisableAll": true, "DisableAll": true,
"Enable": [ "Enable": [
@ -22,6 +26,6 @@
"vet" "vet"
], ],
"Cyclo": 19, "Cyclo": 16,
"LineLength": 200 "LineLength": 200
} }