mirror of https://github.com/docker/cli.git
trust: use mock CLI for testing offline
Signed-off-by: Riyaz Faizullabhoy <riyaz.faizullabhoy@docker.com>
This commit is contained in:
parent
e5c35ab9d1
commit
f667bd7559
|
@ -0,0 +1,108 @@
|
||||||
|
package trust
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/docker/cli/cli/command"
|
||||||
|
"github.com/docker/cli/cli/config/configfile"
|
||||||
|
"github.com/docker/cli/cli/trust"
|
||||||
|
"github.com/docker/docker/client"
|
||||||
|
notaryclient "github.com/docker/notary/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
type notaryClientFuncType func(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error)
|
||||||
|
|
||||||
|
// FakeCli emulates the default DockerCli
|
||||||
|
type FakeCli struct {
|
||||||
|
command.DockerCli
|
||||||
|
client client.APIClient
|
||||||
|
configfile *configfile.ConfigFile
|
||||||
|
out *command.OutStream
|
||||||
|
outBuffer *bytes.Buffer
|
||||||
|
err *bytes.Buffer
|
||||||
|
in *command.InStream
|
||||||
|
server command.ServerInfo
|
||||||
|
notaryClientFunc notaryClientFuncType
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFakeCliWithNotaryClient returns a fake for the command.Cli interface with a specified Notary Client
|
||||||
|
func NewFakeCliWithNotaryClient(client client.APIClient, notaryClientFunc notaryClientFuncType) *FakeCli {
|
||||||
|
outBuffer := new(bytes.Buffer)
|
||||||
|
errBuffer := new(bytes.Buffer)
|
||||||
|
return &FakeCli{
|
||||||
|
client: client,
|
||||||
|
out: command.NewOutStream(outBuffer),
|
||||||
|
outBuffer: outBuffer,
|
||||||
|
err: errBuffer,
|
||||||
|
in: command.NewInStream(ioutil.NopCloser(strings.NewReader(""))),
|
||||||
|
configfile: configfile.New("configfile"),
|
||||||
|
notaryClientFunc: notaryClientFunc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetIn sets the input of the cli to the specified ReadCloser
|
||||||
|
func (c *FakeCli) SetIn(in *command.InStream) {
|
||||||
|
c.in = in
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetErr sets the stderr stream for the cli to the specified io.Writer
|
||||||
|
func (c *FakeCli) SetErr(err *bytes.Buffer) {
|
||||||
|
c.err = err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetConfigFile sets the "fake" config file
|
||||||
|
func (c *FakeCli) SetConfigFile(configfile *configfile.ConfigFile) {
|
||||||
|
c.configfile = configfile
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client returns a docker API client
|
||||||
|
func (c *FakeCli) Client() client.APIClient {
|
||||||
|
return c.client
|
||||||
|
}
|
||||||
|
|
||||||
|
// Out returns the output stream (stdout) the cli should write on
|
||||||
|
func (c *FakeCli) Out() *command.OutStream {
|
||||||
|
return c.out
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err returns the output stream (stderr) the cli should write on
|
||||||
|
func (c *FakeCli) Err() io.Writer {
|
||||||
|
return c.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// In returns the input stream the cli will use
|
||||||
|
func (c *FakeCli) In() *command.InStream {
|
||||||
|
return c.in
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConfigFile returns the cli configfile object (to get client configuration)
|
||||||
|
func (c *FakeCli) ConfigFile() *configfile.ConfigFile {
|
||||||
|
return c.configfile
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerInfo returns API server information for the server used by this client
|
||||||
|
func (c *FakeCli) ServerInfo() command.ServerInfo {
|
||||||
|
return c.server
|
||||||
|
}
|
||||||
|
|
||||||
|
// OutBuffer returns the stdout buffer
|
||||||
|
func (c *FakeCli) OutBuffer() *bytes.Buffer {
|
||||||
|
return c.outBuffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrBuffer Buffer returns the stderr buffer
|
||||||
|
func (c *FakeCli) ErrBuffer() *bytes.Buffer {
|
||||||
|
return c.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotaryClient returns an err for testing unless defined
|
||||||
|
func (c *FakeCli) NotaryClient(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (notaryclient.Repository, error) {
|
||||||
|
if c.notaryClientFunc != nil {
|
||||||
|
return c.notaryClientFunc(imgRefAndAuth, actions)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("no notary client available unless defined")
|
||||||
|
}
|
|
@ -11,7 +11,10 @@ import (
|
||||||
dockerClient "github.com/docker/docker/client"
|
dockerClient "github.com/docker/docker/client"
|
||||||
"github.com/docker/notary"
|
"github.com/docker/notary"
|
||||||
"github.com/docker/notary/client"
|
"github.com/docker/notary/client"
|
||||||
|
"github.com/docker/notary/client/changelist"
|
||||||
|
"github.com/docker/notary/storage"
|
||||||
"github.com/docker/notary/tuf/data"
|
"github.com/docker/notary/tuf/data"
|
||||||
|
"github.com/docker/notary/tuf/signed"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -39,26 +42,11 @@ func TestTrustInspectCommandErrors(t *testing.T) {
|
||||||
args: []string{"870d292919d01a0af7e7f056271dc78792c05f55f49b9b9012b6d89725bd9abd"},
|
args: []string{"870d292919d01a0af7e7f056271dc78792c05f55f49b9b9012b6d89725bd9abd"},
|
||||||
expectedError: "invalid repository name",
|
expectedError: "invalid repository name",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "nonexistent-reg",
|
|
||||||
args: []string{"nonexistent-reg-name.io/image"},
|
|
||||||
expectedError: "No signatures or cannot access nonexistent-reg-name.io/image",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "invalid-img-reference",
|
name: "invalid-img-reference",
|
||||||
args: []string{"ALPINE"},
|
args: []string{"ALPINE"},
|
||||||
expectedError: "invalid reference format",
|
expectedError: "invalid reference format",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "unsigned-img-reference",
|
|
||||||
args: []string{"riyaz/unsigned-img"},
|
|
||||||
expectedError: "No signatures or cannot access riyaz/unsigned-img",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "nonexistent-img-reference",
|
|
||||||
args: []string{"riyaz/nonexistent-img"},
|
|
||||||
expectedError: "No signatures or cannot access riyaz/nonexistent-img",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
cmd := newInspectCommand(
|
cmd := newInspectCommand(
|
||||||
|
@ -69,6 +57,52 @@ func TestTrustInspectCommandErrors(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTrustInspectCommandOfflineErrors(t *testing.T) {
|
||||||
|
cli := NewFakeCliWithNotaryClient(&fakeClient{}, getOfflineNotaryRepository)
|
||||||
|
cmd := newInspectCommand(cli)
|
||||||
|
cmd.SetArgs([]string{"nonexistent-reg-name.io/image"})
|
||||||
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
testutil.ErrorContains(t, cmd.Execute(), "No signatures or cannot access nonexistent-reg-name.io/image")
|
||||||
|
|
||||||
|
cli = NewFakeCliWithNotaryClient(&fakeClient{}, getOfflineNotaryRepository)
|
||||||
|
cmd = newInspectCommand(cli)
|
||||||
|
cmd.SetArgs([]string{"nonexistent-reg-name.io/image:tag"})
|
||||||
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
testutil.ErrorContains(t, cmd.Execute(), "No signatures or cannot access nonexistent-reg-name.io/image")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTrustInspectCommandUninitializedErrors(t *testing.T) {
|
||||||
|
cli := NewFakeCliWithNotaryClient(&fakeClient{}, getUninitializedNotaryRepository)
|
||||||
|
cmd := newInspectCommand(cli)
|
||||||
|
cmd.SetArgs([]string{"reg/unsigned-img"})
|
||||||
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
testutil.ErrorContains(t, cmd.Execute(), "No signatures or cannot access reg/unsigned-img")
|
||||||
|
|
||||||
|
cli = NewFakeCliWithNotaryClient(&fakeClient{}, getUninitializedNotaryRepository)
|
||||||
|
cmd = newInspectCommand(cli)
|
||||||
|
cmd.SetArgs([]string{"reg/unsigned-img:tag"})
|
||||||
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
testutil.ErrorContains(t, cmd.Execute(), "No signatures or cannot access reg/unsigned-img:tag")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTrustInspectCommandEmptyNotaryRepoErrors(t *testing.T) {
|
||||||
|
cli := NewFakeCliWithNotaryClient(&fakeClient{}, getEmptyTargetsNotaryRepository)
|
||||||
|
cmd := newInspectCommand(cli)
|
||||||
|
cmd.SetArgs([]string{"reg/img:unsigned-tag"})
|
||||||
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
assert.NoError(t, cmd.Execute())
|
||||||
|
assert.Contains(t, cli.OutBuffer().String(), "No signatures for reg/img:unsigned-tag")
|
||||||
|
assert.Contains(t, cli.OutBuffer().String(), "Administrative keys for reg/img:")
|
||||||
|
|
||||||
|
cli = NewFakeCliWithNotaryClient(&fakeClient{}, getEmptyTargetsNotaryRepository)
|
||||||
|
cmd = newInspectCommand(cli)
|
||||||
|
cmd.SetArgs([]string{"reg/img"})
|
||||||
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
assert.NoError(t, cmd.Execute())
|
||||||
|
assert.Contains(t, cli.OutBuffer().String(), "No signatures for reg/img")
|
||||||
|
assert.Contains(t, cli.OutBuffer().String(), "Administrative keys for reg/img:")
|
||||||
|
}
|
||||||
|
|
||||||
func TestTrustInspectCommandFullRepoWithoutSigners(t *testing.T) {
|
func TestTrustInspectCommandFullRepoWithoutSigners(t *testing.T) {
|
||||||
cli := test.NewFakeCli(&fakeClient{})
|
cli := test.NewFakeCli(&fakeClient{})
|
||||||
cmd := newInspectCommand(cli)
|
cmd := newInspectCommand(cli)
|
||||||
|
@ -434,3 +468,194 @@ func TestFormatAdminRole(t *testing.T) {
|
||||||
targetsRoleWithSigs := client.RoleWithSignatures{Role: targetsRole, Signatures: nil}
|
targetsRoleWithSigs := client.RoleWithSignatures{Role: targetsRole, Signatures: nil}
|
||||||
assert.Equal(t, "Repository Key:\tabc, key11, key99\n", formatAdminRole(targetsRoleWithSigs))
|
assert.Equal(t, "Repository Key:\tabc, key11, key99\n", formatAdminRole(targetsRoleWithSigs))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sample mock CLI interfaces
|
||||||
|
|
||||||
|
func getOfflineNotaryRepository(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (client.Repository, error) {
|
||||||
|
return OfflineNotaryRepository{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OfflineNotaryRepository is a mock Notary repository that is offline
|
||||||
|
type OfflineNotaryRepository struct{}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) Initialize(rootKeyIDs []string, serverManagedRoles ...data.RoleName) error {
|
||||||
|
return storage.ErrOffline{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) InitializeWithCertificate(rootKeyIDs []string, rootCerts []data.PublicKey, serverManagedRoles ...data.RoleName) error {
|
||||||
|
return storage.ErrOffline{}
|
||||||
|
}
|
||||||
|
func (o OfflineNotaryRepository) Publish() error {
|
||||||
|
return storage.ErrOffline{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) AddTarget(target *client.Target, roles ...data.RoleName) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (o OfflineNotaryRepository) RemoveTarget(targetName string, roles ...data.RoleName) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (o OfflineNotaryRepository) ListTargets(roles ...data.RoleName) ([]*client.TargetWithRole, error) {
|
||||||
|
return nil, storage.ErrOffline{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) GetTargetByName(name string, roles ...data.RoleName) (*client.TargetWithRole, error) {
|
||||||
|
return nil, storage.ErrOffline{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) GetAllTargetMetadataByName(name string) ([]client.TargetSignedStruct, error) {
|
||||||
|
return nil, storage.ErrOffline{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) GetChangelist() (changelist.Changelist, error) {
|
||||||
|
return changelist.NewMemChangelist(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) ListRoles() ([]client.RoleWithSignatures, error) {
|
||||||
|
return nil, storage.ErrOffline{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) GetDelegationRoles() ([]data.Role, error) {
|
||||||
|
return nil, storage.ErrOffline{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) AddDelegation(name data.RoleName, delegationKeys []data.PublicKey, paths []string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) AddDelegationRoleAndKeys(name data.RoleName, delegationKeys []data.PublicKey) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) AddDelegationPaths(name data.RoleName, paths []string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) RemoveDelegationKeysAndPaths(name data.RoleName, keyIDs, paths []string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) RemoveDelegationRole(name data.RoleName) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) RemoveDelegationPaths(name data.RoleName, paths []string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) RemoveDelegationKeys(name data.RoleName, keyIDs []string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) ClearDelegationPaths(name data.RoleName) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) Witness(roles ...data.RoleName) ([]data.RoleName, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) RotateKey(role data.RoleName, serverManagesKey bool, keyList []string) error {
|
||||||
|
return storage.ErrOffline{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) GetCryptoService() signed.CryptoService {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) SetLegacyVersions(version int) {}
|
||||||
|
|
||||||
|
func (o OfflineNotaryRepository) GetGUN() data.GUN {
|
||||||
|
return data.GUN("gun")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUninitializedNotaryRepository(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (client.Repository, error) {
|
||||||
|
return UninitializedNotaryRepository{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UninitializedNotaryRepository is a mock Notary repository that is uninintialized
|
||||||
|
// it builds on top of the OfflineNotaryRepository, instead returning ErrRepoNotInitialized
|
||||||
|
// for any online operation
|
||||||
|
type UninitializedNotaryRepository struct {
|
||||||
|
OfflineNotaryRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UninitializedNotaryRepository) Initialize(rootKeyIDs []string, serverManagedRoles ...data.RoleName) error {
|
||||||
|
return client.ErrRepositoryNotExist{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UninitializedNotaryRepository) InitializeWithCertificate(rootKeyIDs []string, rootCerts []data.PublicKey, serverManagedRoles ...data.RoleName) error {
|
||||||
|
return client.ErrRepositoryNotExist{}
|
||||||
|
}
|
||||||
|
func (u UninitializedNotaryRepository) Publish() error {
|
||||||
|
return client.ErrRepositoryNotExist{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UninitializedNotaryRepository) ListTargets(roles ...data.RoleName) ([]*client.TargetWithRole, error) {
|
||||||
|
return nil, client.ErrRepositoryNotExist{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UninitializedNotaryRepository) GetTargetByName(name string, roles ...data.RoleName) (*client.TargetWithRole, error) {
|
||||||
|
return nil, client.ErrRepositoryNotExist{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UninitializedNotaryRepository) GetAllTargetMetadataByName(name string) ([]client.TargetSignedStruct, error) {
|
||||||
|
return nil, client.ErrRepositoryNotExist{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UninitializedNotaryRepository) ListRoles() ([]client.RoleWithSignatures, error) {
|
||||||
|
return nil, client.ErrRepositoryNotExist{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UninitializedNotaryRepository) GetDelegationRoles() ([]data.Role, error) {
|
||||||
|
return nil, client.ErrRepositoryNotExist{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UninitializedNotaryRepository) RotateKey(role data.RoleName, serverManagesKey bool, keyList []string) error {
|
||||||
|
return client.ErrRepositoryNotExist{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEmptyTargetsNotaryRepository(imgRefAndAuth trust.ImageRefAndAuth, actions []string) (client.Repository, error) {
|
||||||
|
return EmptyTargetsNotaryRepository{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmptyTargetsNotaryRepository is a mock Notary repository that is initialized
|
||||||
|
// but does not have any signed targets
|
||||||
|
type EmptyTargetsNotaryRepository struct {
|
||||||
|
OfflineNotaryRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EmptyTargetsNotaryRepository) Initialize(rootKeyIDs []string, serverManagedRoles ...data.RoleName) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EmptyTargetsNotaryRepository) InitializeWithCertificate(rootKeyIDs []string, rootCerts []data.PublicKey, serverManagedRoles ...data.RoleName) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (e EmptyTargetsNotaryRepository) Publish() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EmptyTargetsNotaryRepository) ListTargets(roles ...data.RoleName) ([]*client.TargetWithRole, error) {
|
||||||
|
return []*client.TargetWithRole{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EmptyTargetsNotaryRepository) GetTargetByName(name string, roles ...data.RoleName) (*client.TargetWithRole, error) {
|
||||||
|
return nil, client.ErrNoSuchTarget(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EmptyTargetsNotaryRepository) GetAllTargetMetadataByName(name string) ([]client.TargetSignedStruct, error) {
|
||||||
|
return nil, client.ErrNoSuchTarget(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EmptyTargetsNotaryRepository) ListRoles() ([]client.RoleWithSignatures, error) {
|
||||||
|
return []client.RoleWithSignatures{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EmptyTargetsNotaryRepository) GetDelegationRoles() ([]data.Role, error) {
|
||||||
|
return []data.Role{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EmptyTargetsNotaryRepository) RotateKey(role data.RoleName, serverManagesKey bool, keyList []string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -88,6 +88,10 @@ func revokeSignature(notaryRepo client.Repository, tag string) error {
|
||||||
func revokeSingleSig(notaryRepo client.Repository, tag string) error {
|
func revokeSingleSig(notaryRepo client.Repository, tag string) error {
|
||||||
releasedTargetWithRole, err := notaryRepo.GetTargetByName(tag, trust.ReleasesRole, data.CanonicalTargetsRole)
|
releasedTargetWithRole, err := notaryRepo.GetTargetByName(tag, trust.ReleasesRole, data.CanonicalTargetsRole)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// if we try to remove the target and it doesn't exist, "succeed" silently
|
||||||
|
if _, ok := err.(client.ErrNoSuchTarget); ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
releasedTarget := releasedTargetWithRole.Target
|
releasedTarget := releasedTargetWithRole.Target
|
||||||
|
|
|
@ -3,7 +3,6 @@ package trust
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/cli/internal/test"
|
"github.com/docker/cli/internal/test"
|
||||||
|
@ -34,29 +33,16 @@ func TestTrustRevokeCommandErrors(t *testing.T) {
|
||||||
args: []string{"870d292919d01a0af7e7f056271dc78792c05f55f49b9b9012b6d89725bd9abd"},
|
args: []string{"870d292919d01a0af7e7f056271dc78792c05f55f49b9b9012b6d89725bd9abd"},
|
||||||
expectedError: "invalid repository name",
|
expectedError: "invalid repository name",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "trust-data-for-tag-does-not-exist",
|
|
||||||
args: []string{"alpine:foo"},
|
|
||||||
expectedError: "could not remove signature for alpine:foo: No valid trust data for foo",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "invalid-img-reference",
|
name: "invalid-img-reference",
|
||||||
args: []string{"ALPINE"},
|
args: []string{"ALPINE"},
|
||||||
expectedError: "invalid reference format",
|
expectedError: "invalid reference format",
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
name: "unsigned-img-reference",
|
// name: "no-signing-keys-for-image",
|
||||||
args: []string{"riyaz/unsigned-img:v1"},
|
// args: []string{"alpine", "-y"},
|
||||||
expectedError: strings.Join([]string{
|
// expectedError: "could not remove signature for alpine: could not find necessary signing keys",
|
||||||
"could not remove signature for riyaz/unsigned-img:v1:",
|
// },
|
||||||
"notary.docker.io does not have trust data for docker.io/riyaz/unsigned-img",
|
|
||||||
}, " "),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "no-signing-keys-for-image",
|
|
||||||
args: []string{"alpine", "-y"},
|
|
||||||
expectedError: "could not remove signature for alpine: could not find necessary signing keys",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "digest-reference",
|
name: "digest-reference",
|
||||||
args: []string{"ubuntu@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2"},
|
args: []string{"ubuntu@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2"},
|
||||||
|
@ -72,6 +58,71 @@ func TestTrustRevokeCommandErrors(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTrustRevokeCommandOfflineErrors(t *testing.T) {
|
||||||
|
cli := NewFakeCliWithNotaryClient(&fakeClient{}, getOfflineNotaryRepository)
|
||||||
|
cmd := newRevokeCommand(cli)
|
||||||
|
cmd.SetArgs([]string{"reg-name.io/image"})
|
||||||
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
assert.NoError(t, cmd.Execute())
|
||||||
|
assert.Contains(t, cli.OutBuffer().String(), "Please confirm you would like to delete all signature data for reg-name.io/image? [y/N] \nAborting action.")
|
||||||
|
|
||||||
|
cli = NewFakeCliWithNotaryClient(&fakeClient{}, getOfflineNotaryRepository)
|
||||||
|
cmd = newRevokeCommand(cli)
|
||||||
|
cmd.SetArgs([]string{"reg-name.io/image", "-y"})
|
||||||
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
testutil.ErrorContains(t, cmd.Execute(), "could not remove signature for reg-name.io/image: client is offline")
|
||||||
|
|
||||||
|
cli = NewFakeCliWithNotaryClient(&fakeClient{}, getOfflineNotaryRepository)
|
||||||
|
cmd = newRevokeCommand(cli)
|
||||||
|
cmd.SetArgs([]string{"reg-name.io/image:tag"})
|
||||||
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
testutil.ErrorContains(t, cmd.Execute(), "could not remove signature for reg-name.io/image:tag: client is offline")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTrustRevokeCommandUninitializedErrors(t *testing.T) {
|
||||||
|
cli := NewFakeCliWithNotaryClient(&fakeClient{}, getUninitializedNotaryRepository)
|
||||||
|
cmd := newRevokeCommand(cli)
|
||||||
|
cmd.SetArgs([]string{"reg-name.io/image"})
|
||||||
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
assert.NoError(t, cmd.Execute())
|
||||||
|
assert.Contains(t, cli.OutBuffer().String(), "Please confirm you would like to delete all signature data for reg-name.io/image? [y/N] \nAborting action.")
|
||||||
|
|
||||||
|
cli = NewFakeCliWithNotaryClient(&fakeClient{}, getUninitializedNotaryRepository)
|
||||||
|
cmd = newRevokeCommand(cli)
|
||||||
|
cmd.SetArgs([]string{"reg-name.io/image", "-y"})
|
||||||
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
testutil.ErrorContains(t, cmd.Execute(), "could not remove signature for reg-name.io/image: does not have trust data for")
|
||||||
|
|
||||||
|
cli = NewFakeCliWithNotaryClient(&fakeClient{}, getUninitializedNotaryRepository)
|
||||||
|
cmd = newRevokeCommand(cli)
|
||||||
|
cmd.SetArgs([]string{"reg-name.io/image:tag"})
|
||||||
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
testutil.ErrorContains(t, cmd.Execute(), "could not remove signature for reg-name.io/image:tag: does not have trust data for")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTrustRevokeCommandEmptyNotaryRepo(t *testing.T) {
|
||||||
|
cli := NewFakeCliWithNotaryClient(&fakeClient{}, getEmptyTargetsNotaryRepository)
|
||||||
|
cmd := newRevokeCommand(cli)
|
||||||
|
cmd.SetArgs([]string{"reg-name.io/image"})
|
||||||
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
assert.NoError(t, cmd.Execute())
|
||||||
|
assert.Contains(t, cli.OutBuffer().String(), "Please confirm you would like to delete all signature data for reg-name.io/image? [y/N] \nAborting action.")
|
||||||
|
|
||||||
|
cli = NewFakeCliWithNotaryClient(&fakeClient{}, getEmptyTargetsNotaryRepository)
|
||||||
|
cmd = newRevokeCommand(cli)
|
||||||
|
cmd.SetArgs([]string{"reg-name.io/image", "-y"})
|
||||||
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
assert.NoError(t, cmd.Execute())
|
||||||
|
assert.Contains(t, cli.OutBuffer().String(), "Successfully deleted signature for reg-name.io/image")
|
||||||
|
|
||||||
|
cli = NewFakeCliWithNotaryClient(&fakeClient{}, getEmptyTargetsNotaryRepository)
|
||||||
|
cmd = newRevokeCommand(cli)
|
||||||
|
cmd.SetArgs([]string{"reg-name.io/image:tag"})
|
||||||
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
assert.NoError(t, cmd.Execute())
|
||||||
|
assert.Contains(t, cli.OutBuffer().String(), "Successfully deleted signature for reg-name.io/image:tag")
|
||||||
|
}
|
||||||
|
|
||||||
func TestNewRevokeTrustAllSigConfirmation(t *testing.T) {
|
func TestNewRevokeTrustAllSigConfirmation(t *testing.T) {
|
||||||
cli := test.NewFakeCli(&fakeClient{})
|
cli := test.NewFakeCli(&fakeClient{})
|
||||||
cmd := newRevokeCommand(cli)
|
cmd := newRevokeCommand(cli)
|
||||||
|
|
|
@ -51,26 +51,16 @@ func TestTrustSignCommandErrors(t *testing.T) {
|
||||||
args: []string{"ALPINE:latest"},
|
args: []string{"ALPINE:latest"},
|
||||||
expectedError: "invalid reference format",
|
expectedError: "invalid reference format",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "no-shell-for-passwd",
|
|
||||||
args: []string{"riyaz/unsigned-img:latest"},
|
|
||||||
expectedError: "error during connect: Get /images/riyaz/unsigned-img:latest/json",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "no-tag",
|
name: "no-tag",
|
||||||
args: []string{"riyaz/unsigned-img"},
|
args: []string{"reg/img"},
|
||||||
expectedError: "No tag specified for riyaz/unsigned-img",
|
expectedError: "No tag specified for reg/img",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "digest-reference",
|
name: "digest-reference",
|
||||||
args: []string{"ubuntu@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2"},
|
args: []string{"ubuntu@sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2"},
|
||||||
expectedError: "cannot use a digest reference for IMAGE:TAG",
|
expectedError: "cannot use a digest reference for IMAGE:TAG",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "no-keys",
|
|
||||||
args: []string{"ubuntu:latest"},
|
|
||||||
expectedError: "failed to sign \"docker.io/library/ubuntu\":latest: you are not authorized to perform this operation: server returned 401.",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
// change to a tmpdir
|
// change to a tmpdir
|
||||||
tmpDir, err := ioutil.TempDir("", "docker-sign-test-")
|
tmpDir, err := ioutil.TempDir("", "docker-sign-test-")
|
||||||
|
@ -86,6 +76,15 @@ func TestTrustSignCommandErrors(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTrustSignCommandOfflineErrors(t *testing.T) {
|
||||||
|
cli := NewFakeCliWithNotaryClient(&fakeClient{}, getOfflineNotaryRepository)
|
||||||
|
cmd := newSignCommand(cli)
|
||||||
|
cmd.SetArgs([]string{"reg-name.io/image:tag"})
|
||||||
|
cmd.SetOutput(ioutil.Discard)
|
||||||
|
assert.Error(t, cmd.Execute())
|
||||||
|
testutil.ErrorContains(t, cmd.Execute(), "client is offline")
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetOrGenerateNotaryKey(t *testing.T) {
|
func TestGetOrGenerateNotaryKey(t *testing.T) {
|
||||||
tmpDir, err := ioutil.TempDir("", "notary-test-")
|
tmpDir, err := ioutil.TempDir("", "notary-test-")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -274,7 +273,6 @@ func TestPrettyPrintExistingSignatureInfo(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestChangeList(t *testing.T) {
|
func TestChangeList(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)
|
||||||
|
|
Loading…
Reference in New Issue