Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions pkg/auth/credential_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package auth

import (
"fmt"
"testing"

"github.com/notaryproject/notation/pkg/config"
)

const (
errMsg = "error message"
validStore = "pass"
)

func TestLoadConfig_LoadNotationConfigFailed(t *testing.T) {
loadOrDefault = func() (*config.File, error) {
return nil, fmt.Errorf(errMsg)
}
_, err := LoadConfig()
if err == nil || err.Error() != errMsg {
t.Fatalf("Didn't get the expected error, but got: %v", err)
}
}

func TestLoadConfig_NotationConfigContainsAuth(t *testing.T) {
loadOrDefault = func() (*config.File, error) {
return &config.File{
CredentialsStore: validStore,
}, nil
}
file, err := LoadConfig()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if file == nil || file.CredentialsStore != validStore {
t.Fatalf("Should contain auth")
}
}

func TestLoadConfig_LoadDockerConfigFailed(t *testing.T) {
loadOrDefault = func() (*config.File, error) {
return nil, nil
}
loadDockerConfig = func() (*config.DockerConfigFile, error) {
return nil, fmt.Errorf(errMsg)
}
_, err := LoadConfig()
if err == nil || err.Error() != errMsg {
t.Fatalf("Didn't get the expected error, but got: %v", err)
}
}

func TestLoadConfig_DockerConfigContainsAuth(t *testing.T) {
loadOrDefault = func() (*config.File, error) {
return nil, nil
}
loadDockerConfig = func() (*config.DockerConfigFile, error) {
return &config.DockerConfigFile{
CredentialsStore: validStore,
}, nil
}
file, err := LoadConfig()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if file == nil || file.CredentialsStore != validStore {
t.Fatalf("Should contain auth")
}
}

func TestLoadConfig_DockerConfigEmptyAuth(t *testing.T) {
loadOrDefault = func() (*config.File, error) {
return nil, nil
}
loadDockerConfig = func() (*config.DockerConfigFile, error) {
return &config.DockerConfigFile{}, nil
}
_, err := LoadConfig()
if err == nil {
t.Fatalf("expect error but got nil")
}
}
199 changes: 199 additions & 0 deletions pkg/auth/native_store_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
package auth

import (
"encoding/json"
"fmt"
"io"
"strings"
"testing"

"github.com/docker/docker-credential-helpers/client"
"github.com/docker/docker-credential-helpers/credentials"
"github.com/notaryproject/notation/pkg/config"
"oras.land/oras-go/v2/registry/remote/auth"
)

const (
validServerAddress = "https://index.docker.io/v1"
validServerAddress2 = "https://example.com:5002"
invalidServerAddress = "https://foobar.example.com"
missingCredsAddress = "https://missing.docker.io/v1"
Username = "Username"
Secret = "Secret"
validUsername = "username"
validPassword = "password"
validIdentityToken = "identityToken"
validHelper = "helper"
)

var (
errCommandExited = fmt.Errorf("exited 1")
)

// mockCommand simulates interactions between the docker client and a remote
// credentials helper.
// Unit tests inject this mocked command into the remote to control execution.
type mockCommand struct {
arg string
input io.Reader
}

// Output returns responses from the remote credentials helper.
// It mocks those responses based in the input in the mock.
func (m *mockCommand) Output() ([]byte, error) {
in, err := io.ReadAll(m.input)
if err != nil {
return nil, err
}
inS := string(in)

switch m.arg {
case "erase":
switch inS {
case validServerAddress:
return nil, nil
default:
return []byte("program failed"), errCommandExited
}
case "get":
switch inS {
case validServerAddress:
return []byte(`{"Username": "username", "Secret": "password"}`), nil
case invalidServerAddress:
return []byte("program failed"), errCommandExited
case validServerAddress2:
return []byte(`{"Username": "<token>", "Secret": "identityToken"}`), nil
}
case "store":
var c credentials.Credentials
err := json.NewDecoder(strings.NewReader(inS)).Decode(&c)
if err != nil {
return []byte("program failed"), errCommandExited
}
switch c.ServerURL {
case validServerAddress, validServerAddress2:
return nil, nil
default:
return []byte("program failed"), errCommandExited
}
}

return []byte(fmt.Sprintf("unknown argument %q with %q", m.arg, inS)), errCommandExited
}

// Input sets the input to send to a remote credentials helper.
func (m *mockCommand) Input(in io.Reader) {
m.input = in
}

func mockCommandFn(args ...string) client.Program {
return &mockCommand{
arg: args[0],
}
}

func TestNativeStore_StoreGetErase(t *testing.T) {
creds := auth.Credential{
Username: validUsername,
Password: validPassword,
}
s := &nativeAuthStore{
programFunc: mockCommandFn,
}

// store creds
err := s.Store(validServerAddress, creds)
if err != nil {
t.Fatalf("unexpected error: %v", err.Error())
}

// get creds
fetchedCreds, err := s.Get(validServerAddress)
if err != nil {
t.Fatalf("unexpected error: %v", err.Error())
}
if fetchedCreds != creds {
t.Fatalf("expected %+v, got %+v", creds, fetchedCreds)
}

// erase creds
err = s.Erase(validServerAddress)
if err != nil {
t.Fatalf("unexpected error: %v", err.Error())
}
fetchedCreds, err = s.Get(validServerAddress)
if err != nil {
t.Fatalf("unexpected error: %v", err.Error())
}
if fetchedCreds == auth.EmptyCredential {
t.Fatalf("expect empty conf, but got: %+v", fetchedCreds)
}
}

func TestNativeStore_StoreIdentityToken(t *testing.T) {
creds := auth.Credential{
RefreshToken: validIdentityToken,
}
s := &nativeAuthStore{
programFunc: mockCommandFn,
}

// store creds
err := s.Store(validServerAddress, creds)
if err != nil {
t.Fatalf("unexpected error: %v", err.Error())
}

// get creds
fetchedCreds, err := s.Get(validServerAddress2)
if err != nil {
t.Fatalf("unexpected error: %v", err.Error())
}
if fetchedCreds.RefreshToken != creds.RefreshToken {
t.Fatalf("expected %+v, got %+v", creds, fetchedCreds)
}
}

func TestNativeStore_FailedGet(t *testing.T) {
s := &nativeAuthStore{
programFunc: mockCommandFn,
}
_, err := s.Get(invalidServerAddress)
if err == nil {
t.Fatalf("expect error, got nil")
}
}

func TestNativeStore_GetCredentialsStore_LoadConfigFailed(t *testing.T) {
loadConfig = func() (*config.File, error) {
return nil, fmt.Errorf("loadConfig err")
}
_, err := GetCredentialsStore(validServerAddress)
if err == nil {
t.Fatalf("expect error, got nil")
}
}

func TestNativeStore_GetCredentialsStore_NoHelperSet(t *testing.T) {
loadConfig = func() (*config.File, error) {
return &config.File{}, nil
}
_, err := GetCredentialsStore(validServerAddress)
if err == nil || err.Error() != "could not get the configured credentials store for registry: "+validServerAddress {
t.Fatalf("Didn't get the expected error, but got: %v", err)
}
}

func TestNativeStore_GetCredentialsStore_HelperSet(t *testing.T) {
loadConfig = func() (*config.File, error) {
return &config.File{
CredentialHelpers: map[string]string{
validServerAddress: validHelper,
},
}, nil
}
_, err := GetCredentialsStore(validServerAddress)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
79 changes: 79 additions & 0 deletions pkg/config/docker_config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package config

import (
"os"
"path/filepath"
"strings"
"testing"
)

const (
validJson = `{
"credHelpers": {
"localhost:5000": "pass"
},
"credsStore": "pass"
}`
invalidJson = `{`
)

func TestLoadDockerConfig_noErrors(t *testing.T) {
// Create temp directory
dockerConfigDir := t.TempDir()
t.Setenv("DOCKER_CONFIG", dockerConfigDir)

// Create config.json
f, err := os.Create(filepath.Join(dockerConfigDir, dockerConfigFileName))
if err != nil {
t.Fatalf("Failed to mock docker config, err: %v", err)
}
defer f.Close()
data := []byte(validJson)
if _, err := f.Write(data); err != nil {
t.Fatalf("Failed to mock docker config, err: %v", err)
}

// Load docker config
config, err := LoadDockerConfig()
if err != nil {
t.Fatalf("Unexpected error loading config.json: %v", err)
}
if config.CredentialsStore != "pass" {
t.Fatalf("Expected credentials store to be 'pass', but got %v", config.CredentialsStore)
}
}

func TestLoadDockerConfig_noConfigFile(t *testing.T) {
// Create temp directory
dockerConfigDir := t.TempDir()
t.Setenv("DOCKER_CONFIG", dockerConfigDir)

// Load docker config
_, err := LoadDockerConfig()
if err == nil {
t.Fatalf("Expected error not returned")
}
}

func TestLoadDockerConfig_invalidConfigFile(t *testing.T) {
// Create temp directory
dockerConfigDir := t.TempDir()
t.Setenv("DOCKER_CONFIG", dockerConfigDir)

// Create config.json
f, err := os.Create(filepath.Join(dockerConfigDir, dockerConfigFileName))
if err != nil {
t.Fatalf("Failed to mock docker config, err: %v", err)
}
defer f.Close()
data := []byte(invalidJson)
if _, err := f.Write(data); err != nil {
t.Fatalf("Failed to mock docker config, err: %v", err)
}

// Load docker config
_, err = LoadDockerConfig()
if err == nil || !strings.HasSuffix(err.Error(), "unexpected EOF") {
t.Fatalf("Expected error not returned")
}
}