trust: update reference type and use golden output

Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
This commit is contained in:
Riyaz Faizullabhoy 2017-09-14 14:58:28 -07:00
parent 6fca400f1e
commit 4e89dc800a
13 changed files with 167 additions and 115 deletions

View File

@ -14,16 +14,13 @@ import (
cliflags "github.com/docker/cli/cli/flags" cliflags "github.com/docker/cli/cli/flags"
"github.com/docker/cli/cli/trust" "github.com/docker/cli/cli/trust"
dopts "github.com/docker/cli/opts" dopts "github.com/docker/cli/opts"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api" "github.com/docker/docker/api"
"github.com/docker/docker/client" "github.com/docker/docker/client"
"github.com/docker/docker/registry"
"github.com/docker/go-connections/sockets" "github.com/docker/go-connections/sockets"
"github.com/docker/go-connections/tlsconfig" "github.com/docker/go-connections/tlsconfig"
"github.com/docker/notary" "github.com/docker/notary"
notaryclient "github.com/docker/notary/client" notaryclient "github.com/docker/notary/client"
"github.com/docker/notary/passphrase" "github.com/docker/notary/passphrase"
digest "github.com/opencontainers/go-digest"
"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"
@ -172,46 +169,6 @@ func (cli *DockerCli) NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions
return trust.GetNotaryRepository(cli.In(), cli.Out(), UserAgent(), imgRefAndAuth.RepoInfo(), imgRefAndAuth.AuthConfig(), actions...) return trust.GetNotaryRepository(cli.In(), cli.Out(), UserAgent(), imgRefAndAuth.RepoInfo(), imgRefAndAuth.AuthConfig(), actions...)
} }
// GetImageReferencesAndAuth retrieves the necessary reference and auth information for an image name
// as a ImageRefAndAuth struct
func GetImageReferencesAndAuth(ctx context.Context, cli Cli, imgName string) (*trust.ImageRefAndAuth, error) {
ref, err := reference.ParseNormalizedNamed(imgName)
if err != nil {
return nil, err
}
// Resolve the Repository name from fqn to RepositoryInfo
repoInfo, err := registry.ParseRepositoryInfo(ref)
if err != nil {
return nil, err
}
authConfig := ResolveAuthConfig(ctx, cli, repoInfo.Index)
return trust.NewImageRefAndAuth(&authConfig, ref, repoInfo, getTag(ref), getDigest(ref)), nil
}
func getTag(ref reference.Named) string {
switch x := ref.(type) {
case reference.Canonical, reference.Digested:
return ""
case reference.NamedTagged:
return x.Tag()
default:
return ""
}
}
func getDigest(ref reference.Named) digest.Digest {
switch x := ref.(type) {
case reference.Canonical:
return x.Digest()
case reference.Digested:
return x.Digest()
default:
return digest.Digest("")
}
}
// ServerInfo stores details about the supported features and platform of the // ServerInfo stores details about the supported features and platform of the
// server // server
type ServerInfo struct { type ServerInfo struct {

View File

@ -9,7 +9,6 @@ import (
"github.com/docker/cli/cli/config/configfile" "github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/flags" "github.com/docker/cli/cli/flags"
"github.com/docker/cli/internal/test/testutil" "github.com/docker/cli/internal/test/testutil"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api" "github.com/docker/docker/api"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/client" "github.com/docker/docker/client"
@ -197,20 +196,3 @@ func TestGetClientWithPassword(t *testing.T) {
}) })
} }
} }
func TestGetTag(t *testing.T) {
ref, err := reference.ParseNormalizedNamed("ubuntu@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2")
assert.NoError(t, err)
tag := getTag(ref)
assert.Equal(t, "", tag)
ref, err = reference.ParseNormalizedNamed("alpine:latest")
assert.NoError(t, err)
tag = getTag(ref)
assert.Equal(t, tag, "latest")
ref, err = reference.ParseNormalizedNamed("alpine")
assert.NoError(t, err)
tag = getTag(ref)
assert.Equal(t, tag, "")
}

View File

@ -299,6 +299,26 @@ var loadedTargets = []client.TargetSignedStruct{
{Target: loadedGreenTarget, Role: loadedReleasesRole}, {Target: loadedGreenTarget, Role: loadedReleasesRole},
} }
func (l LoadedNotaryRepository) ListRoles() ([]client.RoleWithSignatures, error) {
rootRole := data.Role{
RootRole: data.RootRole{
KeyIDs: []string{"rootID"},
Threshold: 1,
},
Name: data.CanonicalRootRole,
}
targetsRole := data.Role{
RootRole: data.RootRole{
KeyIDs: []string{"targetsID"},
Threshold: 1,
},
Name: data.CanonicalTargetsRole,
}
return []client.RoleWithSignatures{{Role: rootRole}, {Role: targetsRole}}, nil
}
func (l LoadedNotaryRepository) ListTargets(roles ...data.RoleName) ([]*client.TargetWithRole, error) { func (l LoadedNotaryRepository) ListTargets(roles ...data.RoleName) ([]*client.TargetWithRole, error) {
filteredTargets := []*client.TargetWithRole{} filteredTargets := []*client.TargetWithRole{}
for _, tgt := range loadedTargets { for _, tgt := range loadedTargets {

View File

@ -12,6 +12,8 @@ import (
"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/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"
@ -59,7 +61,10 @@ func newInspectCommand(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()
imgRefAndAuth, err := command.GetImageReferencesAndAuth(ctx, cli, remote) authResolver := func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig {
return command.ResolveAuthConfig(ctx, cli, index)
}
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, authResolver, remote)
if err != nil { if err != nil {
return err return err
} }

View File

@ -12,6 +12,7 @@ import (
"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"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -113,15 +114,7 @@ func TestTrustInspectCommandFullRepoWithoutSigners(t *testing.T) {
cmd.SetArgs([]string{"signed-repo"}) cmd.SetArgs([]string{"signed-repo"})
assert.NoError(t, cmd.Execute()) assert.NoError(t, cmd.Execute())
// Check for the signed tag headers golden.Assert(t, cli.OutBuffer().String(), "trust-inspect-full-repo-no-signers.golden")
assert.Contains(t, cli.OutBuffer().String(), "SIGNED TAG")
assert.Contains(t, cli.OutBuffer().String(), "DIGEST")
assert.Contains(t, cli.OutBuffer().String(), "SIGNERS")
// Check for the signer headers
assert.Contains(t, cli.OutBuffer().String(), "Administrative keys for signed-repo:")
assert.Contains(t, cli.OutBuffer().String(), "(Repo Admin)")
// no delegations on this repo
assert.NotContains(t, cli.OutBuffer().String(), "List of signers and their keys:")
} }
func TestTrustInspectCommandOneTagWithoutSigners(t *testing.T) { func TestTrustInspectCommandOneTagWithoutSigners(t *testing.T) {
@ -130,19 +123,8 @@ func TestTrustInspectCommandOneTagWithoutSigners(t *testing.T) {
cmd := newInspectCommand(cli) cmd := newInspectCommand(cli)
cmd.SetArgs([]string{"signed-repo:green"}) cmd.SetArgs([]string{"signed-repo:green"})
assert.NoError(t, cmd.Execute()) assert.NoError(t, cmd.Execute())
assert.Contains(t, cli.OutBuffer().String(), "SIGNED TAG")
assert.Contains(t, cli.OutBuffer().String(), "DIGEST") golden.Assert(t, cli.OutBuffer().String(), "trust-inspect-one-tag-no-signers.golden")
assert.Contains(t, cli.OutBuffer().String(), "SIGNERS")
// Check for the signer headers
assert.Contains(t, cli.OutBuffer().String(), "Administrative keys for signed-repo:")
// make sure the tag isn't included
assert.NotContains(t, cli.OutBuffer().String(), "Administrative keys for signed-repo:green")
assert.Contains(t, cli.OutBuffer().String(), "green")
assert.Contains(t, cli.OutBuffer().String(), "(Repo Admin)")
// no delegations on this repo
assert.NotContains(t, cli.OutBuffer().String(), "alice")
assert.NotContains(t, cli.OutBuffer().String(), "bob")
assert.NotContains(t, cli.OutBuffer().String(), "List of signers and their keys:")
} }
func TestTrustInspectCommandFullRepoWithSigners(t *testing.T) { func TestTrustInspectCommandFullRepoWithSigners(t *testing.T) {
@ -152,21 +134,7 @@ func TestTrustInspectCommandFullRepoWithSigners(t *testing.T) {
cmd.SetArgs([]string{"signed-repo"}) cmd.SetArgs([]string{"signed-repo"})
assert.NoError(t, cmd.Execute()) assert.NoError(t, cmd.Execute())
// Check for the signed tag headers and contents golden.Assert(t, cli.OutBuffer().String(), "trust-inspect-full-repo-with-signers.golden")
assert.Contains(t, cli.OutBuffer().String(), "SIGNED TAG")
assert.Contains(t, cli.OutBuffer().String(), "DIGEST")
assert.Contains(t, cli.OutBuffer().String(), "SIGNERS")
assert.Contains(t, cli.OutBuffer().String(), "blue 626c75652d646967657374 alice")
assert.Contains(t, cli.OutBuffer().String(), "green 677265656e2d646967657374 (Repo Admin)")
assert.Contains(t, cli.OutBuffer().String(), "red 7265642d646967657374 alice, bob")
// Check for the signer headers and contents
assert.Contains(t, cli.OutBuffer().String(), "List of signers and their keys:")
assert.Contains(t, cli.OutBuffer().String(), "SIGNER")
assert.Contains(t, cli.OutBuffer().String(), "KEYS")
assert.Contains(t, cli.OutBuffer().String(), "alice A")
assert.Contains(t, cli.OutBuffer().String(), "bob B")
assert.Contains(t, cli.OutBuffer().String(), "Administrative keys for signed-repo:")
} }
func TestTrustInspectCommandUnsignedTagInSignedRepo(t *testing.T) { func TestTrustInspectCommandUnsignedTagInSignedRepo(t *testing.T) {
@ -176,20 +144,7 @@ func TestTrustInspectCommandUnsignedTagInSignedRepo(t *testing.T) {
cmd.SetArgs([]string{"signed-repo:unsigned"}) cmd.SetArgs([]string{"signed-repo:unsigned"})
assert.NoError(t, cmd.Execute()) assert.NoError(t, cmd.Execute())
// Check that the signatures table does not show up, and instead we get the message golden.Assert(t, cli.OutBuffer().String(), "trust-inspect-unsigned-tag-with-signers.golden")
assert.Contains(t, cli.OutBuffer().String(), "No signatures for signed-repo:unsigned")
assert.NotContains(t, cli.OutBuffer().String(), "SIGNED TAG")
assert.NotContains(t, cli.OutBuffer().String(), "DIGEST")
assert.NotContains(t, cli.OutBuffer().String(), "SIGNERS")
// Check for the signer headers and contents
assert.Contains(t, cli.OutBuffer().String(), "List of signers and their keys:")
assert.Contains(t, cli.OutBuffer().String(), "SIGNER")
assert.Contains(t, cli.OutBuffer().String(), "KEYS")
assert.Contains(t, cli.OutBuffer().String(), "alice A")
assert.Contains(t, cli.OutBuffer().String(), "bob B")
assert.Contains(t, cli.OutBuffer().String(), "Administrative keys for signed-repo:")
assert.NotContains(t, cli.OutBuffer().String(), "Administrative keys for signed-repo:unsigned")
} }
func TestNotaryRoleToSigner(t *testing.T) { func TestNotaryRoleToSigner(t *testing.T) {

View File

@ -5,6 +5,8 @@ import (
"fmt" "fmt"
"os" "os"
"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"
@ -36,7 +38,10 @@ 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()
imgRefAndAuth, err := command.GetImageReferencesAndAuth(ctx, cli, remote) authResolver := func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig {
return command.ResolveAuthConfig(ctx, cli, index)
}
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, authResolver, remote)
if err != nil { if err != nil {
return err return err
} }

View File

@ -11,6 +11,8 @@ 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"
@ -31,7 +33,10 @@ func newSignCommand(dockerCli command.Cli) *cobra.Command {
func signImage(cli command.Cli, imageName string) error { func signImage(cli command.Cli, imageName string) error {
ctx := context.Background() ctx := context.Background()
imgRefAndAuth, err := command.GetImageReferencesAndAuth(ctx, cli, imageName) authResolver := func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig {
return command.ResolveAuthConfig(ctx, cli, index)
}
imgRefAndAuth, err := trust.GetImageReferencesAndAuth(ctx, authResolver, imageName)
if err != nil { if err != nil {
return err return err
} }

View File

@ -0,0 +1,6 @@
SIGNED TAG DIGEST SIGNERS
green 677265656e2d646967657374 (Repo Admin)
Administrative keys for signed-repo:
Repository Key: targetsID
Root Key: rootID

View File

@ -0,0 +1,14 @@
SIGNED TAG DIGEST SIGNERS
blue 626c75652d646967657374 alice
green 677265656e2d646967657374 (Repo Admin)
red 7265642d646967657374 alice, bob
List of signers and their keys:
SIGNER KEYS
alice A
bob B
Administrative keys for signed-repo:
Repository Key: targetsID
Root Key: rootID

View File

@ -0,0 +1,6 @@
SIGNED TAG DIGEST SIGNERS
green 677265656e2d646967657374 (Repo Admin)
Administrative keys for signed-repo:
Repository Key: targetsID
Root Key: rootID

View File

@ -0,0 +1,13 @@
No signatures for signed-repo:unsigned
List of signers and their keys:
SIGNER KEYS
alice A
bob B
Administrative keys for signed-repo:
Repository Key: targetsID
Root Key: rootID

View File

@ -1,6 +1,7 @@
package trust package trust
import ( import (
"context"
"encoding/json" "encoding/json"
"io" "io"
"net" "net"
@ -299,6 +300,46 @@ func NewImageRefAndAuth(authConfig *types.AuthConfig, reference reference.Named,
return &ImageRefAndAuth{authConfig, reference, repoInfo, tag, digest} return &ImageRefAndAuth{authConfig, reference, repoInfo, tag, digest}
} }
// GetImageReferencesAndAuth retrieves the necessary reference and auth information for an image name
// as a ImageRefAndAuth struct
func GetImageReferencesAndAuth(ctx context.Context, authResolver func(ctx context.Context, index *registrytypes.IndexInfo) types.AuthConfig, imgName string) (*ImageRefAndAuth, error) {
ref, err := reference.ParseNormalizedNamed(imgName)
if err != nil {
return nil, err
}
// Resolve the Repository name from fqn to RepositoryInfo
repoInfo, err := registry.ParseRepositoryInfo(ref)
if err != nil {
return nil, err
}
authConfig := authResolver(ctx, repoInfo.Index)
return NewImageRefAndAuth(&authConfig, ref, repoInfo, getTag(ref), getDigest(ref)), nil
}
func getTag(ref reference.Named) string {
switch x := ref.(type) {
case reference.Canonical, reference.Digested:
return ""
case reference.NamedTagged:
return x.Tag()
default:
return ""
}
}
func getDigest(ref reference.Named) digest.Digest {
switch x := ref.(type) {
case reference.Canonical:
return x.Digest()
case reference.Digested:
return x.Digest()
default:
return digest.Digest("")
}
}
// AuthConfig returns the auth information (username, etc) for a given ImageRefAndAuth // AuthConfig returns the auth information (username, etc) for a given ImageRefAndAuth
func (imgRefAuth *ImageRefAndAuth) AuthConfig() *types.AuthConfig { func (imgRefAuth *ImageRefAndAuth) AuthConfig() *types.AuthConfig {
return imgRefAuth.authConfig return imgRefAuth.authConfig

43
cli/trust/trust_test.go Normal file
View File

@ -0,0 +1,43 @@
package trust
import (
"testing"
"github.com/docker/distribution/reference"
digest "github.com/opencontainers/go-digest"
"github.com/stretchr/testify/assert"
)
func TestGetTag(t *testing.T) {
ref, err := reference.ParseNormalizedNamed("ubuntu@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2")
assert.NoError(t, err)
tag := getTag(ref)
assert.Equal(t, "", tag)
ref, err = reference.ParseNormalizedNamed("alpine:latest")
assert.NoError(t, err)
tag = getTag(ref)
assert.Equal(t, tag, "latest")
ref, err = reference.ParseNormalizedNamed("alpine")
assert.NoError(t, err)
tag = getTag(ref)
assert.Equal(t, tag, "")
}
func TestGetDigest(t *testing.T) {
ref, err := reference.ParseNormalizedNamed("ubuntu@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2")
assert.NoError(t, err)
d := getDigest(ref)
assert.Equal(t, digest.Digest("sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2"), d)
ref, err = reference.ParseNormalizedNamed("alpine:latest")
assert.NoError(t, err)
d = getDigest(ref)
assert.Equal(t, digest.Digest(""), d)
ref, err = reference.ParseNormalizedNamed("alpine")
assert.NoError(t, err)
d = getDigest(ref)
assert.Equal(t, digest.Digest(""), d)
}