Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
Signed-off-by: Matej Vasek <[email protected]>
  • Loading branch information
matejvasek committed Sep 14, 2021
1 parent 174d302 commit f178089
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 0 deletions.
15 changes: 15 additions & 0 deletions pkg/docker/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,21 @@ func RemoveAuthentication(sys *types.SystemContext, key string) error {
if innerHelper, exists := auths.CredHelpers[key]; exists {
removeFromCredHelper(innerHelper)
}
if auths.CredsStore != "" {
c, err := getAuthFromCredHelper(auths.CredsStore, key)
if err != nil {
multiErr = multierror.Append(multiErr, errors.Wrapf(err, "removing credentials for %s from credential helper %s", key, auths.CredsStore))
} else {
if c.Username != "" || c.IdentityToken != "" {
err = deleteAuthFromCredHelper(auths.CredsStore, key)
if err != nil {
multiErr = multierror.Append(multiErr, errors.Wrapf(err, "removing credentials for %s from credential helper %s", key, auths.CredsStore))
} else {
isLoggedIn = true
}
}
}
}
if _, ok := auths.AuthConfigs[key]; ok {
isLoggedIn = true
delete(auths.AuthConfigs, key)
Expand Down
96 changes: 96 additions & 0 deletions pkg/docker/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"runtime"
Expand All @@ -16,6 +17,32 @@ import (
"github.com/stretchr/testify/require"
)

func TestMain(m *testing.M) {
// fake homedir
// let's hope nobody uses C getpwuid()
tmp, err := os.MkdirTemp("", "testHome")
if err != nil {
log.Fatal(err)
}

homeEnvVar := "HOME"
if runtime.GOOS == "windows" {
homeEnvVar = "USERPROFILE"
}

oldHome, hadHome := os.LookupEnv(homeEnvVar)
defer func() {
if hadHome {
os.Setenv(homeEnvVar, oldHome)
} else {
os.Unsetenv(homeEnvVar)
}
}()

os.Setenv(homeEnvVar, tmp)
m.Run()
}

func TestGetPathToAuth(t *testing.T) {
const linux = "linux"
const darwin = "darwin"
Expand Down Expand Up @@ -650,6 +677,75 @@ func TestGetAllCredentials(t *testing.T) {
require.Equal(t, "bar", authConfigs["registry-a.com"].Password)
}

func TestCredStore(t *testing.T) {
// Create a temporary authentication file.
tmpFile, err := ioutil.TempFile("", "auth.json.")
require.NoError(t, err)
authFilePath := tmpFile.Name()
defer os.Remove(authFilePath)
_, err = tmpFile.Write([]byte(`{ "credsStore": "mock-helper" }`))
require.NoError(t, err)
err = tmpFile.Close()
require.NoError(t, err)
require.NoError(t, err)

sys := types.SystemContext{
AuthFilePath: authFilePath,
}

// Set up path to mock cred helper
path, err := os.Getwd()
origPath := os.Getenv("PATH")
newPath := fmt.Sprintf("%s:%s", filepath.Join(path, "testdata"), origPath)
os.Setenv("PATH", newPath)
t.Logf("using PATH: %q", newPath)
defer os.Setenv("PATH", origPath)

// Set up temporary store for mock cred helper
mockHelperStore, err := ioutil.TempFile("", "cred-helper-store.json")
require.NoError(t, err)
defer os.Remove(mockHelperStore.Name())
_, err = mockHelperStore.Write([]byte("{}"))
require.NoError(t, err)
err = mockHelperStore.Close()
require.NoError(t, err)
os.Setenv("CRED_HELPER_STORE_FILE", mockHelperStore.Name())

expectedCreds := map[string]types.DockerAuthConfig{
"quay.io": {Username: "test-user", Password: "test-pwd"},
"docker.io": {Username: "test-user-2", Password: "test-pwd-2"},
"example.io": {Username: "test-user-3", Password: "test-pwd-3"},
}

for server, cred := range expectedCreds {
err = SetAuthentication(&sys, server, cred.Username, cred.Password)
require.NoError(t, err)
}

creds, err := GetAllCredentials(&sys)
require.NoError(t, err)
require.Equal(t, expectedCreds, creds)

cred, err := GetCredentials(&sys, "quay.io")
require.NoError(t, err)
require.Equal(t, types.DockerAuthConfig{Username: "test-user", Password: "test-pwd"}, cred)

err = RemoveAuthentication(&sys, "quay.io")
require.NoError(t, err)

err = RemoveAuthentication(&sys, "quay.io")
require.ErrorIs(t, err, ErrNotLoggedIn)

creds, err = GetAllCredentials(&sys)
require.NoError(t, err)
require.Equal(t, 2, len(creds))

err = RemoveAllAuthentication(&sys)
require.NoError(t, err)
creds, err = GetAllCredentials(&sys)
require.NoError(t, err)
require.Equal(t, 0, len(creds))
}

func TestAuthKeysForRef(t *testing.T) {
for _, tc := range []struct {
Expand Down
3 changes: 3 additions & 0 deletions pkg/docker/config/testdata/docker-credential-mock-helper
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env sh

exec /usr/bin/env go run ./testdata/docker-credential-mock-helper.go "$@"
126 changes: 126 additions & 0 deletions pkg/docker/config/testdata/docker-credential-mock-helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
///usr/bin/true; exec /usr/bin/env go run "$0" "$@"

package main

import (
"encoding/json"
"fmt"
"github.com/pkg/errors"
"io/ioutil"
"os"
"strings"
"syscall"
)

type userPasswordPair struct {
User, Password string
}

type serverUserSecretTriple struct {
ServerURL, Username, Secret string
}

func load() (map[string]userPasswordPair, error) {
credentials := make(map[string]userPasswordPair)
fname, ok := os.LookupEnv("CRED_HELPER_STORE_FILE")
if !ok {
return credentials, fmt.Errorf("the CRED_HELPER_STORE_FILE envvar not set")
}
f, err := os.OpenFile(fname, os.O_RDONLY, 0644)
if err != nil {
return credentials, err
}
defer f.Close()
dec := json.NewDecoder(f)
err = dec.Decode(&credentials)
return credentials, err
}

func store(credentials map[string]userPasswordPair) error {
fname, ok := os.LookupEnv("CRED_HELPER_STORE_FILE")
if !ok {
return fmt.Errorf("the CRED_HELPER_STORE_FILE envvar not set")
}
f, err := os.OpenFile(fname, os.O_WRONLY | os.O_CREATE | os.O_TRUNC, 0644)
if err != nil {
return err
}
defer f.Close()
enc := json.NewEncoder(f)
return enc.Encode(&credentials)

}

func fatal(err error) {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
var se syscall.Errno
if ok := errors.As(err, &se); ok {
os.Exit(int(se))
}
os.Exit(-1)
}

func main() {
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, "exactly one argument expected\n")
os.Exit(int(syscall.EINVAL))
}

credentials, err := load()
if err != nil {
fatal(err)
}

switch os.Args[1] {
case "list":
outData := make(map[string]string)
for server, up := range credentials {
outData[server] = up.User
}
enc := json.NewEncoder(os.Stdout)
err = enc.Encode(&outData)
if err != nil {
fatal(err)
}
case "get":
inData, err := ioutil.ReadAll(os.Stdin)
if err != nil {
fatal(err)
}
serverURL := string(inData)
serverURL = strings.Trim(serverURL, "\r\n")
up := credentials[serverURL]
outData := serverUserSecretTriple{ServerURL: serverURL, Username: up.User, Secret: up.Password}
enc := json.NewEncoder(os.Stdout)
if err = enc.Encode(outData); err != nil {
fatal(err)
}
case "erase":
inData, err := ioutil.ReadAll(os.Stdin)
if err != nil {
fatal(err)
}
serverURL := string(inData)
serverURL = strings.Trim(serverURL, "\r\n")
delete(credentials, serverURL)
err = store(credentials)
if err != nil {
fatal(err)
}
case "store":
inData := serverUserSecretTriple{}
enc := json.NewDecoder(os.Stdin)
err = enc.Decode(&inData)
if err != nil {
fatal(err)
}
credentials[inData.ServerURL] = userPasswordPair{User: inData.Username, Password: inData.Secret}
err = store(credentials)
if err != nil {
fatal(err)
}
default:
fmt.Fprintf(os.Stderr, "unknown sub-command %s\n", os.Args[1])
os.Exit(int(syscall.EINVAL))
}
}

0 comments on commit f178089

Please sign in to comment.