Skip to content

Commit 0816291

Browse files
committed
fix: upgrade to new cobra implementation
1 parent 32eed0d commit 0816291

File tree

14 files changed

+486
-319
lines changed

14 files changed

+486
-319
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,5 @@ vendor/
2727

2828
.ignore*
2929
local/
30+
.deps/
31+
.cache/

aws-cli-auth.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,20 @@ package main
22

33
import (
44
"context"
5+
"log"
6+
"os"
7+
"os/signal"
8+
"syscall"
59

610
"github.com/DevLabFoundry/aws-cli-auth/cmd"
711
)
812

913
func main() {
10-
cmd.Execute(context.Background())
14+
ctx, stop := signal.NotifyContext(context.Background(), []os.Signal{os.Interrupt, syscall.SIGTERM, os.Kill}...)
15+
defer stop()
16+
c := cmd.New()
17+
c.WithSubCommands(cmd.SubCommands()...)
18+
if err := c.Execute(ctx); err != nil {
19+
log.Fatalf("\x1b[31maws-cli-auth err:\n%s\x1b[0m", err)
20+
}
1121
}

cmd/awscliauth.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package cmd
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
"path"
8+
9+
"github.com/DevLabFoundry/aws-cli-auth/internal/credentialexchange"
10+
"github.com/spf13/cobra"
11+
)
12+
13+
var (
14+
Version string = "0.0.1"
15+
Revision string = "1111aaaa"
16+
)
17+
18+
type Root struct {
19+
ctx context.Context
20+
Cmd *cobra.Command
21+
// ChannelOut io.Writer
22+
// ChannelErr io.Writer
23+
// viperConf *viper.Viper
24+
rootFlags *rootCmdFlags
25+
Datadir string
26+
}
27+
28+
type rootCmdFlags struct {
29+
cfgSectionName string
30+
storeInProfile bool
31+
killHangingProcess bool
32+
roleChain []string
33+
verbose bool
34+
duration int
35+
}
36+
37+
func New() *Root {
38+
rf := &rootCmdFlags{}
39+
r := &Root{
40+
rootFlags: rf,
41+
Cmd: &cobra.Command{
42+
Use: "aws-cli-auth",
43+
Short: "CLI tool for retrieving AWS temporary credentials",
44+
Long: `CLI tool for retrieving AWS temporary credentials using SAML providers, or specified method of retrieval - i.e. force AWS_WEB_IDENTITY.
45+
Useful in situations like CI jobs or containers where multiple env vars might be present.
46+
Stores them under the $HOME/.aws/credentials file under a specified path or returns the crednetial_process payload for use in config`,
47+
Version: fmt.Sprintf("%s-%s", Version, Revision),
48+
SilenceUsage: true,
49+
SilenceErrors: true,
50+
},
51+
}
52+
53+
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")
54+
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.
55+
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`)
56+
r.Cmd.PersistentFlags().StringVarP(&rf.cfgSectionName, "cfg-section", "", "", "Config section name in the default AWS credentials file. To enable priofi")
57+
// When specifying store in profile the config section name must be provided
58+
r.Cmd.MarkFlagsRequiredTogether("store-profile", "cfg-section")
59+
r.Cmd.PersistentFlags().IntVarP(&rf.duration, "max-duration", "d", 900, `Override default max session duration, in seconds, of the role session [900-43200].
60+
NB: This cannot be higher than the 3600 as the API does not allow for AssumeRole for sessions longer than an hour`)
61+
r.Cmd.PersistentFlags().BoolVarP(&rf.verbose, "verbose", "v", false, "Verbose output")
62+
r.dataDirInit()
63+
return r
64+
}
65+
66+
// SubCommands is a standalone Builder helper
67+
//
68+
// IF you are making your sub commands public, you can just pass them directly `WithSubCommands`
69+
func SubCommands() []func(*Root) {
70+
return []func(*Root){
71+
newSamlCmd,
72+
newClearCmd,
73+
newSpecificIdentityCmd,
74+
}
75+
}
76+
77+
func (r *Root) WithSubCommands(iocFuncs ...func(rootCmd *Root)) {
78+
for _, fn := range iocFuncs {
79+
fn(r)
80+
}
81+
}
82+
83+
func (r *Root) Execute(ctx context.Context) error {
84+
return r.Cmd.ExecuteContext(ctx)
85+
}
86+
87+
func (r *Root) dataDirInit() error {
88+
datadir := path.Join(credentialexchange.HomeDir(), fmt.Sprintf(".%s-data", credentialexchange.SELF_NAME))
89+
if _, err := os.Stat(datadir); err != nil {
90+
return os.MkdirAll(datadir, 0755)
91+
}
92+
r.Datadir = datadir
93+
return nil
94+
}

cmd/cmd_test.go renamed to cmd/awscliauth_test.go

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,30 @@ package cmd_test
22

33
import (
44
"bytes"
5+
"context"
6+
"errors"
57
"io"
68
"testing"
79

810
"github.com/DevLabFoundry/aws-cli-auth/cmd"
11+
"github.com/DevLabFoundry/aws-cli-auth/internal/web"
912
)
1013

14+
func cmdHelperExecutor(t *testing.T, args []string) (stdOut *bytes.Buffer, errOut *bytes.Buffer, err error) {
15+
t.Helper()
16+
errOut = new(bytes.Buffer)
17+
stdOut = new(bytes.Buffer)
18+
c := cmd.New()
19+
c.WithSubCommands(cmd.SubCommands()...)
20+
c.Cmd.SetArgs(args)
21+
c.Cmd.SetErr(errOut)
22+
c.Cmd.SetOut(stdOut)
23+
err = c.Execute(context.Background())
24+
return stdOut, errOut, err
25+
}
26+
1127
func Test_helpers_for_command(t *testing.T) {
28+
1229
ttests := map[string]struct{}{
1330
"clear-cache": {},
1431
"saml": {},
@@ -17,27 +34,23 @@ func Test_helpers_for_command(t *testing.T) {
1734
for name := range ttests {
1835
t.Run(name, func(t *testing.T) {
1936
cmdArgs := []string{name, "--help"}
20-
b := new(bytes.Buffer)
21-
o := new(bytes.Buffer)
22-
cmd := cmd.RootCmd
23-
cmd.SetArgs(cmdArgs)
24-
cmd.SetErr(b)
25-
cmd.SetOut(o)
26-
cmd.Execute()
27-
err, _ := io.ReadAll(b)
28-
if len(err) > 0 {
37+
stdOut, errOut, err := cmdHelperExecutor(t, cmdArgs)
38+
if err != nil {
39+
t.Fatal(err)
40+
}
41+
errCheck, _ := io.ReadAll(errOut)
42+
if len(errCheck) > 0 {
2943
t.Fatal("got err, wanted nil")
3044
}
31-
out, _ := io.ReadAll(o)
32-
if len(out) <= 0 {
45+
outCheck, _ := io.ReadAll(stdOut)
46+
if len(outCheck) <= 0 {
3347
t.Fatalf("got empty, wanted a help message")
3448
}
3549
})
3650
}
3751
}
3852

39-
func Test_Saml(t *testing.T) {
40-
t.Skip()
53+
func Test_Saml_timeout(t *testing.T) {
4154
t.Run("standard non sso should fail with incorrect saml URLs", func(t *testing.T) {
4255
cmdArgs := []string{"saml", "-p",
4356
"https://httpbin.org/anything/app123",
@@ -52,13 +65,8 @@ func Test_Saml(t *testing.T) {
5265
"14400",
5366
"--reload-before",
5467
"120"}
55-
b := new(bytes.Buffer)
56-
o := new(bytes.Buffer)
57-
cmd := cmd.RootCmd
58-
cmd.SetArgs(cmdArgs)
59-
cmd.SetErr(b)
60-
cmd.SetOut(o)
61-
if err := cmd.Execute(); err == nil {
68+
_, _, err := cmdHelperExecutor(t, cmdArgs)
69+
if err == nil && !errors.Is(err, web.ErrTimedOut) {
6270
t.Error("got nil, wanted an error")
6371
}
6472
// err, _ := io.ReadAll(b)

cmd/clear.go

Lines changed: 44 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,53 @@ import (
1010
"github.com/spf13/cobra"
1111
)
1212

13-
var (
14-
force bool
15-
ClearCmd = &cobra.Command{
13+
type clearFlags struct {
14+
force bool
15+
}
16+
17+
func newClearCmd(r *Root) {
18+
flags := &clearFlags{}
19+
20+
cmd := &cobra.Command{
1621
Use: "clear-cache <flags>",
1722
Short: "Clears any stored credentials in the OS secret store",
18-
RunE: clear,
23+
RunE: func(cmd *cobra.Command, args []string) error {
24+
user, err := user.Current()
25+
if err != nil {
26+
return err
27+
}
28+
if err := samlInitConfig(); err != nil {
29+
return err
30+
}
31+
secretStore, err := credentialexchange.NewSecretStore("",
32+
fmt.Sprintf("%s-%s", credentialexchange.SELF_NAME, credentialexchange.RoleKeyConverter("")),
33+
os.TempDir(), user.Username)
34+
35+
if err != nil {
36+
return err
37+
}
38+
39+
if flags.force {
40+
w := &web.Web{}
41+
if err := w.ForceKill(r.Datadir); err != nil {
42+
return err
43+
}
44+
fmt.Fprint(os.Stderr, "Chromium Cache cleared")
45+
}
46+
47+
if err := secretStore.ClearAll(); err != nil {
48+
fmt.Fprint(os.Stderr, err.Error())
49+
}
50+
51+
if err := os.Remove(credentialexchange.ConfigIniFile("")); err != nil {
52+
return err
53+
}
54+
55+
return nil
56+
},
1957
}
20-
)
2158

22-
func init() {
23-
cobra.OnInitialize(samlInitConfig)
24-
ClearCmd.PersistentFlags().BoolVarP(&force, "force", "f", false, `If aws-cli-auth exited improprely in a previous run there is a chance that there could be hanging processes left over.
59+
cmd.PersistentFlags().BoolVarP(&flags.force, "force", "f", false, `If aws-cli-auth exited improprely in a previous run there is a chance that there could be hanging processes left over.
2560
2661
This will forcefully all chromium processes.
2762
@@ -32,37 +67,6 @@ Use with caution.
3267
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,
3368
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
3469
`)
35-
RootCmd.AddCommand(ClearCmd)
36-
}
37-
38-
func clear(cmd *cobra.Command, args []string) error {
39-
user, err := user.Current()
40-
if err != nil {
41-
return err
42-
}
43-
secretStore, err := credentialexchange.NewSecretStore("",
44-
fmt.Sprintf("%s-%s", credentialexchange.SELF_NAME, credentialexchange.RoleKeyConverter("")),
45-
os.TempDir(), user.Username)
46-
47-
if err != nil {
48-
return err
49-
}
50-
51-
if force {
52-
w := &web.Web{}
53-
if err := w.ForceKill(datadir); err != nil {
54-
return err
55-
}
56-
fmt.Fprint(os.Stderr, "Chromium Cache cleared")
57-
}
58-
59-
if err := secretStore.ClearAll(); err != nil {
60-
fmt.Fprint(os.Stderr, err.Error())
61-
}
62-
63-
if err := os.Remove(credentialexchange.ConfigIniFile("")); err != nil {
64-
return err
65-
}
6670

67-
return nil
71+
r.Cmd.AddCommand(cmd)
6872
}

cmd/root.go

Lines changed: 0 additions & 52 deletions
This file was deleted.

0 commit comments

Comments
 (0)