Skip to content

Commit

Permalink
Merge pull request #822 from synfinatic/home-url-exec
Browse files Browse the repository at this point in the history
support `~` and $HOME for UrlExecCommand
  • Loading branch information
synfinatic authored Apr 4, 2024
2 parents 4835d18 + 175c4a3 commit 32e1210
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

* Add `aws-sso-cli completion --source` flag to generate completion script and
print to stdout. #779
* UrlExecCommand now supports commands in `~` and the `$HOME` environment variable. #816

## [v1.14.3] - 2024-01-15

Expand Down
8 changes: 8 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,14 @@ UrlExecCommand:
- "%s"
```

###### Use custom shell script
```yaml
UrlAction: exec
UrlExecCommand:
- ~/bin/open_url.sh
- "%s"
```

**Note:** If your `ProfileFormat` generates a _ProfileName_ with an `&`, then
`{{ .AccountId }}:{{ .RoleName }}` will be used as the Firefox container name instead.

Expand Down
18 changes: 12 additions & 6 deletions internal/url/url.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ func (h *HandleUrl) Open() error {
if err == nil {
log.Infof("Please open URL copied to clipboard.\n")
} else {
err = fmt.Errorf("Unable to copy URL to clipboard: %s", err.Error())
err = fmt.Errorf("unable to copy URL to clipboard: %s", err.Error())
}

case Exec:
Expand Down Expand Up @@ -223,13 +223,13 @@ func (h *HandleUrl) Open() error {
err = urlOpenerWith(h.Url, h.Browser)
}
if err != nil {
err = fmt.Errorf("Unable to open URL with %s: %s", browser, err.Error())
err = fmt.Errorf("unable to open URL with %s: %s", browser, err.Error())
} else {
log.Infof("Opening URL in: %s\n", browser)
}

default:
err = fmt.Errorf("Unsupported Open action: %s", string(h.Action))
err = fmt.Errorf("unsupported Open action: %s", string(h.Action))
}

return err
Expand Down Expand Up @@ -280,11 +280,14 @@ func execWithUrl(command []string, url string) error {
log.Debugf("exec command as array: %s", cmdStr)
cmd = exec.Command(program, cmdList...)

// add $HOME to our environment
cmd.Env = append(cmd.Environ(), fmt.Sprintf("HOME=%s", os.Getenv("HOME")))

// var stderr bytes.Buffer
// cmd.Stderr = &stderr
err = cmd.Start() // Don't use Run() because sometimes firefox does bad things?
if err != nil {
err = fmt.Errorf("Unable to exec `%s`: %s", cmdStr, err)
err = fmt.Errorf("unable to exec `%s`: %s", cmdStr, err)
}
log.Debugf("Opened our URL with %s", command[0])
return err
Expand All @@ -297,7 +300,7 @@ func commandBuilder(command []string, url string) (string, []string, error) {
replaced := false

if len(command) < 2 {
return program, cmdList, fmt.Errorf("Invalid UrlExecCommand has fewer than 2 arguments")
return program, cmdList, fmt.Errorf("invalid UrlExecCommand has fewer than 2 arguments")
}

for i, v := range command {
Expand All @@ -312,9 +315,12 @@ func commandBuilder(command []string, url string) (string, []string, error) {
}

if !replaced {
return program, cmdList, fmt.Errorf("Invalid UrlExecCommand has no `%%s` for URL")
return program, cmdList, fmt.Errorf("invalid UrlExecCommand has no `%%s` for URL")
}

// if program is ~/something, expand it
program = utils.GetHomePath(program)

return program, cmdList, nil
}

Expand Down
5 changes: 5 additions & 0 deletions internal/url/url_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"fmt"
"net"
"net/url"
"os"
"testing"

"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -173,6 +174,10 @@ func TestCommandBuilder(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "foo", cmd)
assert.Equal(t, []string{"bar", "url"}, l)

cmd, _, err = commandBuilder([]string{"~/foo", "bar", "%s"}, "url")
assert.NoError(t, err)
assert.Equal(t, fmt.Sprintf("%s/foo", os.Getenv("HOME")), cmd)
}

func TestSelectElement(t *testing.T) {
Expand Down
18 changes: 9 additions & 9 deletions sso/awssso_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func (as *AWSSSO) reauthenticate() error {
err := as.registerClient(false)
log.Tracef("<- reauthenticate()")
if err != nil {
return fmt.Errorf("Unable to register client with AWS SSO: %s", err.Error())
return fmt.Errorf("unable to register client with AWS SSO: %s", err.Error())
}

err = as.startDeviceAuthorization()
Expand All @@ -99,17 +99,17 @@ func (as *AWSSSO) reauthenticate() error {
log.Debugf("startDeviceAuthorization failed. Forcing refresh of registerClient")
// startDeviceAuthorization can fail if our cached registerClient token is invalid
if err = as.registerClient(true); err != nil {
return fmt.Errorf("Unable to register client with AWS SSO: %s", err.Error())
return fmt.Errorf("unable to register client with AWS SSO: %s", err.Error())
}
if err = as.startDeviceAuthorization(); err != nil {
return fmt.Errorf("Unable to start device authorization with AWS SSO: %s", err.Error())
return fmt.Errorf("unable to start device authorization with AWS SSO: %s", err.Error())
}
}

auth, err := as.getDeviceAuthInfo()
log.Tracef("<- reauthenticate()")
if err != nil {
return fmt.Errorf("Unable to get device auth info from AWS SSO: %s", err.Error())
return fmt.Errorf("unable to get device auth info from AWS SSO: %s", err.Error())
}

action := as.urlAction
Expand All @@ -129,7 +129,7 @@ func (as *AWSSSO) reauthenticate() error {

err = as.createToken()
if err != nil {
return fmt.Errorf("Unable to create new AWS SSO token: %s", err.Error())
return fmt.Errorf("unable to create new AWS SSO token: %s", err.Error())
}

return nil
Expand Down Expand Up @@ -177,7 +177,7 @@ func (as *AWSSSO) registerClient(force bool) error {
}
err = as.store.SaveRegisterClientData(as.StoreKey(), as.ClientData)
if err != nil {
log.WithError(err).Errorf("Unable to save RegisterClientData for %s", as.StoreKey())
log.WithError(err).Errorf("unable to save RegisterClientData for %s", as.StoreKey())
}
return nil
}
Expand Down Expand Up @@ -222,7 +222,7 @@ type DeviceAuthInfo struct {
func (as *AWSSSO) getDeviceAuthInfo() (DeviceAuthInfo, error) {
log.Tracef("getDeviceAuthInfo()")
if as.DeviceAuth.VerificationUri == "" {
return DeviceAuthInfo{}, fmt.Errorf("No valid verification url is available for %s", as.StoreKey())
return DeviceAuthInfo{}, fmt.Errorf("no valid verification url is available for %s", as.StoreKey())
}

info := DeviceAuthInfo{
Expand Down Expand Up @@ -290,7 +290,7 @@ func (as *AWSSSO) createToken() error {
err = as.store.SaveCreateTokenResponse(as.StoreKey(), as.Token)
as.tokenLock.RUnlock()
if err != nil {
log.WithError(err).Errorf("Unable to save CreateTokenResponse")
log.WithError(err).Errorf("unable to save CreateTokenResponse")
}

return nil
Expand All @@ -310,7 +310,7 @@ func (as *AWSSSO) Logout() error {

// delete the value from the store so we don't think we have a valid token
if err := as.store.DeleteCreateTokenResponse(as.key); err != nil {
log.WithError(err).Errorf("Unable to delete AccessToken from secure store")
log.WithError(err).Errorf("unable to delete AccessToken from secure store")
}
}

Expand Down
12 changes: 6 additions & 6 deletions sso/awssso_auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,23 +417,23 @@ func TestAuthenticateFailure(t *testing.T) {
}

err = as.Authenticate("print", "fake-browser")
assert.Contains(t, err.Error(), "Unable to register client with AWS SSO")
assert.Contains(t, err.Error(), "unable to register client with AWS SSO")

err = as.Authenticate("print", "fake-browser")
assert.Contains(t, err.Error(), "Unable to start device authorization")
assert.Contains(t, err.Error(), "unable to start device authorization")

err = as.Authenticate("print", "fake-browser")
assert.Contains(t, err.Error(), "createToken:")

err = as.Authenticate("print", "fake-browser")
assert.Contains(t, err.Error(), "No valid verification url")
assert.Contains(t, err.Error(), "no valid verification url")

err = as.Authenticate("invalid", "fake-browser")
assert.Contains(t, err.Error(), "Unsupported Open action")
assert.Contains(t, err.Error(), "unsupported Open action")

as.SSOConfig.AuthUrlAction = "invalid"
err = as.Authenticate("print", "fake-browser")
assert.Contains(t, err.Error(), "Unsupported Open action")
assert.Contains(t, err.Error(), "unsupported Open action")
}

func TestReauthenticate(t *testing.T) {
Expand Down Expand Up @@ -528,7 +528,7 @@ func TestReauthenticate(t *testing.T) {
}

err = as.reauthenticate()
assert.Contains(t, err.Error(), "Unable to exec")
assert.Contains(t, err.Error(), "unable to exec")
}

func TestLogout(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion sso/roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ type AWSRole struct {
}

// AccountIds returns all the configured AWS SSO AccountIds
func (r *Roles) AccountIds() []int64 {
func (r *Roles) AccountIds() []int64 { // nolint: revive
ret := []int64{}
for id := range r.Accounts {
ret = append(ret, id)
Expand Down

0 comments on commit 32e1210

Please sign in to comment.