2016-12-25 14:31:52 -05:00
package config
import (
2017-06-22 12:03:58 -04:00
"bytes"
2019-03-07 09:28:42 -05:00
"fmt"
2016-12-25 14:31:52 -05:00
"os"
"path/filepath"
2019-09-23 19:27:03 -04:00
"runtime"
2016-12-25 14:31:52 -05:00
"strings"
"testing"
2017-04-17 18:07:56 -04:00
"github.com/docker/cli/cli/config/configfile"
2017-06-22 12:03:58 -04:00
"github.com/docker/cli/cli/config/credentials"
2020-07-16 06:01:54 -04:00
"github.com/docker/cli/cli/config/types"
2020-02-22 12:12:14 -05:00
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
2020-04-09 07:37:39 -04:00
"gotest.tools/v3/env"
2020-07-16 06:01:54 -04:00
"gotest.tools/v3/fs"
2016-12-25 14:31:52 -05:00
)
2019-09-23 19:27:03 -04:00
var homeKey = "HOME"
func init ( ) {
if runtime . GOOS == "windows" {
homeKey = "USERPROFILE"
}
}
2022-02-25 08:36:33 -05:00
func setupConfigDir ( t * testing . T ) string {
tmpdir := t . TempDir ( )
2017-06-22 12:03:58 -04:00
oldDir := Dir ( )
SetDir ( tmpdir )
2022-02-25 08:36:33 -05:00
t . Cleanup ( func ( ) {
2017-06-22 12:03:58 -04:00
SetDir ( oldDir )
2022-02-25 08:36:33 -05:00
} )
return tmpdir
2017-06-22 12:03:58 -04:00
}
2016-12-25 14:31:52 -05:00
2017-06-22 12:03:58 -04:00
func TestEmptyConfigDir ( t * testing . T ) {
2022-02-25 08:36:33 -05:00
tmpHome := setupConfigDir ( t )
2016-12-25 14:31:52 -05:00
config , err := Load ( "" )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , err )
2016-12-25 14:31:52 -05:00
expectedConfigFilename := filepath . Join ( tmpHome , ConfigFileName )
2018-03-05 18:53:52 -05:00
assert . Check ( t , is . Equal ( expectedConfigFilename , config . Filename ) )
2016-12-25 14:31:52 -05:00
// Now save it and make sure it shows up in new form
saveConfigAndValidateNewFormat ( t , config , tmpHome )
}
func TestMissingFile ( t * testing . T ) {
2022-02-25 08:36:33 -05:00
tmpHome := t . TempDir ( )
2016-12-25 14:31:52 -05:00
config , err := Load ( tmpHome )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , err )
2016-12-25 14:31:52 -05:00
// Now save it and make sure it shows up in new form
saveConfigAndValidateNewFormat ( t , config , tmpHome )
}
func TestSaveFileToDirs ( t * testing . T ) {
2020-06-17 08:51:16 -04:00
tmpHome := filepath . Join ( t . TempDir ( ) , ".docker" )
2016-12-25 14:31:52 -05:00
config , err := Load ( tmpHome )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , err )
2016-12-25 14:31:52 -05:00
// Now save it and make sure it shows up in new form
saveConfigAndValidateNewFormat ( t , config , tmpHome )
}
func TestEmptyFile ( t * testing . T ) {
2022-02-25 08:36:33 -05:00
tmpHome := t . TempDir ( )
2016-12-25 14:31:52 -05:00
fn := filepath . Join ( tmpHome , ConfigFileName )
2022-02-25 08:36:33 -05:00
err := os . WriteFile ( fn , [ ] byte ( "" ) , 0600 )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , err )
2016-12-25 14:31:52 -05:00
_ , err = Load ( tmpHome )
2020-06-23 07:04:11 -04:00
assert . NilError ( t , err )
2016-12-25 14:31:52 -05:00
}
func TestEmptyJSON ( t * testing . T ) {
2022-02-25 08:36:33 -05:00
tmpHome := t . TempDir ( )
2016-12-25 14:31:52 -05:00
fn := filepath . Join ( tmpHome , ConfigFileName )
2022-02-25 08:36:33 -05:00
err := os . WriteFile ( fn , [ ] byte ( "{}" ) , 0600 )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , err )
2016-12-25 14:31:52 -05:00
config , err := Load ( tmpHome )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , err )
2016-12-25 14:31:52 -05:00
// Now save it and make sure it shows up in new form
saveConfigAndValidateNewFormat ( t , config , tmpHome )
}
2020-07-16 06:01:54 -04:00
func TestOldJSONFallbackDeprecationWarning ( t * testing . T ) {
js := ` { "https://index.docker.io/v1/": { "auth":"am9lam9lOmhlbGxv","email":"user@example.com"}} `
tmpHome := fs . NewDir ( t , t . Name ( ) , fs . WithFile ( oldConfigfile , js ) )
defer tmpHome . Remove ( )
2022-09-22 10:31:28 -04:00
env . PatchAll ( t , map [ string ] string { homeKey : tmpHome . Path ( ) , "DOCKER_CONFIG" : "" } )
2020-07-16 06:01:54 -04:00
// reset the homeDir, configDir, and its sync.Once, to force them being resolved again
resetHomeDir ( )
resetConfigDir ( )
buffer := new ( bytes . Buffer )
configFile := LoadDefaultConfigFile ( buffer )
expected := configfile . New ( tmpHome . Join ( configFileDir , ConfigFileName ) )
2020-05-07 13:37:16 -04:00
expected . AuthConfigs = map [ string ] types . AuthConfig { }
assert . Assert ( t , strings . Contains ( buffer . String ( ) , "WARNING: Support for the legacy ~/.dockercfg configuration file and file-format has been removed and the configuration file will be ignored" ) )
2020-07-16 06:01:54 -04:00
assert . Check ( t , is . DeepEqual ( expected , configFile ) )
}
2016-12-25 14:31:52 -05:00
func TestNewJSON ( t * testing . T ) {
2022-02-25 08:36:33 -05:00
tmpHome := t . TempDir ( )
2016-12-25 14:31:52 -05:00
fn := filepath . Join ( tmpHome , ConfigFileName )
js := ` { "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv" } } } `
2022-02-25 08:36:33 -05:00
if err := os . WriteFile ( fn , [ ] byte ( js ) , 0600 ) ; err != nil {
2016-12-25 14:31:52 -05:00
t . Fatal ( err )
}
config , err := Load ( tmpHome )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , err )
2016-12-25 14:31:52 -05:00
ac := config . AuthConfigs [ "https://index.docker.io/v1/" ]
2019-03-04 12:44:07 -05:00
assert . Equal ( t , ac . Username , "joejoe" )
assert . Equal ( t , ac . Password , "hello" )
2016-12-25 14:31:52 -05:00
// Now save it and make sure it shows up in new form
configStr := saveConfigAndValidateNewFormat ( t , config , tmpHome )
expConfStr := ` {
"auths" : {
"https://index.docker.io/v1/" : {
"auth" : "am9lam9lOmhlbGxv"
}
}
} `
if configStr != expConfStr {
t . Fatalf ( "Should have save in new form: \n%s\n not \n%s" , configStr , expConfStr )
}
}
func TestNewJSONNoEmail ( t * testing . T ) {
2022-02-25 08:36:33 -05:00
tmpHome := t . TempDir ( )
2016-12-25 14:31:52 -05:00
fn := filepath . Join ( tmpHome , ConfigFileName )
js := ` { "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv" } } } `
2022-02-25 08:36:33 -05:00
if err := os . WriteFile ( fn , [ ] byte ( js ) , 0600 ) ; err != nil {
2016-12-25 14:31:52 -05:00
t . Fatal ( err )
}
config , err := Load ( tmpHome )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , err )
2016-12-25 14:31:52 -05:00
ac := config . AuthConfigs [ "https://index.docker.io/v1/" ]
2019-03-04 12:44:07 -05:00
assert . Equal ( t , ac . Username , "joejoe" )
assert . Equal ( t , ac . Password , "hello" )
2016-12-25 14:31:52 -05:00
// Now save it and make sure it shows up in new form
configStr := saveConfigAndValidateNewFormat ( t , config , tmpHome )
expConfStr := ` {
"auths" : {
"https://index.docker.io/v1/" : {
"auth" : "am9lam9lOmhlbGxv"
}
}
} `
if configStr != expConfStr {
t . Fatalf ( "Should have save in new form: \n%s\n not \n%s" , configStr , expConfStr )
}
}
func TestJSONWithPsFormat ( t * testing . T ) {
2022-02-25 08:36:33 -05:00
tmpHome := t . TempDir ( )
2016-12-25 14:31:52 -05:00
fn := filepath . Join ( tmpHome , ConfigFileName )
js := ` {
"auths" : { "https://index.docker.io/v1/" : { "auth" : "am9lam9lOmhlbGxv" , "email" : "user@example.com" } } ,
"psFormat" : "table {{.ID}}\\t{{.Label \"com.docker.label.cpu\"}}"
} `
2022-02-25 08:36:33 -05:00
if err := os . WriteFile ( fn , [ ] byte ( js ) , 0600 ) ; err != nil {
2016-12-25 14:31:52 -05:00
t . Fatal ( err )
}
config , err := Load ( tmpHome )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , err )
2016-12-25 14:31:52 -05:00
if config . PsFormat != ` table {{ .ID }} \t {{ .Label "com.docker.label.cpu" }} ` {
t . Fatalf ( "Unknown ps format: %s\n" , config . PsFormat )
}
// Now save it and make sure it shows up in new form
configStr := saveConfigAndValidateNewFormat ( t , config , tmpHome )
if ! strings . Contains ( configStr , ` "psFormat": ` ) ||
! strings . Contains ( configStr , "{{.ID}}" ) {
t . Fatalf ( "Should have save in new form: %s" , configStr )
}
}
func TestJSONWithCredentialStore ( t * testing . T ) {
2022-02-25 08:36:33 -05:00
tmpHome := t . TempDir ( )
2016-12-25 14:31:52 -05:00
fn := filepath . Join ( tmpHome , ConfigFileName )
js := ` {
"auths" : { "https://index.docker.io/v1/" : { "auth" : "am9lam9lOmhlbGxv" , "email" : "user@example.com" } } ,
"credsStore" : "crazy-secure-storage"
} `
2022-02-25 08:36:33 -05:00
if err := os . WriteFile ( fn , [ ] byte ( js ) , 0600 ) ; err != nil {
2016-12-25 14:31:52 -05:00
t . Fatal ( err )
}
config , err := Load ( tmpHome )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , err )
2016-12-25 14:31:52 -05:00
if config . CredentialsStore != "crazy-secure-storage" {
t . Fatalf ( "Unknown credential store: %s\n" , config . CredentialsStore )
}
// Now save it and make sure it shows up in new form
configStr := saveConfigAndValidateNewFormat ( t , config , tmpHome )
if ! strings . Contains ( configStr , ` "credsStore": ` ) ||
! strings . Contains ( configStr , "crazy-secure-storage" ) {
t . Fatalf ( "Should have save in new form: %s" , configStr )
}
}
func TestJSONWithCredentialHelpers ( t * testing . T ) {
2022-02-25 08:36:33 -05:00
tmpHome := t . TempDir ( )
2016-12-25 14:31:52 -05:00
fn := filepath . Join ( tmpHome , ConfigFileName )
js := ` {
"auths" : { "https://index.docker.io/v1/" : { "auth" : "am9lam9lOmhlbGxv" , "email" : "user@example.com" } } ,
"credHelpers" : { "images.io" : "images-io" , "containers.com" : "crazy-secure-storage" }
} `
2022-02-25 08:36:33 -05:00
if err := os . WriteFile ( fn , [ ] byte ( js ) , 0600 ) ; err != nil {
2016-12-25 14:31:52 -05:00
t . Fatal ( err )
}
config , err := Load ( tmpHome )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , err )
2016-12-25 14:31:52 -05:00
if config . CredentialHelpers == nil {
t . Fatal ( "config.CredentialHelpers was nil" )
} else if config . CredentialHelpers [ "images.io" ] != "images-io" ||
config . CredentialHelpers [ "containers.com" ] != "crazy-secure-storage" {
t . Fatalf ( "Credential helpers not deserialized properly: %v\n" , config . CredentialHelpers )
}
// Now save it and make sure it shows up in new form
configStr := saveConfigAndValidateNewFormat ( t , config , tmpHome )
if ! strings . Contains ( configStr , ` "credHelpers": ` ) ||
! strings . Contains ( configStr , "images.io" ) ||
! strings . Contains ( configStr , "images-io" ) ||
! strings . Contains ( configStr , "containers.com" ) ||
! strings . Contains ( configStr , "crazy-secure-storage" ) {
t . Fatalf ( "Should have save in new form: %s" , configStr )
}
}
// Save it and make sure it shows up in new form
2017-06-22 12:03:58 -04:00
func saveConfigAndValidateNewFormat ( t * testing . T , config * configfile . ConfigFile , configDir string ) string {
2020-06-15 04:41:28 -04:00
t . Helper ( )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , config . Save ( ) )
2016-12-25 14:31:52 -05:00
2022-02-25 08:36:33 -05:00
buf , err := os . ReadFile ( filepath . Join ( configDir , ConfigFileName ) )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , err )
assert . Check ( t , is . Contains ( string ( buf ) , ` "auths": ` ) )
2016-12-25 14:31:52 -05:00
return string ( buf )
}
func TestConfigDir ( t * testing . T ) {
2022-02-25 08:36:33 -05:00
tmpHome := t . TempDir ( )
2016-12-25 14:31:52 -05:00
if Dir ( ) == tmpHome {
t . Fatalf ( "Expected ConfigDir to be different than %s by default, but was the same" , tmpHome )
}
// Update configDir
SetDir ( tmpHome )
if Dir ( ) != tmpHome {
t . Fatalf ( "Expected ConfigDir to %s, but was %s" , tmpHome , Dir ( ) )
}
}
func TestJSONReaderNoFile ( t * testing . T ) {
js := ` { "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } } } `
config , err := LoadFromReader ( strings . NewReader ( js ) )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , err )
2016-12-25 14:31:52 -05:00
ac := config . AuthConfigs [ "https://index.docker.io/v1/" ]
2019-03-04 12:44:07 -05:00
assert . Equal ( t , ac . Username , "joejoe" )
assert . Equal ( t , ac . Password , "hello" )
2016-12-25 14:31:52 -05:00
}
func TestJSONWithPsFormatNoFile ( t * testing . T ) {
js := ` {
"auths" : { "https://index.docker.io/v1/" : { "auth" : "am9lam9lOmhlbGxv" , "email" : "user@example.com" } } ,
"psFormat" : "table {{.ID}}\\t{{.Label \"com.docker.label.cpu\"}}"
} `
config , err := LoadFromReader ( strings . NewReader ( js ) )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , err )
2016-12-25 14:31:52 -05:00
if config . PsFormat != ` table {{ .ID }} \t {{ .Label "com.docker.label.cpu" }} ` {
t . Fatalf ( "Unknown ps format: %s\n" , config . PsFormat )
}
}
func TestJSONSaveWithNoFile ( t * testing . T ) {
js := ` {
"auths" : { "https://index.docker.io/v1/" : { "auth" : "am9lam9lOmhlbGxv" } } ,
"psFormat" : "table {{.ID}}\\t{{.Label \"com.docker.label.cpu\"}}"
} `
config , err := LoadFromReader ( strings . NewReader ( js ) )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , err )
2016-12-25 14:31:52 -05:00
err = config . Save ( )
2018-03-05 19:59:53 -05:00
assert . ErrorContains ( t , err , "with empty filename" )
2016-12-25 14:31:52 -05:00
2022-02-25 08:36:33 -05:00
tmpHome := t . TempDir ( )
2016-12-25 14:31:52 -05:00
fn := filepath . Join ( tmpHome , ConfigFileName )
f , _ := os . OpenFile ( fn , os . O_WRONLY | os . O_CREATE | os . O_TRUNC , 0600 )
defer f . Close ( )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , config . SaveToWriter ( f ) )
2022-02-25 08:36:33 -05:00
buf , err := os . ReadFile ( filepath . Join ( tmpHome , ConfigFileName ) )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , err )
2016-12-25 14:31:52 -05:00
expConfStr := ` {
"auths" : {
"https://index.docker.io/v1/" : {
"auth" : "am9lam9lOmhlbGxv"
}
} ,
"psFormat" : "table {{.ID}}\\t{{.Label \"com.docker.label.cpu\"}}"
} `
if string ( buf ) != expConfStr {
t . Fatalf ( "Should have save in new form: \n%s\nnot \n%s" , string ( buf ) , expConfStr )
}
}
2017-06-22 12:03:58 -04:00
func TestLoadDefaultConfigFile ( t * testing . T ) {
2022-02-25 08:36:33 -05:00
dir := setupConfigDir ( t )
2017-06-22 12:03:58 -04:00
buffer := new ( bytes . Buffer )
filename := filepath . Join ( dir , ConfigFileName )
content := [ ] byte ( ` { "PsFormat": "format"} ` )
2022-02-25 08:36:33 -05:00
err := os . WriteFile ( filename , content , 0644 )
2018-03-05 18:53:52 -05:00
assert . NilError ( t , err )
2017-06-22 12:03:58 -04:00
configFile := LoadDefaultConfigFile ( buffer )
credStore := credentials . DetectDefaultStore ( "" )
2017-06-27 10:31:38 -04:00
expected := configfile . New ( filename )
2017-06-22 12:03:58 -04:00
expected . CredentialsStore = credStore
expected . PsFormat = "format"
2018-03-05 18:53:52 -05:00
assert . Check ( t , is . DeepEqual ( expected , configFile ) )
2017-06-22 12:03:58 -04:00
}
2019-01-10 10:49:06 -05:00
func TestConfigPath ( t * testing . T ) {
oldDir := Dir ( )
2019-03-07 09:28:42 -05:00
for _ , tc := range [ ] struct {
name string
dir string
path [ ] string
expected string
expectedErr string
} {
{
name : "valid_path" ,
dir : "dummy" ,
path : [ ] string { "a" , "b" } ,
expected : filepath . Join ( "dummy" , "a" , "b" ) ,
} ,
{
name : "valid_path_absolute_dir" ,
dir : "/dummy" ,
path : [ ] string { "a" , "b" } ,
expected : filepath . Join ( "/dummy" , "a" , "b" ) ,
} ,
{
name : "invalid_relative_path" ,
dir : "dummy" ,
path : [ ] string { "e" , ".." , ".." , "f" } ,
expectedErr : fmt . Sprintf ( "is outside of root config directory %q" , "dummy" ) ,
} ,
{
name : "invalid_absolute_path" ,
dir : "dummy" ,
path : [ ] string { "/a" , ".." , ".." } ,
expectedErr : fmt . Sprintf ( "is outside of root config directory %q" , "dummy" ) ,
} ,
} {
2019-10-29 08:33:25 -04:00
tc := tc
2019-03-07 09:28:42 -05:00
t . Run ( tc . name , func ( t * testing . T ) {
SetDir ( tc . dir )
f , err := Path ( tc . path ... )
assert . Equal ( t , f , tc . expected )
if tc . expectedErr == "" {
assert . NilError ( t , err )
} else {
assert . ErrorContains ( t , err , tc . expectedErr )
}
} )
}
2019-01-10 10:49:06 -05:00
SetDir ( oldDir )
}