mirror of
https://github.com/docker/docker-credential-helpers.git
synced 2026-06-13 16:01:28 +05:30
Merge pull request #284 from thaJeztah/various_cleanups
Assorted improvements, and add "--version, -v", and "--help, -h" flags
This commit is contained in:
+4
-4
@@ -26,7 +26,7 @@ func isValidCredsMessage(msg string) error {
|
|||||||
|
|
||||||
// Store uses an external program to save credentials.
|
// Store uses an external program to save credentials.
|
||||||
func Store(program ProgramFunc, creds *credentials.Credentials) error {
|
func Store(program ProgramFunc, creds *credentials.Credentials) error {
|
||||||
cmd := program("store")
|
cmd := program(credentials.ActionStore)
|
||||||
|
|
||||||
buffer := new(bytes.Buffer)
|
buffer := new(bytes.Buffer)
|
||||||
if err := json.NewEncoder(buffer).Encode(creds); err != nil {
|
if err := json.NewEncoder(buffer).Encode(creds); err != nil {
|
||||||
@@ -50,7 +50,7 @@ func Store(program ProgramFunc, creds *credentials.Credentials) error {
|
|||||||
|
|
||||||
// Get executes an external program to get the credentials from a native store.
|
// Get executes an external program to get the credentials from a native store.
|
||||||
func Get(program ProgramFunc, serverURL string) (*credentials.Credentials, error) {
|
func Get(program ProgramFunc, serverURL string) (*credentials.Credentials, error) {
|
||||||
cmd := program("get")
|
cmd := program(credentials.ActionGet)
|
||||||
cmd.Input(strings.NewReader(serverURL))
|
cmd.Input(strings.NewReader(serverURL))
|
||||||
|
|
||||||
out, err := cmd.Output()
|
out, err := cmd.Output()
|
||||||
@@ -81,7 +81,7 @@ func Get(program ProgramFunc, serverURL string) (*credentials.Credentials, error
|
|||||||
|
|
||||||
// Erase executes a program to remove the server credentials from the native store.
|
// Erase executes a program to remove the server credentials from the native store.
|
||||||
func Erase(program ProgramFunc, serverURL string) error {
|
func Erase(program ProgramFunc, serverURL string) error {
|
||||||
cmd := program("erase")
|
cmd := program(credentials.ActionErase)
|
||||||
cmd.Input(strings.NewReader(serverURL))
|
cmd.Input(strings.NewReader(serverURL))
|
||||||
out, err := cmd.Output()
|
out, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -99,7 +99,7 @@ func Erase(program ProgramFunc, serverURL string) error {
|
|||||||
|
|
||||||
// List executes a program to list server credentials in the native store.
|
// List executes a program to list server credentials in the native store.
|
||||||
func List(program ProgramFunc) (map[string]string, error) {
|
func List(program ProgramFunc) (map[string]string, error) {
|
||||||
cmd := program("list")
|
cmd := program(credentials.ActionList)
|
||||||
cmd.Input(strings.NewReader("unused"))
|
cmd.Input(strings.NewReader("unused"))
|
||||||
out, err := cmd.Output()
|
out, err := cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+14
-14
@@ -21,14 +21,14 @@ const (
|
|||||||
var errProgramExited = fmt.Errorf("exited 1")
|
var errProgramExited = fmt.Errorf("exited 1")
|
||||||
|
|
||||||
// mockProgram simulates interactions between the docker client and a remote
|
// mockProgram simulates interactions between the docker client and a remote
|
||||||
// credentials helper.
|
// credentials-helper.
|
||||||
// Unit tests inject this mocked command into the remote to control execution.
|
// Unit tests inject this mocked command into the remote to control execution.
|
||||||
type mockProgram struct {
|
type mockProgram struct {
|
||||||
arg string
|
arg string
|
||||||
input io.Reader
|
input io.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output returns responses from the remote credentials helper.
|
// Output returns responses from the remote credentials-helper.
|
||||||
// It mocks those responses based in the input in the mock.
|
// It mocks those responses based in the input in the mock.
|
||||||
func (m *mockProgram) Output() ([]byte, error) {
|
func (m *mockProgram) Output() ([]byte, error) {
|
||||||
in, err := io.ReadAll(m.input)
|
in, err := io.ReadAll(m.input)
|
||||||
@@ -80,7 +80,7 @@ func (m *mockProgram) Output() ([]byte, error) {
|
|||||||
return []byte(fmt.Sprintf("unknown argument %q with %q", m.arg, inS)), errProgramExited
|
return []byte(fmt.Sprintf("unknown argument %q with %q", m.arg, inS)), errProgramExited
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input sets the input to send to a remote credentials helper.
|
// Input sets the input to send to a remote credentials-helper.
|
||||||
func (m *mockProgram) Input(in io.Reader) {
|
func (m *mockProgram) Input(in io.Reader) {
|
||||||
m.input = in
|
m.input = in
|
||||||
}
|
}
|
||||||
@@ -92,16 +92,16 @@ func mockProgramFn(args ...string) Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ExampleStore() {
|
func ExampleStore() {
|
||||||
p := NewShellProgramFunc("docker-credential-secretservice")
|
p := NewShellProgramFunc("docker-credential-pass")
|
||||||
|
|
||||||
c := &credentials.Credentials{
|
c := &credentials.Credentials{
|
||||||
ServerURL: "https://example.com",
|
ServerURL: "https://registry.example.com",
|
||||||
Username: "calavera",
|
Username: "exampleuser",
|
||||||
Secret: "my super secret token",
|
Secret: "my super secret token",
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := Store(p, c); err != nil {
|
if err := Store(p, c); err != nil {
|
||||||
fmt.Println(err)
|
_, _ = fmt.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,14 +129,14 @@ func TestStore(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ExampleGet() {
|
func ExampleGet() {
|
||||||
p := NewShellProgramFunc("docker-credential-secretservice")
|
p := NewShellProgramFunc("docker-credential-pass")
|
||||||
|
|
||||||
creds, err := Get(p, "https://example.com")
|
creds, err := Get(p, "https://registry.example.com")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
_, _ = fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Got credentials for user `%s` in `%s`\n", creds.Username, creds.ServerURL)
|
_, _ = fmt.Printf("Got credentials for user `%s` in `%s`\n", creds.Username, creds.ServerURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGet(t *testing.T) {
|
func TestGet(t *testing.T) {
|
||||||
@@ -190,10 +190,10 @@ func TestGet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ExampleErase() {
|
func ExampleErase() {
|
||||||
p := NewShellProgramFunc("docker-credential-secretservice")
|
p := NewShellProgramFunc("docker-credential-pass")
|
||||||
|
|
||||||
if err := Erase(p, "https://example.com"); err != nil {
|
if err := Erase(p, "https://registry.example.com"); err != nil {
|
||||||
fmt.Println(err)
|
_, _ = fmt.Println(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-6
@@ -1,7 +1,6 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@@ -30,27 +29,26 @@ func NewShellProgramFuncWithEnv(name string, env *map[string]string) ProgramFunc
|
|||||||
|
|
||||||
func createProgramCmdRedirectErr(commandName string, args []string, env *map[string]string) *exec.Cmd {
|
func createProgramCmdRedirectErr(commandName string, args []string, env *map[string]string) *exec.Cmd {
|
||||||
programCmd := exec.Command(commandName, args...)
|
programCmd := exec.Command(commandName, args...)
|
||||||
programCmd.Env = os.Environ()
|
|
||||||
if env != nil {
|
if env != nil {
|
||||||
for k, v := range *env {
|
for k, v := range *env {
|
||||||
programCmd.Env = append(programCmd.Env, fmt.Sprintf("%s=%s", k, v))
|
programCmd.Env = append(programCmd.Environ(), k+"="+v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
programCmd.Stderr = os.Stderr
|
programCmd.Stderr = os.Stderr
|
||||||
return programCmd
|
return programCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shell invokes shell commands to talk with a remote credentials helper.
|
// Shell invokes shell commands to talk with a remote credentials-helper.
|
||||||
type Shell struct {
|
type Shell struct {
|
||||||
cmd *exec.Cmd
|
cmd *exec.Cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output returns responses from the remote credentials helper.
|
// Output returns responses from the remote credentials-helper.
|
||||||
func (s *Shell) Output() ([]byte, error) {
|
func (s *Shell) Output() ([]byte, error) {
|
||||||
return s.cmd.Output()
|
return s.cmd.Output()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input sets the input to send to a remote credentials helper.
|
// Input sets the input to send to a remote credentials-helper.
|
||||||
func (s *Shell) Input(in io.Reader) {
|
func (s *Shell) Input(in io.Reader) {
|
||||||
s.cmd.Stdin = in
|
s.cmd.Stdin = in
|
||||||
}
|
}
|
||||||
|
|||||||
+51
-28
@@ -10,6 +10,20 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Action defines the name of an action (sub-command) supported by a
|
||||||
|
// credential-helper binary. It is an alias for "string", and mostly
|
||||||
|
// for convenience.
|
||||||
|
type Action = string
|
||||||
|
|
||||||
|
// List of actions (sub-commands) supported by credential-helper binaries.
|
||||||
|
const (
|
||||||
|
ActionStore Action = "store"
|
||||||
|
ActionGet Action = "get"
|
||||||
|
ActionErase Action = "erase"
|
||||||
|
ActionList Action = "list"
|
||||||
|
ActionVersion Action = "version"
|
||||||
|
)
|
||||||
|
|
||||||
// Credentials holds the information shared between docker and the credentials store.
|
// Credentials holds the information shared between docker and the credentials store.
|
||||||
type Credentials struct {
|
type Credentials struct {
|
||||||
ServerURL string
|
ServerURL string
|
||||||
@@ -43,42 +57,52 @@ func SetCredsLabel(label string) {
|
|||||||
CredsLabel = label
|
CredsLabel = label
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serve initializes the credentials helper and parses the action argument.
|
// Serve initializes the credentials-helper and parses the action argument.
|
||||||
// This function is designed to be called from a command line interface.
|
// 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.Args[1] as the key for the action.
|
||||||
// It uses os.Stdin as input and os.Stdout as output.
|
// 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.
|
// This function terminates the program with os.Exit(1) if there is an error.
|
||||||
func Serve(helper Helper) {
|
func Serve(helper Helper) {
|
||||||
var err error
|
|
||||||
if len(os.Args) != 2 {
|
if len(os.Args) != 2 {
|
||||||
err = fmt.Errorf("Usage: %s <store|get|erase|list|version>", os.Args[0])
|
_, _ = fmt.Fprintln(os.Stdout, usage())
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
switch os.Args[1] {
|
||||||
err = HandleCommand(helper, os.Args[1], os.Stdin, os.Stdout)
|
case "--version", "-v":
|
||||||
|
_ = PrintVersion(os.Stdout)
|
||||||
|
os.Exit(0)
|
||||||
|
case "--help", "-h":
|
||||||
|
_, _ = fmt.Fprintln(os.Stdout, usage())
|
||||||
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err := HandleCommand(helper, os.Args[1], os.Stdin, os.Stdout); err != nil {
|
||||||
fmt.Fprintf(os.Stdout, "%v\n", err)
|
_, _ = fmt.Fprintln(os.Stdout, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleCommand uses a helper and a key to run a credential action.
|
func usage() string {
|
||||||
func HandleCommand(helper Helper, key string, in io.Reader, out io.Writer) error {
|
return fmt.Sprintf("Usage: %s <store|get|erase|list|version>", Name)
|
||||||
switch key {
|
}
|
||||||
case "store":
|
|
||||||
return Store(helper, in)
|
// HandleCommand runs a helper to execute a credential action.
|
||||||
case "get":
|
func HandleCommand(helper Helper, action Action, in io.Reader, out io.Writer) error {
|
||||||
return Get(helper, in, out)
|
switch action {
|
||||||
case "erase":
|
case ActionStore:
|
||||||
return Erase(helper, in)
|
return Store(helper, in)
|
||||||
case "list":
|
case ActionGet:
|
||||||
return List(helper, out)
|
return Get(helper, in, out)
|
||||||
case "version":
|
case ActionErase:
|
||||||
return PrintVersion(out)
|
return Erase(helper, in)
|
||||||
|
case ActionList:
|
||||||
|
return List(helper, out)
|
||||||
|
case ActionVersion:
|
||||||
|
return PrintVersion(out)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("%s: unknown action: %s", Name, action)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("Unknown credential action `%s`", key)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store uses a helper and an input reader to save credentials.
|
// Store uses a helper and an input reader to save credentials.
|
||||||
@@ -132,18 +156,17 @@ func Get(helper Helper, reader io.Reader, writer io.Writer) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
resp := Credentials{
|
buffer.Reset()
|
||||||
|
err = json.NewEncoder(buffer).Encode(Credentials{
|
||||||
ServerURL: serverURL,
|
ServerURL: serverURL,
|
||||||
Username: username,
|
Username: username,
|
||||||
Secret: secret,
|
Secret: secret,
|
||||||
}
|
})
|
||||||
|
if err != nil {
|
||||||
buffer.Reset()
|
|
||||||
if err := json.NewEncoder(buffer).Encode(resp); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Fprint(writer, buffer.String())
|
_, _ = fmt.Fprint(writer, buffer.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,6 +204,6 @@ func List(helper Helper, writer io.Writer) error {
|
|||||||
|
|
||||||
// PrintVersion outputs the current version.
|
// PrintVersion outputs the current version.
|
||||||
func PrintVersion(writer io.Writer) error {
|
func PrintVersion(writer io.Writer) error {
|
||||||
fmt.Fprintf(writer, "%s (%s) %s\n", Name, Package, Version)
|
_, _ = fmt.Fprintf(writer, "%s (%s) %s\n", Name, Package, Version)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user