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"
"github.com/docker/cli/cli/trust"
dopts "github.com/docker/cli/opts"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api"
"github.com/docker/docker/client"
"github.com/docker/docker/registry"
"github.com/docker/go-connections/sockets"
"github.com/docker/go-connections/tlsconfig"
"github.com/docker/notary"
notaryclient "github.com/docker/notary/client"
"github.com/docker/notary/passphrase"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"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...)
}
// 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
// server
type ServerInfo struct {

View File

@ -9,7 +9,6 @@ import (
"github.com/docker/cli/cli/config/configfile"
"github.com/docker/cli/cli/flags"
"github.com/docker/cli/internal/test/testutil"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api"
"github.com/docker/docker/api/types"
"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},
}
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) {
filteredTargets := []*client.TargetWithRole{}
for _, tgt := range loadedTargets {

View File

@ -12,6 +12,8 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/formatter"
"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/client"
"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 {
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 {
return err
}

View File

@ -12,6 +12,7 @@ import (
"github.com/docker/notary"
"github.com/docker/notary/client"
"github.com/docker/notary/tuf/data"
"github.com/gotestyourself/gotestyourself/golden"
"github.com/stretchr/testify/assert"
)
@ -113,15 +114,7 @@ func TestTrustInspectCommandFullRepoWithoutSigners(t *testing.T) {
cmd.SetArgs([]string{"signed-repo"})
assert.NoError(t, cmd.Execute())
// Check for the signed tag headers
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:")
golden.Assert(t, cli.OutBuffer().String(), "trust-inspect-full-repo-no-signers.golden")
}
func TestTrustInspectCommandOneTagWithoutSigners(t *testing.T) {
@ -130,19 +123,8 @@ func TestTrustInspectCommandOneTagWithoutSigners(t *testing.T) {
cmd := newInspectCommand(cli)
cmd.SetArgs([]string{"signed-repo:green"})
assert.NoError(t, cmd.Execute())
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:")
// 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:")
golden.Assert(t, cli.OutBuffer().String(), "trust-inspect-one-tag-no-signers.golden")
}
func TestTrustInspectCommandFullRepoWithSigners(t *testing.T) {
@ -152,21 +134,7 @@ func TestTrustInspectCommandFullRepoWithSigners(t *testing.T) {
cmd.SetArgs([]string{"signed-repo"})
assert.NoError(t, cmd.Execute())
// Check for the signed tag headers and contents
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:")
golden.Assert(t, cli.OutBuffer().String(), "trust-inspect-full-repo-with-signers.golden")
}
func TestTrustInspectCommandUnsignedTagInSignedRepo(t *testing.T) {
@ -176,20 +144,7 @@ func TestTrustInspectCommandUnsignedTagInSignedRepo(t *testing.T) {
cmd.SetArgs([]string{"signed-repo:unsigned"})
assert.NoError(t, cmd.Execute())
// Check that the signatures table does not show up, and instead we get the message
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")
golden.Assert(t, cli.OutBuffer().String(), "trust-inspect-unsigned-tag-with-signers.golden")
}
func TestNotaryRoleToSigner(t *testing.T) {

View File

@ -5,6 +5,8 @@ import (
"fmt"
"os"
"github.com/docker/docker/api/types"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/notary/client"
"github.com/docker/notary/tuf/data"
"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 {
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 {
return err
}

View File

@ -11,6 +11,8 @@ import (
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/image"
"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/tuf/data"
"github.com/pkg/errors"
@ -31,7 +33,10 @@ func newSignCommand(dockerCli command.Cli) *cobra.Command {
func signImage(cli command.Cli, imageName string) error {
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 {
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
import (
"context"
"encoding/json"
"io"
"net"
@ -299,6 +300,46 @@ func NewImageRefAndAuth(authConfig *types.AuthConfig, reference reference.Named,
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
func (imgRefAuth *ImageRefAndAuth) AuthConfig() *types.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)
}