mirror of https://github.com/docker/cli.git
trust: update reference type and use golden output
Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
This commit is contained in:
parent
6fca400f1e
commit
4e89dc800a
|
@ -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 {
|
||||
|
|
|
@ -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, "")
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
SIGNED TAG DIGEST SIGNERS
|
||||
green 677265656e2d646967657374 (Repo Admin)
|
||||
|
||||
Administrative keys for signed-repo:
|
||||
Repository Key: targetsID
|
||||
Root Key: rootID
|
|
@ -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
|
|
@ -0,0 +1,6 @@
|
|||
SIGNED TAG DIGEST SIGNERS
|
||||
green 677265656e2d646967657374 (Repo Admin)
|
||||
|
||||
Administrative keys for signed-repo:
|
||||
Repository Key: targetsID
|
||||
Root Key: rootID
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
Loading…
Reference in New Issue