Skip to content

Commit f9cb9ea

Browse files
committed
Fix setting of AWS variables in env subcommand
1 parent e37f732 commit f9cb9ea

File tree

4 files changed

+146
-38
lines changed

4 files changed

+146
-38
lines changed

env.go

+15-3
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,30 @@ func (e *Env) Run(steward Steward) error {
2020
}
2121

2222
usageHint := ""
23+
unsetVar := ""
2324
setVar := ""
2425
quoteReplacement := "\""
2526
switch e.Shell {
2627
case "fish":
2728
usageHint = "# To load these variables into your shell, execute:\n# eval (%s)\n"
29+
unsetVar = "set -e %s;\n"
2830
setVar = "set -x %s \"%s\";\n"
2931
quoteReplacement = "\\\""
3032
default:
3133
usageHint = "# To load these variables into your shell, execute:\n# eval $(%s)\n"
34+
unsetVar = "unset %s\n"
3235
setVar = "export %s=\"%s\"\n"
3336
quoteReplacement = "\\\""
3437
}
3538

36-
// sort the vars
39+
vars := env.Variables()
40+
41+
// sort the vars to unset
42+
sort.Strings(vars.Unset)
43+
44+
// sort the vars to set
3745
var keys []string
38-
for key := range env.Vars {
46+
for key := range vars.Set {
3947
keys = append(keys, key)
4048
}
4149
sort.Strings(keys)
@@ -45,8 +53,12 @@ func (e *Env) Run(steward Steward) error {
4553
fmt.Printf(usageHint, strings.Join(os.Args, " "))
4654
}
4755

56+
for _, key := range vars.Unset {
57+
fmt.Printf(unsetVar, key)
58+
}
59+
4860
for _, key := range keys {
49-
fmt.Printf(setVar, key, strings.Replace(env.Vars[key], "\"", quoteReplacement, -1))
61+
fmt.Printf(setVar, key, strings.Replace(vars.Set[key], "\"", quoteReplacement, -1))
5062
}
5163

5264
return nil

env_test.go

+57
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ set -x TWO "222";
1717
set -x ONE "111111";
1818
set -x THREE "333";
1919
set -x TWO "222";
20+
`
21+
envFishOutputWithPermCreds = `set -e AWS_SECURITY_TOKEN;
22+
set -e AWS_SESSION_TOKEN;
23+
set -x AWS_ACCESS_KEY_ID "aws-key-id";
24+
set -x AWS_SECRET_ACCESS_KEY "aws-secret-key";
25+
set -x ONE "111111";
26+
set -x THREE "333";
27+
set -x TWO "222";
2028
`
2129

2230
envShOutput = `export ONE="111111"
@@ -28,6 +36,14 @@ export TWO="222"
2836
export ONE="111111"
2937
export THREE="333"
3038
export TWO="222"
39+
`
40+
envShOutputWithPermCreds = `unset AWS_SECURITY_TOKEN
41+
unset AWS_SESSION_TOKEN
42+
export AWS_ACCESS_KEY_ID="aws-key-id"
43+
export AWS_SECRET_ACCESS_KEY="aws-secret-key"
44+
export ONE="111111"
45+
export THREE="333"
46+
export TWO="222"
3147
`
3248
)
3349

@@ -106,4 +122,45 @@ func TestEng(t *testing.T) {
106122
if string(output) != envShOutputWithHint {
107123
t.Fatalf("Incorrect output: %s", output)
108124
}
125+
126+
// cached environment
127+
steward.Environments["one"] = &vaulted.Environment{
128+
AWSCreds: &vaulted.AWSCredentials{
129+
ID: "aws-key-id",
130+
Secret: "aws-secret-key",
131+
},
132+
Vars: map[string]string{
133+
"TWO": "222",
134+
"ONE": "111111",
135+
"THREE": "333",
136+
},
137+
}
138+
139+
output = CaptureStdout(func() {
140+
e := Env{
141+
VaultName: "one",
142+
Shell: "fish",
143+
}
144+
err := e.Run(steward)
145+
if err != nil {
146+
t.Fatal(err)
147+
}
148+
})
149+
if string(output) != envFishOutputWithPermCreds {
150+
t.Fatalf("Incorrect output: %s", output)
151+
}
152+
153+
output = CaptureStdout(func() {
154+
e := Env{
155+
VaultName: "one",
156+
Shell: "sh",
157+
}
158+
err := e.Run(steward)
159+
if err != nil {
160+
t.Fatal(err)
161+
}
162+
})
163+
if string(output) != envShOutputWithPermCreds {
164+
t.Fatalf("Incorrect output: %s", output)
165+
}
109166
}

lib/environment.go

+43-22
Original file line numberDiff line numberDiff line change
@@ -132,40 +132,61 @@ func (e *Environment) startProxyKeyring() (string, error) {
132132
return sock, err
133133
}
134134

135-
func (e *Environment) buildEnviron(extraVars map[string]string) []string {
136-
// load the current environ
137-
env := make(map[string]string)
138-
for _, envVar := range os.Environ() {
139-
parts := strings.SplitN(envVar, "=", 2)
140-
env[parts[0]] = parts[1]
135+
func (e *Environment) Variables() *Variables {
136+
vars := Variables{
137+
Set: make(map[string]string),
141138
}
142139

143-
// merge the vars
144140
for key, value := range e.Vars {
145-
env[key] = value
146-
}
147-
for key, value := range extraVars {
148-
env[key] = value
141+
vars.Set[key] = value
149142
}
150143

151144
if e.AWSCreds != nil {
152-
delete(env, "AWS_ACCESS_KEY_ID")
153-
delete(env, "AWS_SECRET_ACCESS_KEY")
154-
delete(env, "AWS_SESSION_TOKEN")
155-
delete(env, "AWS_SECURITY_TOKEN")
145+
vars.Set["AWS_ACCESS_KEY_ID"] = e.AWSCreds.ID
146+
vars.Set["AWS_SECRET_ACCESS_KEY"] = e.AWSCreds.Secret
156147

157-
env["AWS_ACCESS_KEY_ID"] = e.AWSCreds.ID
158-
env["AWS_SECRET_ACCESS_KEY"] = e.AWSCreds.Secret
159148
if e.AWSCreds.Token != "" {
160-
env["AWS_SESSION_TOKEN"] = e.AWSCreds.Token
161-
env["AWS_SECURITY_TOKEN"] = e.AWSCreds.Token
149+
vars.Set["AWS_SESSION_TOKEN"] = e.AWSCreds.Token
150+
vars.Set["AWS_SECURITY_TOKEN"] = e.AWSCreds.Token
151+
} else {
152+
vars.Unset = append(
153+
vars.Unset,
154+
"AWS_SESSION_TOKEN",
155+
"AWS_SECURITY_TOKEN",
156+
)
162157
}
163158
}
164159

165-
// recombine into environ
166-
environ := make([]string, 0, len(env))
167-
for key, value := range env {
160+
return &vars
161+
}
162+
163+
func (e *Environment) buildEnviron(extraVars map[string]string) []string {
164+
vars := make(map[string]string)
165+
for _, v := range os.Environ() {
166+
parts := strings.SplitN(v, "=", 2)
167+
vars[parts[0]] = parts[1]
168+
}
169+
170+
v := e.Variables()
171+
for _, key := range v.Unset {
172+
delete(vars, key)
173+
}
174+
for key, value := range v.Set {
175+
vars[key] = value
176+
}
177+
178+
for key, value := range extraVars {
179+
vars[key] = value
180+
}
181+
182+
environ := make([]string, 0, len(vars))
183+
for key, value := range vars {
168184
environ = append(environ, fmt.Sprintf("%s=%s", key, value))
169185
}
170186
return environ
171187
}
188+
189+
type Variables struct {
190+
Set map[string]string
191+
Unset []string
192+
}

steward_test.go

+31-13
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,16 @@ func WriteStdin(b []byte, f func()) {
5959

6060
func NewTestSteward() *TestSteward {
6161
return &TestSteward{
62-
Passwords: make(map[string]string),
63-
Vaults: make(map[string]*vaulted.Vault),
62+
Passwords: make(map[string]string),
63+
Vaults: make(map[string]*vaulted.Vault),
64+
Environments: make(map[string]*vaulted.Environment),
6465
}
6566
}
6667

6768
type TestSteward struct {
68-
Passwords map[string]string
69-
Vaults map[string]*vaulted.Vault
69+
Passwords map[string]string
70+
Vaults map[string]*vaulted.Vault
71+
Environments map[string]*vaulted.Environment
7072

7173
LegacyPassword string
7274
LegacyEnvironments map[string]legacy.Environment
@@ -139,22 +141,38 @@ func (ts TestSteward) GetEnvironment(name string, password *string) (string, *va
139141
}
140142
}
141143

142-
vault := ts.Vaults[name]
143-
144-
env := &vaulted.Environment{
144+
e := &vaulted.Environment{
145145
Vars: make(map[string]string),
146146
SSHKeys: make(map[string]string),
147147
}
148+
if _, exists := ts.Environments[name]; exists {
149+
env := ts.Environments[name]
148150

149-
for key, value := range vault.Vars {
150-
env.Vars[key] = value
151-
}
151+
e.Expiration = env.Expiration
152152

153-
for key, value := range vault.SSHKeys {
154-
env.SSHKeys[key] = value
153+
creds := *env.AWSCreds
154+
e.AWSCreds = &creds
155+
156+
for key, value := range env.Vars {
157+
e.Vars[key] = value
158+
}
159+
160+
for key, value := range env.SSHKeys {
161+
e.SSHKeys[key] = value
162+
}
163+
} else {
164+
vault := ts.Vaults[name]
165+
166+
for key, value := range vault.Vars {
167+
e.Vars[key] = value
168+
}
169+
170+
for key, value := range vault.SSHKeys {
171+
e.SSHKeys[key] = value
172+
}
155173
}
156174

157-
return ts.Passwords[name], env, nil
175+
return ts.Passwords[name], e, nil
158176
}
159177

160178
func (ts TestSteward) OpenLegacyVault() (password string, environments map[string]legacy.Environment, err error) {

0 commit comments

Comments
 (0)