mirror of https://github.com/docker/cli.git
Fix issue where one bad credential helper causes none to be returned
Instead, skip bad credential helpers (and warn the user about the error) Signed-off-by: Laura Brehm <laurabrehm@hey.com>
This commit is contained in:
parent
4a500f690f
commit
9e3d5d1528
|
@ -300,7 +300,8 @@ func (configFile *ConfigFile) GetAllCredentials() (map[string]types.AuthConfig,
|
||||||
for registryHostname := range configFile.CredentialHelpers {
|
for registryHostname := range configFile.CredentialHelpers {
|
||||||
newAuth, err := configFile.GetAuthConfig(registryHostname)
|
newAuth, err := configFile.GetAuthConfig(registryHostname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
logrus.WithError(err).Warnf("Failed to get credentials for registry: %s", registryHostname)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
auths[registryHostname] = newAuth
|
auths[registryHostname] = newAuth
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package configfile
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -168,6 +169,7 @@ func TestConfigFile(t *testing.T) {
|
||||||
type mockNativeStore struct {
|
type mockNativeStore struct {
|
||||||
GetAllCallCount int
|
GetAllCallCount int
|
||||||
authConfigs map[string]types.AuthConfig
|
authConfigs map[string]types.AuthConfig
|
||||||
|
authConfigErrors map[string]error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *mockNativeStore) Erase(registryHostname string) error {
|
func (c *mockNativeStore) Erase(registryHostname string) error {
|
||||||
|
@ -176,7 +178,7 @@ func (c *mockNativeStore) Erase(registryHostname string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *mockNativeStore) Get(registryHostname string) (types.AuthConfig, error) {
|
func (c *mockNativeStore) Get(registryHostname string) (types.AuthConfig, error) {
|
||||||
return c.authConfigs[registryHostname], nil
|
return c.authConfigs[registryHostname], c.authConfigErrors[registryHostname]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *mockNativeStore) GetAll() (map[string]types.AuthConfig, error) {
|
func (c *mockNativeStore) GetAll() (map[string]types.AuthConfig, error) {
|
||||||
|
@ -191,8 +193,8 @@ func (c *mockNativeStore) Store(authConfig types.AuthConfig) error {
|
||||||
// make sure it satisfies the interface
|
// make sure it satisfies the interface
|
||||||
var _ credentials.Store = (*mockNativeStore)(nil)
|
var _ credentials.Store = (*mockNativeStore)(nil)
|
||||||
|
|
||||||
func NewMockNativeStore(authConfigs map[string]types.AuthConfig) credentials.Store {
|
func NewMockNativeStore(authConfigs map[string]types.AuthConfig, authConfigErrors map[string]error) credentials.Store {
|
||||||
return &mockNativeStore{authConfigs: authConfigs}
|
return &mockNativeStore{authConfigs: authConfigs, authConfigErrors: authConfigErrors}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetAllCredentialsFileStoreOnly(t *testing.T) {
|
func TestGetAllCredentialsFileStoreOnly(t *testing.T) {
|
||||||
|
@ -220,7 +222,7 @@ func TestGetAllCredentialsCredsStore(t *testing.T) {
|
||||||
Password: "pass",
|
Password: "pass",
|
||||||
}
|
}
|
||||||
|
|
||||||
testCredsStore := NewMockNativeStore(map[string]types.AuthConfig{testRegistryHostname: expectedAuth})
|
testCredsStore := NewMockNativeStore(map[string]types.AuthConfig{testRegistryHostname: expectedAuth}, nil)
|
||||||
|
|
||||||
tmpNewNativeStore := newNativeStore
|
tmpNewNativeStore := newNativeStore
|
||||||
defer func() { newNativeStore = tmpNewNativeStore }()
|
defer func() { newNativeStore = tmpNewNativeStore }()
|
||||||
|
@ -237,6 +239,48 @@ func TestGetAllCredentialsCredsStore(t *testing.T) {
|
||||||
assert.Check(t, is.Equal(1, testCredsStore.(*mockNativeStore).GetAllCallCount))
|
assert.Check(t, is.Equal(1, testCredsStore.(*mockNativeStore).GetAllCallCount))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetAllCredentialsCredStoreErrorHandling(t *testing.T) {
|
||||||
|
const (
|
||||||
|
workingHelperRegistryHostname = "working-helper.example.com"
|
||||||
|
brokenHelperRegistryHostname = "broken-helper.example.com"
|
||||||
|
)
|
||||||
|
configFile := New("filename")
|
||||||
|
configFile.CredentialHelpers = map[string]string{
|
||||||
|
workingHelperRegistryHostname: "cred_helper",
|
||||||
|
brokenHelperRegistryHostname: "broken_cred_helper",
|
||||||
|
}
|
||||||
|
expectedAuth := types.AuthConfig{
|
||||||
|
Username: "username",
|
||||||
|
Password: "pass",
|
||||||
|
}
|
||||||
|
// configure the mock store to throw an error
|
||||||
|
// when calling the helper for this registry
|
||||||
|
authErrors := map[string]error{
|
||||||
|
brokenHelperRegistryHostname: errors.New("an error"),
|
||||||
|
}
|
||||||
|
|
||||||
|
testCredsStore := NewMockNativeStore(map[string]types.AuthConfig{
|
||||||
|
workingHelperRegistryHostname: expectedAuth,
|
||||||
|
// configure an auth entry for the "broken" credential
|
||||||
|
// helper that will throw an error
|
||||||
|
brokenHelperRegistryHostname: {},
|
||||||
|
}, authErrors)
|
||||||
|
|
||||||
|
tmpNewNativeStore := newNativeStore
|
||||||
|
defer func() { newNativeStore = tmpNewNativeStore }()
|
||||||
|
newNativeStore = func(configFile *ConfigFile, helperSuffix string) credentials.Store {
|
||||||
|
return testCredsStore
|
||||||
|
}
|
||||||
|
|
||||||
|
authConfigs, err := configFile.GetAllCredentials()
|
||||||
|
|
||||||
|
// make sure we're still returning the expected credentials
|
||||||
|
// and skipping the ones throwing an error
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Check(t, is.Equal(1, len(authConfigs)))
|
||||||
|
assert.Check(t, is.DeepEqual(expectedAuth, authConfigs[workingHelperRegistryHostname]))
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetAllCredentialsCredHelper(t *testing.T) {
|
func TestGetAllCredentialsCredHelper(t *testing.T) {
|
||||||
const (
|
const (
|
||||||
testCredHelperSuffix = "test_cred_helper"
|
testCredHelperSuffix = "test_cred_helper"
|
||||||
|
@ -261,7 +305,7 @@ func TestGetAllCredentialsCredHelper(t *testing.T) {
|
||||||
// Add in an extra auth entry which doesn't appear in CredentialHelpers section of the configFile.
|
// Add in an extra auth entry which doesn't appear in CredentialHelpers section of the configFile.
|
||||||
// This verifies that only explicitly configured registries are being requested from the cred helpers.
|
// This verifies that only explicitly configured registries are being requested from the cred helpers.
|
||||||
testExtraCredHelperRegistryHostname: unexpectedCredHelperAuth,
|
testExtraCredHelperRegistryHostname: unexpectedCredHelperAuth,
|
||||||
})
|
}, nil)
|
||||||
|
|
||||||
tmpNewNativeStore := newNativeStore
|
tmpNewNativeStore := newNativeStore
|
||||||
defer func() { newNativeStore = tmpNewNativeStore }()
|
defer func() { newNativeStore = tmpNewNativeStore }()
|
||||||
|
@ -298,7 +342,7 @@ func TestGetAllCredentialsFileStoreAndCredHelper(t *testing.T) {
|
||||||
configFile.CredentialHelpers = map[string]string{testCredHelperRegistryHostname: testCredHelperSuffix}
|
configFile.CredentialHelpers = map[string]string{testCredHelperRegistryHostname: testCredHelperSuffix}
|
||||||
configFile.AuthConfigs[testFileStoreRegistryHostname] = expectedFileStoreAuth
|
configFile.AuthConfigs[testFileStoreRegistryHostname] = expectedFileStoreAuth
|
||||||
|
|
||||||
testCredHelper := NewMockNativeStore(map[string]types.AuthConfig{testCredHelperRegistryHostname: expectedCredHelperAuth})
|
testCredHelper := NewMockNativeStore(map[string]types.AuthConfig{testCredHelperRegistryHostname: expectedCredHelperAuth}, nil)
|
||||||
|
|
||||||
newNativeStore = func(configFile *ConfigFile, helperSuffix string) credentials.Store {
|
newNativeStore = func(configFile *ConfigFile, helperSuffix string) credentials.Store {
|
||||||
return testCredHelper
|
return testCredHelper
|
||||||
|
@ -337,8 +381,8 @@ func TestGetAllCredentialsCredStoreAndCredHelper(t *testing.T) {
|
||||||
Password: "cred_helper_pass",
|
Password: "cred_helper_pass",
|
||||||
}
|
}
|
||||||
|
|
||||||
testCredHelper := NewMockNativeStore(map[string]types.AuthConfig{testCredHelperRegistryHostname: expectedCredHelperAuth})
|
testCredHelper := NewMockNativeStore(map[string]types.AuthConfig{testCredHelperRegistryHostname: expectedCredHelperAuth}, nil)
|
||||||
testCredsStore := NewMockNativeStore(map[string]types.AuthConfig{testCredStoreRegistryHostname: expectedCredStoreAuth})
|
testCredsStore := NewMockNativeStore(map[string]types.AuthConfig{testCredStoreRegistryHostname: expectedCredStoreAuth}, nil)
|
||||||
|
|
||||||
tmpNewNativeStore := newNativeStore
|
tmpNewNativeStore := newNativeStore
|
||||||
defer func() { newNativeStore = tmpNewNativeStore }()
|
defer func() { newNativeStore = tmpNewNativeStore }()
|
||||||
|
@ -380,8 +424,8 @@ func TestGetAllCredentialsCredHelperOverridesDefaultStore(t *testing.T) {
|
||||||
Password: "cred_helper_pass",
|
Password: "cred_helper_pass",
|
||||||
}
|
}
|
||||||
|
|
||||||
testCredHelper := NewMockNativeStore(map[string]types.AuthConfig{testRegistryHostname: expectedCredHelperAuth})
|
testCredHelper := NewMockNativeStore(map[string]types.AuthConfig{testRegistryHostname: expectedCredHelperAuth}, nil)
|
||||||
testCredsStore := NewMockNativeStore(map[string]types.AuthConfig{testRegistryHostname: unexpectedCredStoreAuth})
|
testCredsStore := NewMockNativeStore(map[string]types.AuthConfig{testRegistryHostname: unexpectedCredStoreAuth}, nil)
|
||||||
|
|
||||||
tmpNewNativeStore := newNativeStore
|
tmpNewNativeStore := newNativeStore
|
||||||
defer func() { newNativeStore = tmpNewNativeStore }()
|
defer func() { newNativeStore = tmpNewNativeStore }()
|
||||||
|
|
Loading…
Reference in New Issue