Skip to content

Commit c08afec

Browse files
authored
feat: add the ability to specify global and specific parameters through the config ini file (#24)
* fix: add more tests rework how the config file is passed in perform merges from config.specific sections to the global config +semver: feature +semver: FEATURE
1 parent 1708da4 commit c08afec

File tree

18 files changed

+481
-215
lines changed

18 files changed

+481
-215
lines changed

cmd/awscliauth.go

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,21 @@ type Root struct {
2020
// ChannelOut io.Writer
2121
// ChannelErr io.Writer
2222
// viperConf *viper.Viper
23-
rootFlags *rootCmdFlags
23+
rootFlags *RootCmdFlags
2424
Datadir string
2525
}
2626

27-
type rootCmdFlags struct {
28-
cfgSectionName string
29-
storeInProfile bool
30-
killHangingProcess bool
31-
roleChain []string
32-
verbose bool
33-
duration int
27+
type RootCmdFlags struct {
28+
CfgSectionName string
29+
StoreInProfile bool
30+
RoleChain []string
31+
Verbose bool
32+
Duration int
33+
CustomIniLocation string
3434
}
3535

3636
func New() *Root {
37-
rf := &rootCmdFlags{}
37+
rf := &RootCmdFlags{}
3838
r := &Root{
3939
rootFlags: rf,
4040
Cmd: &cobra.Command{
@@ -49,15 +49,17 @@ Stores them under the $HOME/.aws/credentials file under a specified path or retu
4949
},
5050
}
5151

52-
r.Cmd.PersistentFlags().StringSliceVarP(&rf.roleChain, "role-chain", "", []string{}, "If specified it will assume the roles from the base credentials, in order they are specified in")
53-
r.Cmd.PersistentFlags().BoolVarP(&rf.storeInProfile, "store-profile", "s", false, `By default the credentials are returned to stdout to be used by the credential_process.
52+
r.Cmd.PersistentFlags().StringSliceVarP(&rf.RoleChain, "role-chain", "", []string{}, "If specified it will assume the roles from the base credentials, in order they are specified in")
53+
r.Cmd.PersistentFlags().BoolVarP(&rf.StoreInProfile, "store-profile", "s", false, `By default the credentials are returned to stdout to be used by the credential_process.
5454
Set this flag to instead store the credentials under a named profile section. You can then reference that profile name via the CLI or for use in an SDK`)
55-
r.Cmd.PersistentFlags().StringVarP(&rf.cfgSectionName, "cfg-section", "", "", "Config section name in the default AWS credentials file. To enable priofi")
55+
r.Cmd.PersistentFlags().StringVarP(&rf.CfgSectionName, "cfg-section", "", "", "Config section name to use in the look up of the config ini file (~/.aws-cli-auth.ini) and in the AWS credentials file")
5656
// When specifying store in profile the config section name must be provided
5757
r.Cmd.MarkFlagsRequiredTogether("store-profile", "cfg-section")
58-
r.Cmd.PersistentFlags().IntVarP(&rf.duration, "max-duration", "d", 900, `Override default max session duration, in seconds, of the role session [900-43200].
58+
r.Cmd.PersistentFlags().IntVarP(&rf.Duration, "max-duration", "d", 900, `Override default max session duration, in seconds, of the role session [900-43200].
5959
NB: This cannot be higher than the 3600 as the API does not allow for AssumeRole for sessions longer than an hour`)
60-
r.Cmd.PersistentFlags().BoolVarP(&rf.verbose, "verbose", "v", false, "Verbose output")
60+
r.Cmd.PersistentFlags().BoolVarP(&rf.Verbose, "verbose", "v", false, "Verbose output")
61+
r.Cmd.PersistentFlags().StringVarP(&rf.CustomIniLocation, "config-file", "c", "", "Specify the custom location of config file")
62+
6163
_ = r.dataDirInit()
6264
return r
6365
}

cmd/awscliauth_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ import (
55
"context"
66
"errors"
77
"io"
8+
"os"
9+
"strings"
810
"testing"
911

1012
"github.com/DevLabFoundry/aws-cli-auth/cmd"
13+
"github.com/DevLabFoundry/aws-cli-auth/internal/credentialexchange"
1114
"github.com/DevLabFoundry/aws-cli-auth/internal/web"
1215
)
1316

@@ -81,3 +84,52 @@ func Test_Saml_timeout(t *testing.T) {
8184
// }
8285
})
8386
}
87+
88+
func Test_SpecificCommand(t *testing.T) {
89+
90+
t.Run("Specific command should fail with wrong method", func(t *testing.T) {
91+
_, _, err := cmdHelperExecutor(t, []string{"specific", "--method=unknown", "--role",
92+
"arn:aws:iam::1234111111111:role/Role-ReadOnly"})
93+
if err == nil {
94+
t.Error("got nil, wanted an error")
95+
}
96+
if !errors.Is(err, cmd.ErrUnsupportedMethod) {
97+
t.Errorf("got %v, wanted %v", err, cmd.ErrUnsupportedMethod)
98+
}
99+
})
100+
101+
t.Run("Specific command fails on missing env AWS_WEB_IDENTITY_TOKEN_FILE", func(t *testing.T) {
102+
os.Setenv("AWS_ROLE_ARN", "arn:aws:iam::1234111111111:role/Role-ReadOnly")
103+
defer os.Unsetenv("AWS_ROLE_ARN")
104+
_, _, err := cmdHelperExecutor(t, []string{"specific", "--method=WEB_ID", "--role",
105+
"arn:aws:iam::1234111111111:role/Role-ReadOnly"})
106+
if err == nil {
107+
t.Error("got nil, wanted an error")
108+
}
109+
if !errors.Is(err, credentialexchange.ErrMissingEnvVar) {
110+
t.Errorf("got %v, wanted %v", err, cmd.ErrUnsupportedMethod)
111+
}
112+
})
113+
}
114+
115+
func Test_ClearCommand(t *testing.T) {
116+
117+
t.Run("should pass without --force", func(t *testing.T) {
118+
_, _, err := cmdHelperExecutor(t, []string{"clear-cache"})
119+
if err != nil {
120+
t.Error("got nil, wanted an error")
121+
}
122+
})
123+
t.Run("should warn user to manually delete data dir", func(t *testing.T) {
124+
stdout, _, err := cmdHelperExecutor(t, []string{"clear-cache", "--force"})
125+
if err != nil {
126+
t.Error("got nil, wanted an error")
127+
}
128+
if len(stdout.String()) < 1 {
129+
t.Fatal("got nil, wanted output")
130+
}
131+
if !strings.Contains(stdout.String(), "manually") {
132+
t.Errorf("incorrect messasge displayed, got %s, wanted to include manually", stdout.String())
133+
}
134+
})
135+
}

cmd/clear.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cmd
22

33
import (
4+
"errors"
45
"fmt"
56
"os"
67
"os/user"
@@ -13,6 +14,10 @@ type clearFlags struct {
1314
force bool
1415
}
1516

17+
var (
18+
ErrCannotReadConfig = errors.New("cannot open config file")
19+
)
20+
1621
func newClearCmd(r *Root) {
1722
flags := &clearFlags{}
1823

@@ -26,7 +31,8 @@ func newClearCmd(r *Root) {
2631
if err != nil {
2732
return err
2833
}
29-
if err := samlInitConfig(); err != nil {
34+
iniCfg, err := samlInitConfig(r.rootFlags.CustomIniLocation)
35+
if err != nil {
3036
return err
3137
}
3238
secretStore, err := credentialexchange.NewSecretStore("",
@@ -38,15 +44,11 @@ func newClearCmd(r *Root) {
3844
}
3945

4046
if flags.force {
41-
fmt.Fprint(os.Stderr, "delete ~/.aws-cli-auth-data/ manually")
47+
fmt.Fprint(cmd.OutOrStderr(), "delete ~/.aws-cli-auth-data/ manually")
4248
}
4349

44-
if err := secretStore.ClearAll(); err != nil {
45-
fmt.Fprint(os.Stderr, err.Error())
46-
}
47-
48-
if err := os.Remove(credentialexchange.ConfigIniFile("")); err != nil {
49-
return err
50+
if err := secretStore.ClearAll(iniCfg); err != nil {
51+
fmt.Fprint(cmd.OutOrStderr(), err.Error())
5052
}
5153

5254
return nil
@@ -64,6 +66,5 @@ Use with caution.
6466
If for any reason the local ini file and the secret store on your OS (keyring on GNU, keychain MacOS, windows secret store) are out of sync and the secrets cannot be retrieved by name but still exists,
6567
you might want to use CLI or GUI interface to the secret backing store on your OS and search for a secret prefixed with aws-cli-* and delete manually
6668
`)
67-
6869
r.Cmd.AddCommand(cmd)
6970
}

0 commit comments

Comments
 (0)