Skip to content

Commit

Permalink
Support XDG config path
Browse files Browse the repository at this point in the history
Fixes: #330
  • Loading branch information
synfinatic committed Jul 8, 2024
1 parent 0644b6a commit 0a1b78e
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 16 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
* Replace `--port` with `--server` flag for the `aws-sso ecs [list|load|unload|profile]` commands #937
* Update cache during login when relevant settings in the config.yaml changes #555
* Add support for `$AWS_SHARED_CREDENTIALS_FILE` #914
* Add support for `~/.config/aws-sso` #330

### Changes

* Bump cache file version to 4.
* `ConfigProfilesUrlAction` now defaults to value of `UrlAction` instead of `url` #946
* Rename/rework many of the `ecs` commands #938
* New installs of `aws-sso` will default to `~/.config/aws-sso` instead of `~/.aws-sso` for configuration

## [v1.16.1] - 2024-06-13

Expand Down
23 changes: 10 additions & 13 deletions cmd/aws-sso/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
// "github.com/davecgh/go-spew/spew"
"github.com/sirupsen/logrus"
"github.com/synfinatic/aws-sso-cli/internal/awscreds"
"github.com/synfinatic/aws-sso-cli/internal/config"
"github.com/synfinatic/aws-sso-cli/internal/ecs"
"github.com/synfinatic/aws-sso-cli/internal/ecs/client"
"github.com/synfinatic/aws-sso-cli/internal/ecs/server"
Expand Down Expand Up @@ -60,12 +61,8 @@ type RunContext struct {
}

const (
CONFIG_DIR = "~/.aws-sso"
CONFIG_FILE = CONFIG_DIR + "/config.yaml"
JSON_STORE_FILE = CONFIG_DIR + "/store.json"
INSECURE_CACHE_FILE = CONFIG_DIR + "/cache.json"
DEFAULT_STORE = "file"
COPYRIGHT_YEAR = "2021-2024"
DEFAULT_STORE = "file"
COPYRIGHT_YEAR = "2021-2024"
)

var DEFAULT_CONFIG map[string]interface{} = map[string]interface{}{
Expand Down Expand Up @@ -192,7 +189,7 @@ func main() {
log.WithError(err).Fatalf("Unable to open config file: %s", cli.ConfigFile)
}

cacheFile := utils.GetHomePath(INSECURE_CACHE_FILE)
cacheFile := config.InsecureCacheFile(true)

if runCtx.Settings, err = sso.LoadSettings(cli.ConfigFile, cacheFile, DEFAULT_CONFIG, override); err != nil {
log.Fatalf("%s", err.Error())
Expand All @@ -201,7 +198,7 @@ func main() {
// Load the secure store data
switch runCtx.Settings.SecureStore {
case "json":
sfile := utils.GetHomePath(JSON_STORE_FILE)
sfile := config.JsonStoreFile(true)
if runCtx.Settings.JsonStore != "" {
sfile = utils.GetHomePath(runCtx.Settings.JsonStore)
}
Expand All @@ -211,7 +208,7 @@ func main() {
}
log.Warnf("Using insecure json file for SecureStore: %s", sfile)
default:
cfg, err := storage.NewKeyringConfig(runCtx.Settings.SecureStore, CONFIG_DIR)
cfg, err := storage.NewKeyringConfig(runCtx.Settings.SecureStore, config.ConfigDir(true))
if err != nil {
log.WithError(err).Fatalf("Unable to create SecureStore")
}
Expand All @@ -231,10 +228,10 @@ func main() {
func parseArgs(cli *CLI) (*kong.Context, sso.OverrideSettings) {
// need to pass in the variables for defaults
vars := kong.Vars{
"CONFIG_DIR": CONFIG_DIR,
"CONFIG_FILE": CONFIG_FILE,
"CONFIG_DIR": config.ConfigDir(false),
"CONFIG_FILE": config.ConfigFile(false),
"DEFAULT_STORE": DEFAULT_STORE,
"JSON_STORE_FILE": JSON_STORE_FILE,
"JSON_STORE_FILE": config.JsonStoreFile(false),
"VERSION": Version,
}

Expand All @@ -245,7 +242,7 @@ func parseArgs(cli *CLI) (*kong.Context, sso.OverrideSettings) {
vars,
)

p := predictor.NewPredictor(utils.GetHomePath(INSECURE_CACHE_FILE), utils.GetHomePath(CONFIG_FILE))
p := predictor.NewPredictor(config.InsecureCacheFile(true), config.ConfigFile(true))

kongplete.Complete(parser,
kongplete.WithPredictors(
Expand Down
15 changes: 12 additions & 3 deletions docs/config.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
# Configuration

By default, `aws-sso` stores it's configuration file in `~/.aws-sso/config.yaml`,
but this can be overridden by setting `$AWS_SSO_CONFIG` in your shell or via the
`--config` flag.
By default, `aws-sso` will by default store all it's configuration and state files in
`~/.config/aws-sso` for versions `>= 1.17.0` per the [XDG spec](
https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html).
Previous versions of `aws-sso` used `~/.aws-sso`. Users at their own descresion may move the
files to the new location. To keep files co-located in the same place, if the directory
`~/.aws-sso` exists, then it will be used.

**Note:** The `aws-sso` documentation will generally use the older file path (`~/.aws-sso/...`)
when describing file locations.

The main configuration file is named `~/.aws-sso/config.yaml`, but this can be overridden by
setting `$AWS_SSO_CONFIG` in your shell or via the `--config` flag.

The first time you run `aws-sso` and it detects there is no configuration file,
it will prompt you for a number of questions to give you a basic configuration.
Expand Down
94 changes: 94 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package config

/*
* AWS SSO CLI
* Copyright (c) 2021-2024 Aaron Turner <synfinatic at gmail dot com>
*
* This program is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or with the authors permission any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import (
"fmt"
"os"

"github.com/synfinatic/aws-sso-cli/internal/utils"
)

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"
)

func ConfigDir(expand bool) string {
var path string
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)
}
return path
}

// 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))
fmt.Printf("fi: %v, err: %v\n", fi, err)
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
}

// 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
}

// 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
}
72 changes: 72 additions & 0 deletions internal/config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package config

import (
"fmt"
"os"
"testing"

"github.com/stretchr/testify/assert"
)

func TestConfigDir(t *testing.T) {
home := os.Getenv("HOME")
tempDir, err := os.MkdirTemp("", "")
assert.NoError(t, err)
defer os.RemoveAll(tempDir)

os.Setenv("HOME", tempDir)
defer os.Setenv("HOME", home)

assert.Equal(t, tempDir+"/.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))
assert.Equal(t, "~/.aws-sso", ConfigDir(false))
}
func TestConfigFile(t *testing.T) {
tempDir, err := os.MkdirTemp("", "")
assert.NoError(t, err)
defer os.RemoveAll(tempDir)

os.Setenv("HOME", tempDir)
home := os.Getenv("HOME")
defer os.Setenv("HOME", home)

assert.Equal(t, tempDir+"/.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))
assert.Equal(t, "~/.aws-sso/config.yaml", ConfigFile(false))
}

func TestJsonStoreFile(t *testing.T) {
tempDir, err := os.MkdirTemp("", "")
assert.NoError(t, err)
defer os.RemoveAll(tempDir)

os.Setenv("HOME", tempDir)
home := os.Getenv("HOME")
defer os.Setenv("HOME", home)

assert.Equal(t, tempDir+"/.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))
assert.Equal(t, "~/.aws-sso/store.json", JsonStoreFile(false))
}

func TestInsecureCacheFile(t *testing.T) {
tempDir, err := os.MkdirTemp("", "")
assert.NoError(t, err)
defer os.RemoveAll(tempDir)

os.Setenv("HOME", tempDir)
home := os.Getenv("HOME")
defer os.Setenv("HOME", home)

assert.Equal(t, tempDir+"/.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))
assert.Equal(t, "~/.aws-sso/cache.json", InsecureCacheFile(false))
}

0 comments on commit 0a1b78e

Please sign in to comment.