From e0d084b45ab6c430556a4e083e5d437adb33a9ac Mon Sep 17 00:00:00 2001 From: Aaron Turner Date: Sat, 20 Jul 2024 12:07:00 -0700 Subject: [PATCH] Support XDG_CONFIG_HOME to override config location - We still default to ~/.config/aws-sso - If you have set XDG_CONFIG_HOME, we will use that... - Unless you still have ~/.aws-sso, in which case we will use that Fixes: #1003 --- CHANGELOG.md | 1 + internal/config/config.go | 56 ++++++---------- internal/config/config_test.go | 119 ++++++++++++++++++++++++++------- 3 files changed, 114 insertions(+), 62 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70210247..3b02e82b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ * `aws-sso` commands other than `cache` and `login` no longer can trigger a cache refresh without update of `~/.aws/config` file * Add support for running ECS Server via docker (`aws-sso ecs docker ...`) + * Add support for `XDG_CONFIG_HOME` env variable to specify config location #1003 ## [v1.17.0] - 2024-07-10 diff --git a/internal/config/config.go b/internal/config/config.go index 928f0bd8..e9c93899 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -27,20 +27,32 @@ import ( const ( OLD_CONFIG_DIR = "~/.aws-sso" - CONFIG_DIR = "~/.config/aws-sso" CONFIG_FILE = "%s/config.yaml" JSON_STORE_FILE = "%s/store.json" INSECURE_CACHE_FILE = "%s/cache.json" ) +// ConfigDir returns the path to the config directory func ConfigDir(expand bool) string { - var path string + path := "~/.config/aws-sso" // default XDG path is default + + // check if the user has a custom XDG_CONFIG_HOME + xdgPath, ok := os.LookupEnv("XDG_CONFIG_HOME") + if ok { + // fixup the path if it's the default, otherwise our tests are a disaster + if xdgPath == fmt.Sprintf("%s/.config", os.Getenv("HOME")) { + xdgPath = "~/.config" + } + path = fmt.Sprintf("%s/aws-sso", xdgPath) + } + + // check if the user has an old config directory which overrides + // the XDG_CONFIG_HOME fi, err := os.Stat(utils.GetHomePath(OLD_CONFIG_DIR)) if err == nil && fi.IsDir() { path = OLD_CONFIG_DIR - } else { - path = CONFIG_DIR } + if expand { path = utils.GetHomePath(path) } @@ -49,45 +61,15 @@ func ConfigDir(expand bool) string { // ConfigFile returns the path to the config file func ConfigFile(expand bool) string { - var path string - fi, err := os.Stat(utils.GetHomePath(OLD_CONFIG_DIR)) - if err == nil && fi.IsDir() { - path = fmt.Sprintf(CONFIG_FILE, OLD_CONFIG_DIR) - } else { - path = fmt.Sprintf(CONFIG_FILE, CONFIG_DIR) - } - if expand { - path = utils.GetHomePath(path) - } - return path + return fmt.Sprintf(CONFIG_FILE, ConfigDir(expand)) } // JsonStoreFile returns the path to the JSON store file func JsonStoreFile(expand bool) string { - var path string - fi, err := os.Stat(utils.GetHomePath(OLD_CONFIG_DIR)) - if err == nil && fi.IsDir() { - path = fmt.Sprintf(JSON_STORE_FILE, OLD_CONFIG_DIR) - } else { - path = fmt.Sprintf(JSON_STORE_FILE, CONFIG_DIR) - } - if expand { - path = utils.GetHomePath(path) - } - return path + return fmt.Sprintf(JSON_STORE_FILE, ConfigDir(expand)) } // InsecureCacheFile returns the path to the insecure cache file func InsecureCacheFile(expand bool) string { - var path string - fi, err := os.Stat(utils.GetHomePath(OLD_CONFIG_DIR)) - if err == nil && fi.IsDir() { - path = fmt.Sprintf(INSECURE_CACHE_FILE, OLD_CONFIG_DIR) - } else { - path = fmt.Sprintf(INSECURE_CACHE_FILE, CONFIG_DIR) - } - if expand { - path = utils.GetHomePath(path) - } - return path + return fmt.Sprintf(INSECURE_CACHE_FILE, ConfigDir(expand)) } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 5af36934..f9415419 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -3,70 +3,139 @@ package config import ( "fmt" "os" + "path/filepath" "testing" "github.com/stretchr/testify/assert" ) func TestConfigDir(t *testing.T) { - home := os.Getenv("HOME") - tempDir, err := os.MkdirTemp("", "") + tempHome, err := os.MkdirTemp("", "") assert.NoError(t, err) - defer os.RemoveAll(tempDir) + defer os.RemoveAll(tempHome) + + xdg := os.Getenv("XDG_CONFIG_HOME") + defer os.Setenv("XDG_CONFIG_HOME", xdg) + os.Unsetenv("XDG_CONFIG_HOME") - os.Setenv("HOME", tempDir) + home := os.Getenv("HOME") defer os.Setenv("HOME", home) + err = os.Setenv("HOME", tempHome) + assert.NoError(t, err) - assert.Equal(t, tempDir+"/.config/aws-sso", ConfigDir(true)) + assert.Equal(t, tempHome+"/.config/aws-sso", ConfigDir(true)) assert.Equal(t, "~/.config/aws-sso", ConfigDir(false)) - _ = os.MkdirAll(fmt.Sprintf("%s/.aws-sso", tempDir), 0755) - assert.Equal(t, tempDir+"/.aws-sso", ConfigDir(true)) + _ = os.MkdirAll(fmt.Sprintf("%s/.aws-sso", tempHome), 0755) + assert.Equal(t, tempHome+"/.aws-sso", ConfigDir(true)) assert.Equal(t, "~/.aws-sso", ConfigDir(false)) } func TestConfigFile(t *testing.T) { - tempDir, err := os.MkdirTemp("", "") + tempHome, err := os.MkdirTemp("", "") assert.NoError(t, err) - defer os.RemoveAll(tempDir) + defer os.RemoveAll(tempHome) + + xdg := os.Getenv("XDG_CONFIG_HOME") + defer os.Setenv("XDG_CONFIG_HOME", xdg) + os.Unsetenv("XDG_CONFIG_HOME") - os.Setenv("HOME", tempDir) home := os.Getenv("HOME") defer os.Setenv("HOME", home) + err = os.Setenv("HOME", tempHome) + assert.NoError(t, err) - assert.Equal(t, tempDir+"/.config/aws-sso/config.yaml", ConfigFile(true)) + assert.Equal(t, tempHome+"/.config/aws-sso/config.yaml", ConfigFile(true)) assert.Equal(t, "~/.config/aws-sso/config.yaml", ConfigFile(false)) - _ = os.MkdirAll(fmt.Sprintf("%s/.aws-sso", tempDir), 0755) - assert.Equal(t, tempDir+"/.aws-sso/config.yaml", ConfigFile(true)) + _ = os.MkdirAll(fmt.Sprintf("%s/.aws-sso", tempHome), 0755) + assert.Equal(t, tempHome+"/.aws-sso/config.yaml", ConfigFile(true)) assert.Equal(t, "~/.aws-sso/config.yaml", ConfigFile(false)) } func TestJsonStoreFile(t *testing.T) { - tempDir, err := os.MkdirTemp("", "") + tempHome, err := os.MkdirTemp("", "") assert.NoError(t, err) - defer os.RemoveAll(tempDir) + defer os.RemoveAll(tempHome) + + xdg := os.Getenv("XDG_CONFIG_HOME") + defer os.Setenv("XDG_CONFIG_HOME", xdg) + os.Unsetenv("XDG_CONFIG_HOME") - os.Setenv("HOME", tempDir) home := os.Getenv("HOME") defer os.Setenv("HOME", home) + err = os.Setenv("HOME", tempHome) + assert.NoError(t, err) - assert.Equal(t, tempDir+"/.config/aws-sso/store.json", JsonStoreFile(true)) + assert.Equal(t, tempHome+"/.config/aws-sso/store.json", JsonStoreFile(true)) assert.Equal(t, "~/.config/aws-sso/store.json", JsonStoreFile(false)) - _ = os.MkdirAll(fmt.Sprintf("%s/.aws-sso", tempDir), 0755) - assert.Equal(t, tempDir+"/.aws-sso/store.json", JsonStoreFile(true)) + _ = os.MkdirAll(fmt.Sprintf("%s/.aws-sso", tempHome), 0755) + assert.Equal(t, tempHome+"/.aws-sso/store.json", JsonStoreFile(true)) assert.Equal(t, "~/.aws-sso/store.json", JsonStoreFile(false)) } func TestInsecureCacheFile(t *testing.T) { - tempDir, err := os.MkdirTemp("", "") + tempHome, err := os.MkdirTemp("", "") assert.NoError(t, err) - defer os.RemoveAll(tempDir) + defer os.RemoveAll(tempHome) + + xdg := os.Getenv("XDG_CONFIG_HOME") + defer os.Setenv("XDG_CONFIG_HOME", xdg) + os.Unsetenv("XDG_CONFIG_HOME") - os.Setenv("HOME", tempDir) home := os.Getenv("HOME") defer os.Setenv("HOME", home) + err = os.Setenv("HOME", tempHome) + assert.NoError(t, err) - assert.Equal(t, tempDir+"/.config/aws-sso/cache.json", InsecureCacheFile(true)) + assert.Equal(t, tempHome+"/.config/aws-sso/cache.json", InsecureCacheFile(true)) assert.Equal(t, "~/.config/aws-sso/cache.json", InsecureCacheFile(false)) - _ = os.MkdirAll(fmt.Sprintf("%s/.aws-sso", tempDir), 0755) - assert.Equal(t, tempDir+"/.aws-sso/cache.json", InsecureCacheFile(true)) + _ = os.MkdirAll(fmt.Sprintf("%s/.aws-sso", tempHome), 0755) + assert.Equal(t, tempHome+"/.aws-sso/cache.json", InsecureCacheFile(true)) assert.Equal(t, "~/.aws-sso/cache.json", InsecureCacheFile(false)) } + +func TestXDGConfigDir(t *testing.T) { + tempHome, err := os.MkdirTemp("", "") + assert.NoError(t, err) + defer os.RemoveAll(tempHome) + + xdg := os.Getenv("XDG_CONFIG_HOME") + defer os.Setenv("XDG_CONFIG_HOME", xdg) + os.Unsetenv("XDG_CONFIG_HOME") + + home := os.Getenv("HOME") + defer os.Setenv("HOME", home) + + err = os.Setenv("HOME", tempHome) + assert.NoError(t, err) + + // new config, use default XDG_CONFIG_HOME + assert.Equal(t, filepath.Join(tempHome, ".config", "aws-sso"), ConfigDir(true)) + assert.Equal(t, "~/.config/aws-sso", ConfigDir(false)) + + // use a custom XDG_CONFIG_HOME path + os.Setenv("XDG_CONFIG_HOME", filepath.Join(tempHome, ".new-config")) + assert.Equal(t, filepath.Join(tempHome, ".new-config", "aws-sso"), ConfigDir(true)) + + // once we have the old config, we should use that though... + err = os.MkdirAll(fmt.Sprintf("%s/.aws-sso", tempHome), 0755) + assert.NoError(t, err) + assert.Equal(t, filepath.Join(tempHome, "/.aws-sso"), ConfigDir(true)) + assert.Equal(t, "~/.aws-sso", ConfigDir(false)) +} + +func TestXDGDefaultDir(t *testing.T) { + tempHome, err := os.MkdirTemp("", "") + assert.NoError(t, err) + defer os.RemoveAll(tempHome) + + home := os.Getenv("HOME") + defer os.Setenv("HOME", home) + err = os.Setenv("HOME", tempHome) + assert.NoError(t, err) + + xdg := os.Getenv("XDG_CONFIG_HOME") + defer os.Setenv("XDG_CONFIG_HOME", xdg) + os.Setenv("XDG_CONFIG_HOME", tempHome+"/.config") + + assert.Equal(t, "~/.config/aws-sso", ConfigDir(false)) + assert.Equal(t, tempHome+"/.config/aws-sso", ConfigDir(true)) +}