From feab8db60da39ecda00c86b34bf5958ae257a14f Mon Sep 17 00:00:00 2001 From: David Calavera Date: Sat, 4 Jun 2016 10:06:07 -0700 Subject: [PATCH 1/2] Vendor docker-credential-helpers v0.3.0 Fix a bug in the vendor helpers that took packages that started with github.com/docker/docker like if they were from within the project. Signed-off-by: David Calavera --- hack/.vendor-helpers.sh | 2 +- hack/vendor.sh | 3 + .../docker/docker-credential-helpers/LICENSE | 20 +++ .../client/client.go | 70 ++++++++++ .../client/command.go | 37 +++++ .../credentials/credentials.go | 129 ++++++++++++++++++ .../credentials/error.go | 37 +++++ .../credentials/helper.go | 12 ++ 8 files changed, 309 insertions(+), 1 deletion(-) create mode 100644 vendor/src/github.com/docker/docker-credential-helpers/LICENSE create mode 100644 vendor/src/github.com/docker/docker-credential-helpers/client/client.go create mode 100644 vendor/src/github.com/docker/docker-credential-helpers/client/command.go create mode 100644 vendor/src/github.com/docker/docker-credential-helpers/credentials/credentials.go create mode 100644 vendor/src/github.com/docker/docker-credential-helpers/credentials/error.go create mode 100644 vendor/src/github.com/docker/docker-credential-helpers/credentials/helper.go diff --git a/hack/.vendor-helpers.sh b/hack/.vendor-helpers.sh index 3f075e3494..94ed5cc5bb 100755 --- a/hack/.vendor-helpers.sh +++ b/hack/.vendor-helpers.sh @@ -108,7 +108,7 @@ clean() { go list -e -tags "$buildTags" -f '{{join .Deps "\n"}}' "${packages[@]}" go list -e -tags "$buildTags" -f '{{join .TestImports "\n"}}' "${packages[@]}" done - done | grep -vE "^${PROJECT}" | sort -u + done | grep -vE "^${PROJECT}/" | sort -u ) ) imports=( $(go list -e -f '{{if not .Standard}}{{.ImportPath}}{{end}}' "${imports[@]}") ) unset IFS diff --git a/hack/vendor.sh b/hack/vendor.sh index 2b545a5dec..4d449440cb 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -131,6 +131,9 @@ clone git golang.org/x/oauth2 2baa8a1b9338cf13d9eeb27696d761155fa480be https://g clone git google.golang.org/api dc6d2353af16e2a2b0ff6986af051d473a4ed468 https://code.googlesource.com/google-api-go-client clone git google.golang.org/cloud dae7e3d993bc3812a2185af60552bb6b847e52a0 https://code.googlesource.com/gocloud +# native credentials +clone git github.com/docker/docker-credential-helpers v0.3.0 + # containerd clone git github.com/docker/containerd 57b7c3da915ebe943bd304c00890959b191e5264 diff --git a/vendor/src/github.com/docker/docker-credential-helpers/LICENSE b/vendor/src/github.com/docker/docker-credential-helpers/LICENSE new file mode 100644 index 0000000000..1ea555e2af --- /dev/null +++ b/vendor/src/github.com/docker/docker-credential-helpers/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2016 David Calavera + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/src/github.com/docker/docker-credential-helpers/client/client.go b/vendor/src/github.com/docker/docker-credential-helpers/client/client.go new file mode 100644 index 0000000000..ddd30bbc88 --- /dev/null +++ b/vendor/src/github.com/docker/docker-credential-helpers/client/client.go @@ -0,0 +1,70 @@ +package client + +import ( + "bytes" + "encoding/json" + "fmt" + "strings" + + "github.com/docker/docker-credential-helpers/credentials" +) + +// Store uses an external program to save credentials. +func Store(program ProgramFunc, credentials *credentials.Credentials) error { + cmd := program("store") + + buffer := new(bytes.Buffer) + if err := json.NewEncoder(buffer).Encode(credentials); err != nil { + return err + } + cmd.Input(buffer) + + out, err := cmd.Output() + if err != nil { + t := strings.TrimSpace(string(out)) + return fmt.Errorf("error storing credentials - err: %v, out: `%s`", err, t) + } + + return nil +} + +// Get executes an external program to get the credentials from a native store. +func Get(program ProgramFunc, serverURL string) (*credentials.Credentials, error) { + cmd := program("get") + cmd.Input(strings.NewReader(serverURL)) + + out, err := cmd.Output() + if err != nil { + t := strings.TrimSpace(string(out)) + + if credentials.IsErrCredentialsNotFoundMessage(t) { + return nil, credentials.NewErrCredentialsNotFound() + } + + return nil, fmt.Errorf("error getting credentials - err: %v, out: `%s`", err, t) + } + + resp := &credentials.Credentials{ + ServerURL: serverURL, + } + + if err := json.NewDecoder(bytes.NewReader(out)).Decode(resp); err != nil { + return nil, err + } + + return resp, nil +} + +// Erase executes a program to remove the server credentails from the native store. +func Erase(program ProgramFunc, serverURL string) error { + cmd := program("erase") + cmd.Input(strings.NewReader(serverURL)) + + out, err := cmd.Output() + if err != nil { + t := strings.TrimSpace(string(out)) + return fmt.Errorf("error erasing credentials - err: %v, out: `%s`", err, t) + } + + return nil +} diff --git a/vendor/src/github.com/docker/docker-credential-helpers/client/command.go b/vendor/src/github.com/docker/docker-credential-helpers/client/command.go new file mode 100644 index 0000000000..8983da6947 --- /dev/null +++ b/vendor/src/github.com/docker/docker-credential-helpers/client/command.go @@ -0,0 +1,37 @@ +package client + +import ( + "io" + "os/exec" +) + +// Program is an interface to execute external programs. +type Program interface { + Output() ([]byte, error) + Input(in io.Reader) +} + +// ProgramFunc is a type of function that initializes programs based on arguments. +type ProgramFunc func(args ...string) Program + +// NewShellProgramFunc creates programs that are executed in a Shell. +func NewShellProgramFunc(name string) ProgramFunc { + return func(args ...string) Program { + return &Shell{cmd: exec.Command(name, args...)} + } +} + +// Shell invokes shell commands to talk with a remote credentials helper. +type Shell struct { + cmd *exec.Cmd +} + +// Output returns responses from the remote credentials helper. +func (s *Shell) Output() ([]byte, error) { + return s.cmd.Output() +} + +// Input sets the input to send to a remote credentials helper. +func (s *Shell) Input(in io.Reader) { + s.cmd.Stdin = in +} diff --git a/vendor/src/github.com/docker/docker-credential-helpers/credentials/credentials.go b/vendor/src/github.com/docker/docker-credential-helpers/credentials/credentials.go new file mode 100644 index 0000000000..b14f495660 --- /dev/null +++ b/vendor/src/github.com/docker/docker-credential-helpers/credentials/credentials.go @@ -0,0 +1,129 @@ +package credentials + +import ( + "bufio" + "bytes" + "encoding/json" + "fmt" + "io" + "os" + "strings" +) + +// Credentials holds the information shared between docker and the credentials store. +type Credentials struct { + ServerURL string + Username string + Secret string +} + +// Serve initializes the credentials helper and parses the action argument. +// This function is designed to be called from a command line interface. +// It uses os.Args[1] as the key for the action. +// It uses os.Stdin as input and os.Stdout as output. +// This function terminates the program with os.Exit(1) if there is an error. +func Serve(helper Helper) { + var err error + if len(os.Args) != 2 { + err = fmt.Errorf("Usage: %s ", os.Args[0]) + } + + if err == nil { + err = HandleCommand(helper, os.Args[1], os.Stdin, os.Stdout) + } + + if err != nil { + fmt.Fprintf(os.Stdout, "%v\n", err) + os.Exit(1) + } +} + +// HandleCommand uses a helper and a key to run a credential action. +func HandleCommand(helper Helper, key string, in io.Reader, out io.Writer) error { + switch key { + case "store": + return Store(helper, in) + case "get": + return Get(helper, in, out) + case "erase": + return Erase(helper, in) + } + return fmt.Errorf("Unknown credential action `%s`", key) +} + +// Store uses a helper and an input reader to save credentials. +// The reader must contain the JSON serialization of a Credentials struct. +func Store(helper Helper, reader io.Reader) error { + scanner := bufio.NewScanner(reader) + + buffer := new(bytes.Buffer) + for scanner.Scan() { + buffer.Write(scanner.Bytes()) + } + + if err := scanner.Err(); err != nil && err != io.EOF { + return err + } + + var creds Credentials + if err := json.NewDecoder(buffer).Decode(&creds); err != nil { + return err + } + + return helper.Add(&creds) +} + +// Get retrieves the credentials for a given server url. +// The reader must contain the server URL to search. +// The writer is used to write the JSON serialization of the credentials. +func Get(helper Helper, reader io.Reader, writer io.Writer) error { + scanner := bufio.NewScanner(reader) + + buffer := new(bytes.Buffer) + for scanner.Scan() { + buffer.Write(scanner.Bytes()) + } + + if err := scanner.Err(); err != nil && err != io.EOF { + return err + } + + serverURL := strings.TrimSpace(buffer.String()) + + username, secret, err := helper.Get(serverURL) + if err != nil { + return err + } + + resp := Credentials{ + Username: username, + Secret: secret, + } + + buffer.Reset() + if err := json.NewEncoder(buffer).Encode(resp); err != nil { + return err + } + + fmt.Fprint(writer, buffer.String()) + return nil +} + +// Erase removes credentials from the store. +// The reader must contain the server URL to remove. +func Erase(helper Helper, reader io.Reader) error { + scanner := bufio.NewScanner(reader) + + buffer := new(bytes.Buffer) + for scanner.Scan() { + buffer.Write(scanner.Bytes()) + } + + if err := scanner.Err(); err != nil && err != io.EOF { + return err + } + + serverURL := strings.TrimSpace(buffer.String()) + + return helper.Delete(serverURL) +} diff --git a/vendor/src/github.com/docker/docker-credential-helpers/credentials/error.go b/vendor/src/github.com/docker/docker-credential-helpers/credentials/error.go new file mode 100644 index 0000000000..d24bf16f09 --- /dev/null +++ b/vendor/src/github.com/docker/docker-credential-helpers/credentials/error.go @@ -0,0 +1,37 @@ +package credentials + +// ErrCredentialsNotFound standarizes the not found error, so every helper returns +// the same message and docker can handle it properly. +const errCredentialsNotFoundMessage = "credentials not found in native keychain" + +// errCredentialsNotFound represents an error +// raised when credentials are not in the store. +type errCredentialsNotFound struct{} + +// Error returns the standard error message +// for when the credentials are not in the store. +func (errCredentialsNotFound) Error() string { + return errCredentialsNotFoundMessage +} + +// NewErrCredentialsNotFound creates a new error +// for when the credentials are not in the store. +func NewErrCredentialsNotFound() error { + return errCredentialsNotFound{} +} + +// IsErrCredentialsNotFound returns true if the error +// was caused by not having a set of credentials in a store. +func IsErrCredentialsNotFound(err error) bool { + _, ok := err.(errCredentialsNotFound) + return ok +} + +// IsErrCredentialsNotFoundMessage returns true if the error +// was caused by not having a set of credentials in a store. +// +// This function helps to check messages returned by an +// external program via its standard output. +func IsErrCredentialsNotFoundMessage(err string) bool { + return err == errCredentialsNotFoundMessage +} diff --git a/vendor/src/github.com/docker/docker-credential-helpers/credentials/helper.go b/vendor/src/github.com/docker/docker-credential-helpers/credentials/helper.go new file mode 100644 index 0000000000..8a6967144e --- /dev/null +++ b/vendor/src/github.com/docker/docker-credential-helpers/credentials/helper.go @@ -0,0 +1,12 @@ +package credentials + +// Helper is the interface a credentials store helper must implement. +type Helper interface { + // Add appends credentials to the store. + Add(*Credentials) error + // Delete removes credentials from the store. + Delete(serverURL string) error + // Get retrieves credentials from the store. + // It returns username and secret as strings. + Get(serverURL string) (string, string, error) +} From ff3e187cc7a56ce102a61c1a4883f57fb1aed2f7 Mon Sep 17 00:00:00 2001 From: David Calavera Date: Sat, 4 Jun 2016 10:08:22 -0700 Subject: [PATCH 2/2] Use docker-credential-helpers client to talk with native creds stores. Signed-off-by: David Calavera --- cliconfig/credentials/native_store.go | 106 ++++----------------- cliconfig/credentials/native_store_test.go | 64 +++++++------ cliconfig/credentials/shell_command.go | 28 ------ 3 files changed, 51 insertions(+), 147 deletions(-) delete mode 100644 cliconfig/credentials/shell_command.go diff --git a/cliconfig/credentials/native_store.go b/cliconfig/credentials/native_store.go index e81de437e2..1717ce7b39 100644 --- a/cliconfig/credentials/native_store.go +++ b/cliconfig/credentials/native_store.go @@ -1,14 +1,8 @@ package credentials import ( - "bytes" - "encoding/json" - "errors" - "fmt" - "io" - "strings" - - "github.com/Sirupsen/logrus" + "github.com/docker/docker-credential-helpers/client" + "github.com/docker/docker-credential-helpers/credentials" "github.com/docker/docker/cliconfig/configfile" "github.com/docker/engine-api/types" ) @@ -18,50 +12,27 @@ const ( tokenUsername = "" ) -// Standarize the not found error, so every helper returns -// the same message and docker can handle it properly. -var errCredentialsNotFound = errors.New("credentials not found in native keychain") - -// command is an interface that remote executed commands implement. -type command interface { - Output() ([]byte, error) - Input(in io.Reader) -} - -// credentialsRequest holds information shared between docker and a remote credential store. -type credentialsRequest struct { - ServerURL string - Username string - Secret string -} - -// credentialsGetResponse is the information serialized from a remote store -// when the plugin sends requests to get the user credentials. -type credentialsGetResponse struct { - Username string - Secret string -} - // nativeStore implements a credentials store // using native keychain to keep credentials secure. // It piggybacks into a file store to keep users' emails. type nativeStore struct { - commandFn func(args ...string) command - fileStore Store + programFunc client.ProgramFunc + fileStore Store } // NewNativeStore creates a new native store that // uses a remote helper program to manage credentials. func NewNativeStore(file *configfile.ConfigFile) Store { + name := remoteCredentialsPrefix + file.CredentialsStore return &nativeStore{ - commandFn: shellCommandFn(file.CredentialsStore), - fileStore: NewFileStore(file), + programFunc: client.NewShellProgramFunc(name), + fileStore: NewFileStore(file), } } // Erase removes the given credentials from the native store. func (c *nativeStore) Erase(serverAddress string) error { - if err := c.eraseCredentialsFromStore(serverAddress); err != nil { + if err := client.Erase(c.programFunc, serverAddress); err != nil { return err } @@ -115,8 +86,7 @@ func (c *nativeStore) Store(authConfig types.AuthConfig) error { // storeCredentialsInStore executes the command to store the credentials in the native store. func (c *nativeStore) storeCredentialsInStore(config types.AuthConfig) error { - cmd := c.commandFn("store") - creds := &credentialsRequest{ + creds := &credentials.Credentials{ ServerURL: config.ServerAddress, Username: config.Username, Secret: config.Password, @@ -127,70 +97,30 @@ func (c *nativeStore) storeCredentialsInStore(config types.AuthConfig) error { creds.Secret = config.IdentityToken } - buffer := new(bytes.Buffer) - if err := json.NewEncoder(buffer).Encode(creds); err != nil { - return err - } - cmd.Input(buffer) - - out, err := cmd.Output() - if err != nil { - t := strings.TrimSpace(string(out)) - logrus.Debugf("error adding credentials - err: %v, out: `%s`", err, t) - return fmt.Errorf(t) - } - - return nil + return client.Store(c.programFunc, creds) } // getCredentialsFromStore executes the command to get the credentials from the native store. func (c *nativeStore) getCredentialsFromStore(serverAddress string) (types.AuthConfig, error) { var ret types.AuthConfig - cmd := c.commandFn("get") - cmd.Input(strings.NewReader(serverAddress)) - - out, err := cmd.Output() + creds, err := client.Get(c.programFunc, serverAddress) if err != nil { - t := strings.TrimSpace(string(out)) - - // do not return an error if the credentials are not - // in the keyckain. Let docker ask for new credentials. - if t == errCredentialsNotFound.Error() { + if credentials.IsErrCredentialsNotFound(err) { + // do not return an error if the credentials are not + // in the keyckain. Let docker ask for new credentials. return ret, nil } - - logrus.Debugf("error getting credentials - err: %v, out: `%s`", err, t) - return ret, fmt.Errorf(t) - } - - var resp credentialsGetResponse - if err := json.NewDecoder(bytes.NewReader(out)).Decode(&resp); err != nil { return ret, err } - if resp.Username == tokenUsername { - ret.IdentityToken = resp.Secret + if creds.Username == tokenUsername { + ret.IdentityToken = creds.Secret } else { - ret.Password = resp.Secret - ret.Username = resp.Username + ret.Password = creds.Secret + ret.Username = creds.Username } ret.ServerAddress = serverAddress return ret, nil } - -// eraseCredentialsFromStore executes the command to remove the server credentails from the native store. -func (c *nativeStore) eraseCredentialsFromStore(serverURL string) error { - cmd := c.commandFn("erase") - cmd.Input(strings.NewReader(serverURL)) - - out, err := cmd.Output() - if err != nil { - t := strings.TrimSpace(string(out)) - logrus.Debugf("error erasing credentials - err: %v, out: `%s`", err, t) - return fmt.Errorf(t) - } - - return nil -} diff --git a/cliconfig/credentials/native_store_test.go b/cliconfig/credentials/native_store_test.go index b233b5b5a3..952e447dfe 100644 --- a/cliconfig/credentials/native_store_test.go +++ b/cliconfig/credentials/native_store_test.go @@ -8,6 +8,8 @@ import ( "strings" "testing" + "github.com/docker/docker-credential-helpers/client" + "github.com/docker/docker-credential-helpers/credentials" "github.com/docker/engine-api/types" ) @@ -43,7 +45,7 @@ func (m *mockCommand) Output() ([]byte, error) { case validServerAddress: return nil, nil default: - return []byte("error erasing credentials"), errCommandExited + return []byte("program failed"), errCommandExited } case "get": switch inS { @@ -52,21 +54,21 @@ func (m *mockCommand) Output() ([]byte, error) { case validServerAddress2: return []byte(`{"Username": "", "Secret": "abcd1234"}`), nil case missingCredsAddress: - return []byte(errCredentialsNotFound.Error()), errCommandExited + return []byte(credentials.NewErrCredentialsNotFound().Error()), errCommandExited case invalidServerAddress: - return []byte("error getting credentials"), errCommandExited + return []byte("program failed"), errCommandExited } case "store": - var c credentialsRequest + var c credentials.Credentials err := json.NewDecoder(strings.NewReader(inS)).Decode(&c) if err != nil { - return []byte("error storing credentials"), errCommandExited + return []byte("program failed"), errCommandExited } switch c.ServerURL { case validServerAddress: return nil, nil default: - return []byte("error storing credentials"), errCommandExited + return []byte("program failed"), errCommandExited } } @@ -78,7 +80,7 @@ func (m *mockCommand) Input(in io.Reader) { m.input = in } -func mockCommandFn(args ...string) command { +func mockCommandFn(args ...string) client.Program { return &mockCommand{ arg: args[0], } @@ -89,8 +91,8 @@ func TestNativeStoreAddCredentials(t *testing.T) { f.CredentialsStore = "mock" s := &nativeStore{ - commandFn: mockCommandFn, - fileStore: NewFileStore(f), + programFunc: mockCommandFn, + fileStore: NewFileStore(f), } err := s.Store(types.AuthConfig{ Username: "foo", @@ -133,8 +135,8 @@ func TestNativeStoreAddInvalidCredentials(t *testing.T) { f.CredentialsStore = "mock" s := &nativeStore{ - commandFn: mockCommandFn, - fileStore: NewFileStore(f), + programFunc: mockCommandFn, + fileStore: NewFileStore(f), } err := s.Store(types.AuthConfig{ Username: "foo", @@ -147,8 +149,8 @@ func TestNativeStoreAddInvalidCredentials(t *testing.T) { t.Fatal("expected error, got nil") } - if err.Error() != "error storing credentials" { - t.Fatalf("expected `error storing credentials`, got %v", err) + if !strings.Contains(err.Error(), "program failed") { + t.Fatalf("expected `program failed`, got %v", err) } if len(f.AuthConfigs) != 0 { @@ -165,8 +167,8 @@ func TestNativeStoreGet(t *testing.T) { f.CredentialsStore = "mock" s := &nativeStore{ - commandFn: mockCommandFn, - fileStore: NewFileStore(f), + programFunc: mockCommandFn, + fileStore: NewFileStore(f), } a, err := s.Get(validServerAddress) if err != nil { @@ -196,8 +198,8 @@ func TestNativeStoreGetIdentityToken(t *testing.T) { f.CredentialsStore = "mock" s := &nativeStore{ - commandFn: mockCommandFn, - fileStore: NewFileStore(f), + programFunc: mockCommandFn, + fileStore: NewFileStore(f), } a, err := s.Get(validServerAddress2) if err != nil { @@ -230,8 +232,8 @@ func TestNativeStoreGetAll(t *testing.T) { f.CredentialsStore = "mock" s := &nativeStore{ - commandFn: mockCommandFn, - fileStore: NewFileStore(f), + programFunc: mockCommandFn, + fileStore: NewFileStore(f), } as, err := s.GetAll() if err != nil { @@ -277,8 +279,8 @@ func TestNativeStoreGetMissingCredentials(t *testing.T) { f.CredentialsStore = "mock" s := &nativeStore{ - commandFn: mockCommandFn, - fileStore: NewFileStore(f), + programFunc: mockCommandFn, + fileStore: NewFileStore(f), } _, err := s.Get(missingCredsAddress) if err != nil { @@ -296,16 +298,16 @@ func TestNativeStoreGetInvalidAddress(t *testing.T) { f.CredentialsStore = "mock" s := &nativeStore{ - commandFn: mockCommandFn, - fileStore: NewFileStore(f), + programFunc: mockCommandFn, + fileStore: NewFileStore(f), } _, err := s.Get(invalidServerAddress) if err == nil { t.Fatal("expected error, got nil") } - if err.Error() != "error getting credentials" { - t.Fatalf("expected `error getting credentials`, got %v", err) + if !strings.Contains(err.Error(), "program failed") { + t.Fatalf("expected `program failed`, got %v", err) } } @@ -318,8 +320,8 @@ func TestNativeStoreErase(t *testing.T) { f.CredentialsStore = "mock" s := &nativeStore{ - commandFn: mockCommandFn, - fileStore: NewFileStore(f), + programFunc: mockCommandFn, + fileStore: NewFileStore(f), } err := s.Erase(validServerAddress) if err != nil { @@ -340,15 +342,15 @@ func TestNativeStoreEraseInvalidAddress(t *testing.T) { f.CredentialsStore = "mock" s := &nativeStore{ - commandFn: mockCommandFn, - fileStore: NewFileStore(f), + programFunc: mockCommandFn, + fileStore: NewFileStore(f), } err := s.Erase(invalidServerAddress) if err == nil { t.Fatal("expected error, got nil") } - if err.Error() != "error erasing credentials" { - t.Fatalf("expected `error erasing credentials`, got %v", err) + if !strings.Contains(err.Error(), "program failed") { + t.Fatalf("expected `program failed`, got %v", err) } } diff --git a/cliconfig/credentials/shell_command.go b/cliconfig/credentials/shell_command.go deleted file mode 100644 index fa481b195d..0000000000 --- a/cliconfig/credentials/shell_command.go +++ /dev/null @@ -1,28 +0,0 @@ -package credentials - -import ( - "io" - "os/exec" -) - -func shellCommandFn(storeName string) func(args ...string) command { - name := remoteCredentialsPrefix + storeName - return func(args ...string) command { - return &shell{cmd: exec.Command(name, args...)} - } -} - -// shell invokes shell commands to talk with a remote credentials helper. -type shell struct { - cmd *exec.Cmd -} - -// Output returns responses from the remote credentials helper. -func (s *shell) Output() ([]byte, error) { - return s.cmd.Output() -} - -// Input sets the input to send to a remote credentials helper. -func (s *shell) Input(in io.Reader) { - s.cmd.Stdin = in -}