Skip to content

Commit

Permalink
Merge pull request #148 from 99designs/move-commands-to-cli-package
Browse files Browse the repository at this point in the history
Move go files into top level packages
  • Loading branch information
lox committed Aug 28, 2017
2 parents 5739bc1 + 60fe0a7 commit 7d4cd04
Show file tree
Hide file tree
Showing 22 changed files with 380 additions and 330 deletions.
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
language: go

install: ./ci/install.sh
install: ./scripts/ci_install.sh

go:
- 1.7
- 1.8
- 1.9

os:
- linux
Expand Down
25 changes: 22 additions & 3 deletions add.go → cli/add.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package main
package cli

import (
"fmt"
"os"

"github.com/99designs/aws-vault/prompt"
"github.com/99designs/aws-vault/vault"
"github.com/99designs/keyring"
"github.com/aws/aws-sdk-go/aws/credentials"
"gopkg.in/alecthomas/kingpin.v2"
Expand All @@ -16,6 +17,24 @@ type AddCommandInput struct {
FromEnv bool
}

func ConfigureAddCommand(app *kingpin.Application) {
input := AddCommandInput{}

cmd := app.Command("add", "Adds credentials, prompts if none provided")
cmd.Arg("profile", "Name of the profile").
Required().
StringVar(&input.Profile)

cmd.Flag("env", "Read the credentials from the environment").
BoolVar(&input.FromEnv)

cmd.Action(func(c *kingpin.ParseContext) error {
input.Keyring = keyringImpl
AddCommand(app, input)
return nil
})
}

func AddCommand(app *kingpin.Application, input AddCommandInput) {
var accessKeyId, secretKey string

Expand All @@ -41,7 +60,7 @@ func AddCommand(app *kingpin.Application, input AddCommandInput) {
}

creds := credentials.Value{AccessKeyID: accessKeyId, SecretAccessKey: secretKey}
provider := &KeyringProvider{Keyring: input.Keyring, Profile: input.Profile}
provider := &vault.KeyringProvider{Keyring: input.Keyring, Profile: input.Profile}

if err := provider.Store(creds); err != nil {
app.Fatalf(err.Error())
Expand All @@ -56,7 +75,7 @@ func AddCommand(app *kingpin.Application, input AddCommandInput) {
return
}

sessions, err := NewKeyringSessions(input.Keyring, profiles)
sessions, err := vault.NewKeyringSessions(input.Keyring, profiles)
if err != nil {
app.Fatalf(err.Error())
return
Expand Down
14 changes: 11 additions & 3 deletions add_test.go → cli/add_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package main
package cli

import "os"
import (
"os"

kingpin "gopkg.in/alecthomas/kingpin.v2"
)

func ExampleAddCommand() {
os.Setenv("AWS_ACCESS_KEY_ID", "llamas")
Expand All @@ -13,7 +17,11 @@ func ExampleAddCommand() {
defer os.Unsetenv("AWS_VAULT_BACKEND")
defer os.Unsetenv("AWS_VAULT_FILE_PASSPHRASE")

run([]string{"add", "--env", "foo"}, os.Exit)
app := kingpin.New(`aws-vault`, ``)
ConfigureGlobals(app)
ConfigureAddCommand(app)
kingpin.MustParse(app.Parse([]string{"add", "--env", "foo"}))

// Output:
// Added credentials to profile "foo" in vault
}
59 changes: 55 additions & 4 deletions exec.go → cli/exec.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package main
package cli

import (
"log"
"os"
"os/exec"
"os/signal"
"strings"
"syscall"
"time"

"github.com/99designs/aws-vault/prompt"
"github.com/99designs/aws-vault/server"
"github.com/99designs/aws-vault/vault"
"github.com/99designs/keyring"
"gopkg.in/alecthomas/kingpin.v2"
)
Expand All @@ -27,6 +30,54 @@ type ExecCommandInput struct {
NoSession bool
}

func ConfigureExecCommand(app *kingpin.Application) {
input := ExecCommandInput{}

cmd := app.Command("exec", "Executes a command with AWS credentials in the environment")
cmd.Flag("no-session", "Use root credentials, no session created").
Short('n').
BoolVar(&input.NoSession)

cmd.Flag("session-ttl", "Expiration time for aws session").
Default("4h").
OverrideDefaultFromEnvar("AWS_SESSION_TTL").
Short('t').
DurationVar(&input.Duration)

cmd.Flag("assume-role-ttl", "Expiration time for aws assumed role").
Default("15m").
OverrideDefaultFromEnvar("AWS_ASSUME_ROLE_TTL").
DurationVar(&input.RoleDuration)

cmd.Flag("mfa-token", "The mfa token to use").
Short('m').
StringVar(&input.MfaToken)

cmd.Flag("server", "Run the server in the background for credentials").
Short('s').
BoolVar(&input.StartServer)

cmd.Arg("profile", "Name of the profile").
Required().
StringVar(&input.Profile)

cmd.Arg("cmd", "Command to execute").
Default(os.Getenv("SHELL")).
StringVar(&input.Command)

cmd.Arg("args", "Command arguments").
StringsVar(&input.Args)

cmd.Action(func(c *kingpin.ParseContext) error {
input.Keyring = keyringImpl
input.MfaPrompt = prompt.Method(GlobalFlags.PromptDriver)
input.Signals = make(chan os.Signal)
signal.Notify(input.Signals, os.Interrupt, os.Kill)
ExecCommand(app, input)
return nil
})
}

func ExecCommand(app *kingpin.Application, input ExecCommandInput) {
if os.Getenv("AWS_VAULT") != "" {
app.Fatalf("aws-vault sessions should be nested with care, unset $AWS_VAULT to force")
Expand All @@ -46,7 +97,7 @@ func ExecCommand(app *kingpin.Application, input ExecCommandInput) {
return
}

creds, err := NewVaultCredentials(input.Keyring, input.Profile, VaultOptions{
creds, err := vault.NewVaultCredentials(input.Keyring, input.Profile, vault.VaultOptions{
SessionDuration: input.Duration,
AssumeRoleDuration: input.RoleDuration,
MfaToken: input.MfaToken,
Expand All @@ -60,11 +111,11 @@ func ExecCommand(app *kingpin.Application, input ExecCommandInput) {

val, err := creds.Get()
if err != nil {
app.Fatalf(formatCredentialError(input.Profile, profiles, err))
app.Fatalf(vault.FormatCredentialError(input.Profile, profiles, err))
}

if input.StartServer {
if err := startCredentialsServer(creds); err != nil {
if err := server.StartCredentialsServer(creds); err != nil {
app.Fatalf("Failed to start credential server: %v", err)
} else {
setEnv = false
Expand Down
25 changes: 25 additions & 0 deletions cli/exec_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package cli

import (
kingpin "gopkg.in/alecthomas/kingpin.v2"

"github.com/99designs/aws-vault/vault"
"github.com/99designs/keyring"
)

func ExampleExecCommand() {
awsConfigFile = &vault.FileConfig{}
keyringImpl = keyring.NewArrayKeyring([]keyring.Item{
{Key: "llamas", Data: []byte(`{"AccessKeyID":"ABC","SecretAccessKey":"XYZ"}`)},
})

app := kingpin.New(`aws-vault`, ``)
ConfigureGlobals(app)
ConfigureExecCommand(app)
kingpin.MustParse(app.Parse([]string{
"--debug", "exec", "--no-session", "llamas", "--", "sh", "-c", "echo $AWS_ACCESS_KEY_ID",
}))

// Output:
// ABC
}
58 changes: 58 additions & 0 deletions cli/global.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package cli

import (
"fmt"
"io/ioutil"
"log"

"github.com/99designs/aws-vault/prompt"
"github.com/99designs/aws-vault/vault"
"github.com/99designs/keyring"
kingpin "gopkg.in/alecthomas/kingpin.v2"
)

const (
KeyringName = "aws-vault"
)

var (
keyringImpl keyring.Keyring
awsConfigFile vault.Config
promptsAvailable = prompt.Available()
backendsAvailable = keyring.SupportedBackends()
)

var GlobalFlags struct {
Debug bool
Backend string
PromptDriver string
}

func ConfigureGlobals(app *kingpin.Application) {
app.Flag("debug", "Show debugging output").
BoolVar(&GlobalFlags.Debug)

app.Flag("backend", fmt.Sprintf("Secret backend to use %v", backendsAvailable)).
Default(keyring.DefaultBackend).
OverrideDefaultFromEnvar("AWS_VAULT_BACKEND").
EnumVar(&GlobalFlags.Backend, backendsAvailable...)

app.Flag("prompt", fmt.Sprintf("Prompt driver to use %v", promptsAvailable)).
Default("terminal").
OverrideDefaultFromEnvar("AWS_VAULT_PROMPT").
EnumVar(&GlobalFlags.PromptDriver, promptsAvailable...)

app.PreAction(func(c *kingpin.ParseContext) (err error) {
if !GlobalFlags.Debug {
log.SetOutput(ioutil.Discard)
}
if keyringImpl == nil {
keyringImpl, err = keyring.Open(KeyringName, GlobalFlags.Backend)
}
if awsConfigFile == nil {
awsConfigFile, err = vault.NewConfigFromEnv()
}
return err
})

}
41 changes: 38 additions & 3 deletions login.go → cli/login.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package cli

import (
"encoding/json"
Expand All @@ -10,6 +10,7 @@ import (
"time"

"github.com/99designs/aws-vault/prompt"
"github.com/99designs/aws-vault/vault"
"github.com/99designs/keyring"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
Expand All @@ -32,6 +33,40 @@ type LoginCommandInput struct {
AssumeRoleDuration time.Duration
}

func ConfigureLoginCommand(app *kingpin.Application) {
input := LoginCommandInput{}

cmd := app.Command("login", "Generate a login link for the AWS Console")
cmd.Arg("profile", "Name of the profile").
Required().
StringVar(&input.Profile)

cmd.Flag("mfa-token", "The mfa token to use").
Short('t').
StringVar(&input.MfaToken)

cmd.Flag("federation-token-ttl", "Expiration time for aws console session").
Default("12h").
OverrideDefaultFromEnvar("AWS_FEDERATION_TOKEN_TTL").
Short('f').
DurationVar(&input.FederationTokenDuration)

cmd.Flag("assume-role-ttl", "Expiration time for aws assumed role").
Default("15m").
DurationVar(&input.AssumeRoleDuration)

cmd.Flag("stdout", "Print login URL to stdout instead of opening in default browser").
Short('s').
BoolVar(&input.UseStdout)

cmd.Action(func(c *kingpin.ParseContext) error {
input.MfaPrompt = prompt.Method(GlobalFlags.PromptDriver)
input.Keyring = keyringImpl
LoginCommand(app, input)
return nil
})
}

func LoginCommand(app *kingpin.Application, input LoginCommandInput) {
if input.FederationTokenDuration > (time.Hour * 12) {
app.Fatalf("Maximum federation token duration is 12 hours")
Expand All @@ -44,7 +79,7 @@ func LoginCommand(app *kingpin.Application, input LoginCommandInput) {
return
}

provider, err := NewVaultProvider(input.Keyring, input.Profile, VaultOptions{
provider, err := vault.NewVaultProvider(input.Keyring, input.Profile, vault.VaultOptions{
AssumeRoleDuration: input.AssumeRoleDuration,
MfaToken: input.MfaToken,
MfaPrompt: input.MfaPrompt,
Expand All @@ -59,7 +94,7 @@ func LoginCommand(app *kingpin.Application, input LoginCommandInput) {
creds := credentials.NewCredentials(provider)
val, err := creds.Get()
if err != nil {
app.Fatalf(formatCredentialError(input.Profile, profiles, err))
app.Fatalf(vault.FormatCredentialError(input.Profile, profiles, err))
}

var isFederated bool
Expand Down
14 changes: 13 additions & 1 deletion ls.go → cli/ls.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package cli

import (
"fmt"
Expand All @@ -11,6 +11,18 @@ type LsCommandInput struct {
Keyring keyring.Keyring
}

func ConfigureListCommand(app *kingpin.Application) {
input := LsCommandInput{}

cmd := app.Command("list", "List all credentials and sessions")
cmd.Alias("ls")
cmd.Action(func(c *kingpin.ParseContext) error {
input.Keyring = keyringImpl
LsCommand(app, input)
return nil
})
}

func LsCommand(app *kingpin.Application, input LsCommandInput) {
accounts, err := input.Keyring.Keys()
if err != nil {
Expand Down
12 changes: 9 additions & 3 deletions ls_test.go → cli/ls_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package main
package cli

import (
"os"
kingpin "gopkg.in/alecthomas/kingpin.v2"

"github.com/99designs/keyring"
)
Expand All @@ -11,7 +11,13 @@ func ExampleListCommand() {
{Key: "llamas", Data: []byte(`{"AccessKeyID":"ABC","SecretAccessKey":"XYZ"}`)},
})

run([]string{"list"}, os.Exit)
app := kingpin.New(`aws-vault`, ``)
ConfigureGlobals(app)
ConfigureListCommand(app)
kingpin.MustParse(app.Parse([]string{
"list",
}))

// Output:
// llamas
}
Loading

0 comments on commit 7d4cd04

Please sign in to comment.