Skip to content

Commit 08025db

Browse files
authored
Merge pull request #389 from synfinatic/predict-in-binary
Context sensitive prediction
2 parents 7f86c33 + 6d213f6 commit 08025db

16 files changed

+929
-99
lines changed

CHANGELOG.md

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
# AWS SSO CLI Changelog
22

3+
## Unreleased
4+
5+
### New Features
6+
7+
* Auto-completion is now context sensitive to the `--sso`, `--account`, and
8+
`--role` flags and filters results accordingly.
9+
10+
### Bugs
11+
312
## [v1.9.1] - 2022-05-09
413

514
## Bugs
615

716
* Fix `config` command when user has no `UrlExecCommand` defined #385
8-
* `console` no longer warns when a role is missing the Color or Icon tag
17+
* `console` no longer warns when a role is missing the Color or Icon tag
918

1019
## [v1.9.0] - 2022-05-08
1120

@@ -353,7 +362,8 @@
353362

354363
Initial release
355364

356-
[Unreleased]: https://github.com/synfinatic/aws-sso-cli/compare/v1.9.0...main
365+
[Unreleased]: https://github.com/synfinatic/aws-sso-cli/compare/v1.9.1...main
366+
[v1.9.1]: https://github.com/synfinatic/aws-sso-cli/releases/tag/v1.9.1
357367
[v1.9.0]: https://github.com/synfinatic/aws-sso-cli/releases/tag/v1.9.0
358368
[v1.8.1]: https://github.com/synfinatic/aws-sso-cli/releases/tag/v1.8.1
359369
[v1.8.0]: https://github.com/synfinatic/aws-sso-cli/releases/tag/v1.8.0

cmd/list_cmd.go

+3-19
Original file line numberDiff line numberDiff line change
@@ -24,29 +24,13 @@ import (
2424
"sort"
2525
"strings"
2626

27+
"github.com/synfinatic/aws-sso-cli/internal/predictor"
2728
"github.com/synfinatic/aws-sso-cli/internal/utils"
2829
"github.com/synfinatic/aws-sso-cli/sso"
2930
"github.com/synfinatic/aws-sso-cli/storage"
3031
"github.com/synfinatic/gotable"
3132
)
3233

33-
// keys match AWSRoleFlat header and value is the description
34-
var allListFields = map[string]string{
35-
"Id": "Column Index",
36-
"Arn": "AWS Role Resource Name",
37-
"AccountId": "AWS AccountID",
38-
"AccountName": "Configured Account Name",
39-
"AccountAlias": "AWS Account Alias",
40-
"DefaultRegion": "Default AWS Region",
41-
"EmailAddress": "Root Email for AWS account",
42-
"ExpiresStr": "Time until STS creds expire",
43-
"Expires": "Unix Epoch when STS creds expire",
44-
"RoleName": "AWS Role Name",
45-
"SSO": "AWS SSO Instance Name",
46-
"Via": "Role Chain Via",
47-
"Profile": "AWS_SSO_PROFILE / AWS_PROFILE",
48-
}
49-
5034
type ListCmd struct {
5135
ListFields bool `kong:"short='f',help='List available fields',xor='fields'"`
5236
CSV bool `kong:"help='Generate CSV instead of a table',xor='fields'"`
@@ -196,15 +180,15 @@ func (cfn ConfigFieldNames) GetHeader(fieldName string) (string, error) {
196180
// listAllFields generates a table with all the AWSRoleFlat fields we can print
197181
func listAllFields() {
198182
names := []string{}
199-
for k := range allListFields {
183+
for k := range predictor.AllListFields {
200184
names = append(names, k)
201185
}
202186
sort.Strings(names)
203187
ts := []gotable.TableStruct{}
204188
for _, k := range names {
205189
ts = append(ts, ConfigFieldNames{
206190
Field: k,
207-
Description: allListFields[k],
191+
Description: predictor.AllListFields[k],
208192
})
209193
}
210194

cmd/main.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/sirupsen/logrus"
3030
"github.com/synfinatic/aws-sso-cli/awsconfig"
3131
"github.com/synfinatic/aws-sso-cli/internal/helper"
32+
"github.com/synfinatic/aws-sso-cli/internal/predictor"
3233
"github.com/synfinatic/aws-sso-cli/internal/utils"
3334
"github.com/synfinatic/aws-sso-cli/sso"
3435
"github.com/synfinatic/aws-sso-cli/storage"
@@ -82,13 +83,11 @@ var DEFAULT_CONFIG map[string]interface{} = map[string]interface{}{
8283
"ListFields": []string{"AccountId", "AccountAlias", "RoleName", "Profile", "ExpiresStr"},
8384
"ConsoleDuration": 60,
8485
"UrlAction": "open",
85-
"UrlExecCommand": "",
86+
"ConfigProfilesUrlAction": "open",
8687
"LogLevel": "warn",
8788
"DefaultSSO": "Default",
8889
"FirefoxOpenUrlInContainer": false,
8990
"AutoConfigCheck": false,
90-
"ConfigProfilesUrlAction": "",
91-
"ConfigUrlAction": "", // deprecated
9291
"ProfileFormat": `{{ .AccountId }}:{{ .RoleName }}`,
9392
"CacheRefresh": 24, // in hours
9493
}
@@ -134,6 +133,7 @@ func main() {
134133
utils.SetLogger(log)
135134
awsconfig.SetLogger(log)
136135
helper.SetLogger(log)
136+
predictor.SetLogger(log)
137137

138138
if err := logLevelValidate(cli.LogLevel); err != nil {
139139
log.Fatalf("%s", err.Error())
@@ -209,7 +209,7 @@ func parseArgs(cli *CLI) (*kong.Context, sso.OverrideSettings) {
209209
vars,
210210
)
211211

212-
p := NewPredictor(utils.GetHomePath(INSECURE_CACHE_FILE), utils.GetHomePath(CONFIG_FILE))
212+
p := predictor.NewPredictor(utils.GetHomePath(INSECURE_CACHE_FILE), utils.GetHomePath(CONFIG_FILE))
213213

214214
kongplete.Complete(parser,
215215
kongplete.WithPredictors(

cmd/setup_prompt.go

+3-22
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"strconv"
2828

2929
"github.com/manifoldco/promptui"
30+
"github.com/synfinatic/aws-sso-cli/internal/predictor"
3031
"github.com/synfinatic/aws-sso-cli/internal/utils"
3132
)
3233

@@ -35,26 +36,6 @@ const (
3536
START_FQDN_FORMAT = "%s.awsapps.com"
3637
)
3738

38-
// https://docs.aws.amazon.com/general/latest/gr/sso.html
39-
var AvailableAwsSSORegions []string = []string{
40-
"us-east-1",
41-
"us-east-2",
42-
"us-west-2",
43-
"ap-south-1",
44-
"ap-northeast-2",
45-
"ap-southeast-1",
46-
"ap-southeast-2",
47-
"ap-northeast-1",
48-
"ca-central-1",
49-
"eu-central-1",
50-
"eu-west-1",
51-
"eu-west-2",
52-
"eu-west-3",
53-
"eu-north-1",
54-
"sa-east-1",
55-
"us-gov-west-1",
56-
}
57-
5839
type selectOptions struct {
5940
Name string
6041
Value string
@@ -184,7 +165,7 @@ func promptAwsSsoRegion(defaultValue string) string {
184165
fmt.Printf("\n")
185166

186167
items := []selectOptions{}
187-
for _, x := range AvailableAwsSSORegions {
168+
for _, x := range predictor.AvailableAwsSSORegions {
188169
items = append(items, selectOptions{
189170
Value: x,
190171
Name: x,
@@ -220,7 +201,7 @@ func promptDefaultRegion(defaultValue string) string {
220201
Value: "",
221202
},
222203
}
223-
for _, x := range AvailableAwsRegions {
204+
for _, x := range predictor.AvailableAwsRegions {
224205
items = append(items, selectOptions{
225206
Value: x,
226207
Name: x,

docs/commands.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,8 @@ in your shell via [eval](#eval) or [exec](#exec).
301301
### completions
302302

303303
Configures your appropriate shell configuration file to add auto-complete
304-
functionality for commands, flags and options. Must restart your shell
305-
for this to take effect.
304+
and [shell helper](#shell-helper) functionality for commands, flags and
305+
options. Must restart your shell for this to take effect.
306306

307307
For more information about this feature, please read [the quickstart](
308308
quickstart.md#enabling-auto-completion-in-your-shell).
@@ -390,7 +390,7 @@ If you want to pass specific args to `aws-sso-profile` you can use the
390390
`$AWS_SSO_HELPER_ARGS` environment variable. If nothing is set, then
391391
`--level error` is used.
392392

393-
Currently the following shells are supported:
393+
Currently the following shells are fully supported:
394394

395395
* `bash`
396396
* [zsh - TBD](https://github.com/synfinatic/aws-sso-cli/issues/360)

docs/quickstart.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ and the `$AWS_PROFILE` environment variable, AWS SSO CLI can support that as wel
183183

184184
#### Configuration
185185

186-
Run: `aws-sso config --open [open|clip|exec]`
186+
Run: `aws-sso config`
187187

188188
This will add the following lines (example) to your `~/.aws/config` file:
189189

internal/predictor/comp_vars.go

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package predictor
2+
3+
/*
4+
* AWS SSO CLI
5+
* Copyright (c) 2021-2022 Aaron Turner <synfinatic at gmail dot com>
6+
*
7+
* This program is free software: you can redistribute it
8+
* and/or modify it under the terms of the GNU General Public License as
9+
* published by the Free Software Foundation, either version 3 of the
10+
* License, or with the authors permission any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
21+
import (
22+
"os"
23+
"strconv"
24+
"strings"
25+
)
26+
27+
// getSSOFlag returns the value of -S/--sso from $COMP_LINE or empty string
28+
func getSSOFlag() string {
29+
compLine, ok := os.LookupEnv("COMP_LINE")
30+
if !ok {
31+
return ""
32+
}
33+
34+
return flagValue(compLine, []string{"-S", "--sso"})
35+
}
36+
37+
// getAccountIdFlag returns the value of -A/--account from $COMP_LINE or
38+
// -1 for none
39+
func getAccountIdFlag() int64 {
40+
compLine, ok := os.LookupEnv("COMP_LINE")
41+
if !ok {
42+
return -1
43+
}
44+
45+
aStr := flagValue(compLine, []string{"-A", "--account"})
46+
if aStr == "" {
47+
return -1
48+
}
49+
aid, _ := strconv.ParseInt(aStr, 10, 64)
50+
return aid
51+
}
52+
53+
// getRoleFlag returns the value of -R/--role from $COMP_LINE or empty string
54+
func getRoleFlag() string {
55+
compLine, ok := os.LookupEnv("COMP_LINE")
56+
if !ok {
57+
return ""
58+
}
59+
60+
return flagValue(compLine, []string{"-R", "--role"})
61+
}
62+
63+
func flagValue(line string, flags []string) string {
64+
var flag string
65+
i := 0
66+
67+
// remove double spaces
68+
line = strings.ReplaceAll(line, " ", "")
69+
70+
// skip past our executable
71+
i = strings.Index(line, " ")
72+
if i < 0 {
73+
return ""
74+
}
75+
76+
line = line[i:]
77+
78+
for _, flag = range flags {
79+
i = strings.Index(line, flag)
80+
if i > 0 {
81+
i += len(flag)
82+
line = line[i:] // jump past our flag
83+
break
84+
}
85+
}
86+
87+
// missing completely or need a space + at least 1 char
88+
if i < 0 || len(line) < 2 {
89+
return ""
90+
}
91+
92+
line = line[1:] // eat the space
93+
94+
// find the next space
95+
i = strings.Index(line, " ")
96+
if i < 0 {
97+
// let kongplete do the work
98+
return ""
99+
}
100+
101+
// return a result
102+
return line[:i]
103+
}

internal/predictor/comp_vars_test.go

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package predictor
2+
3+
/*
4+
* AWS SSO CLI
5+
* Copyright (c) 2021-2022 Aaron Turner <synfinatic at gmail dot com>
6+
*
7+
* This program is free software: you can redistribute it
8+
* and/or modify it under the terms of the GNU General Public License as
9+
* published by the Free Software Foundation, either version 3 of the
10+
* License, or with the authors permission any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
*/
20+
21+
import (
22+
"os"
23+
"testing"
24+
25+
"github.com/stretchr/testify/assert"
26+
)
27+
28+
func TestGetSSOFlag(t *testing.T) {
29+
defer func() { os.Unsetenv("COMP_LINE") }()
30+
31+
os.Setenv("COMP_LINE", "aws-sso eval -S Default -R")
32+
assert.Equal(t, "Default", getSSOFlag())
33+
34+
os.Setenv("COMP_LINE", "aws-sso eval --sso Default -R")
35+
assert.Equal(t, "Default", getSSOFlag())
36+
37+
os.Setenv("COMP_LINE", "aws-sso eval --so Default -R")
38+
assert.Equal(t, "", getSSOFlag())
39+
}
40+
41+
func TestGetAccountIdFlag(t *testing.T) {
42+
defer func() { os.Unsetenv("COMP_LINE") }()
43+
44+
os.Setenv("COMP_LINE", "aws-sso eval -A 5555 -R")
45+
assert.Equal(t, int64(5555), getAccountIdFlag())
46+
47+
os.Setenv("COMP_LINE", "aws-sso eval --account 5555 -R")
48+
assert.Equal(t, int64(5555), getAccountIdFlag())
49+
50+
os.Setenv("COMP_LINE", "aws-sso eval --account -5555 -R")
51+
assert.Equal(t, int64(-5555), getAccountIdFlag())
52+
53+
os.Setenv("COMP_LINE", "aws-sso eval --accoun 5555 -R")
54+
assert.Equal(t, int64(-1), getAccountIdFlag())
55+
}
56+
57+
func TestGetRoleFlag(t *testing.T) {
58+
defer func() { os.Unsetenv("COMP_LINE") }()
59+
60+
os.Setenv("COMP_LINE", "aws-sso eval -R Default -A")
61+
assert.Equal(t, "Default", getRoleFlag())
62+
63+
os.Setenv("COMP_LINE", "aws-sso eval --role Default -A")
64+
assert.Equal(t, "Default", getRoleFlag())
65+
66+
os.Setenv("COMP_LINE", "aws-sso eval --rol Default -A")
67+
assert.Equal(t, "", getRoleFlag())
68+
}
69+
70+
func TestFlagValue(t *testing.T) {
71+
flags := []string{"-S", "--sso"}
72+
73+
assert.Equal(t, "", flagValue("", flags))
74+
assert.Equal(t, "", flagValue("aws-sso eval -S", flags))
75+
assert.Equal(t, "", flagValue("aws-sso eval -S D", flags))
76+
assert.Equal(t, "", flagValue("aws-sso eval -S Default", flags))
77+
assert.Equal(t, "Default", flagValue("aws-sso eval -S Default ", flags))
78+
}

0 commit comments

Comments
 (0)