Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
lima-vm
GitHub Repository: lima-vm/lima
Path: blob/master/pkg/envutil/envutil_test.go
2611 views
1
// SPDX-FileCopyrightText: Copyright The Lima Authors
2
// SPDX-License-Identifier: Apache-2.0
3
4
package envutil
5
6
import (
7
"os"
8
"slices"
9
"strings"
10
"testing"
11
12
"gotest.tools/v3/assert"
13
)
14
15
func isUsingDefaultBlockList() bool {
16
blockEnv := os.Getenv("LIMA_SHELLENV_BLOCK")
17
return blockEnv == "" || strings.HasPrefix(blockEnv, "+")
18
}
19
20
func TestMatchesPattern(t *testing.T) {
21
tests := []struct {
22
name string
23
pattern string
24
expected bool
25
}{
26
{"PATH", "PATH", true},
27
{"PATH", "HOME", false},
28
{"SSH_AUTH_SOCK", "SSH_*", true},
29
{"SSH_AGENT_PID", "SSH_*", true},
30
{"HOME", "SSH_*", false},
31
{"XDG_CONFIG_HOME", "XDG_*", true},
32
{"_LIMA_TEST", "_*", true},
33
{"LIMA_HOME", "_*", false},
34
}
35
36
for _, tt := range tests {
37
t.Run(tt.name+"_matches_"+tt.pattern, func(t *testing.T) {
38
result := matchesPattern(tt.name, tt.pattern)
39
assert.Equal(t, result, tt.expected)
40
})
41
}
42
}
43
44
func TestMatchesAnyPattern(t *testing.T) {
45
patterns := []string{"PATH", "SSH_*", "XDG_*"}
46
47
tests := []struct {
48
name string
49
expected bool
50
}{
51
{"PATH", true},
52
{"HOME", false},
53
{"SSH_AUTH_SOCK", true},
54
{"XDG_CONFIG_HOME", true},
55
{"USER", false},
56
}
57
58
for _, tt := range tests {
59
t.Run(tt.name, func(t *testing.T) {
60
result := matchesAnyPattern(tt.name, patterns)
61
assert.Equal(t, result, tt.expected)
62
})
63
}
64
}
65
66
func TestParseEnvList(t *testing.T) {
67
tests := []struct {
68
input string
69
expected []string
70
}{
71
{"", []string{}},
72
{"PATH", []string{"PATH"}},
73
{"PATH,HOME", []string{"PATH", "HOME"}},
74
{"PATH, HOME , USER", []string{"PATH", "HOME", "USER"}},
75
{" , , ", []string{}},
76
}
77
78
for _, tt := range tests {
79
t.Run(tt.input, func(t *testing.T) {
80
result := parseEnvList(tt.input)
81
assert.DeepEqual(t, result, tt.expected)
82
})
83
}
84
}
85
86
func TestGetBlockAndAllowLists(t *testing.T) {
87
t.Run("default config", func(t *testing.T) {
88
t.Setenv("LIMA_SHELLENV_BLOCK", "")
89
t.Setenv("LIMA_SHELLENV_ALLOW", "")
90
91
blockList := getBlockList()
92
allowList := getAllowList()
93
94
assert.Assert(t, isUsingDefaultBlockList())
95
assert.DeepEqual(t, blockList, defaultBlockList)
96
assert.Equal(t, len(allowList), 0)
97
})
98
99
t.Run("custom blocklist", func(t *testing.T) {
100
t.Setenv("LIMA_SHELLENV_BLOCK", "PATH,HOME")
101
102
blockList := getBlockList()
103
assert.Assert(t, !isUsingDefaultBlockList())
104
expected := []string{"PATH", "HOME"}
105
assert.DeepEqual(t, blockList, expected)
106
})
107
108
t.Run("additive blocklist", func(t *testing.T) {
109
t.Setenv("LIMA_SHELLENV_BLOCK", "+CUSTOM_VAR")
110
111
blockList := getBlockList()
112
assert.Assert(t, isUsingDefaultBlockList())
113
expected := slices.Concat(GetDefaultBlockList(), []string{"CUSTOM_VAR"})
114
assert.DeepEqual(t, blockList, expected)
115
})
116
117
t.Run("allowlist", func(t *testing.T) {
118
t.Setenv("LIMA_SHELLENV_ALLOW", "FOO,BAR")
119
120
allowList := getAllowList()
121
expected := []string{"FOO", "BAR"}
122
assert.DeepEqual(t, allowList, expected)
123
})
124
}
125
126
func TestFilterEnvironment(t *testing.T) {
127
testEnv := []string{
128
"PATH=/usr/bin",
129
"HOME=/home/user",
130
"USER=testuser",
131
"FOO=bar",
132
"SSH_AUTH_SOCK=/tmp/ssh",
133
"XDG_CONFIG_HOME=/config",
134
"BASH_VERSION=5.0",
135
"_INTERNAL=secret",
136
"CUSTOM_VAR=value",
137
}
138
139
t.Run("default blocklist", func(t *testing.T) {
140
result := filterEnvironmentWithLists(testEnv, nil, defaultBlockList)
141
142
expected := []string{"FOO=bar", "CUSTOM_VAR=value"}
143
assert.Assert(t, containsAll(result, expected))
144
145
blockedPrefixes := []string{
146
"PATH=",
147
"HOME=",
148
"SSH_AUTH_SOCK=",
149
"XDG_CONFIG_HOME=",
150
"BASH_VERSION=",
151
"_INTERNAL=",
152
}
153
for _, prefix := range blockedPrefixes {
154
for _, envVar := range result {
155
assert.Assert(t, !strings.HasPrefix(envVar, prefix), "Expected result to not contain variable with prefix %q, but found %q", prefix, envVar)
156
}
157
}
158
})
159
160
t.Run("custom blocklist", func(t *testing.T) {
161
result := filterEnvironmentWithLists(testEnv, nil, []string{"FOO"})
162
163
assert.Assert(t, !slices.Contains(result, "FOO=bar"))
164
165
expected := []string{"PATH=/usr/bin", "HOME=/home/user", "USER=testuser"}
166
assert.Assert(t, containsAll(result, expected))
167
})
168
169
t.Run("allowlist", func(t *testing.T) {
170
result := filterEnvironmentWithLists(testEnv, []string{"FOO", "USER"}, nil)
171
expected := []string{"FOO=bar", "USER=testuser"}
172
173
// since FOO and USER are included in testEnv, the filtered result should not differ
174
// from what is in the testEnv
175
assert.Equal(t, len(result), len(testEnv))
176
assert.Assert(t, containsAll(result, expected))
177
})
178
179
t.Run("allowlist takes precedence over blocklist", func(t *testing.T) {
180
result := filterEnvironmentWithLists(testEnv, []string{"FOO", "CUSTOM_VAR"}, []string{"FOO", "USER"})
181
182
expected := []string{"FOO=bar", "CUSTOM_VAR=value"}
183
assert.Assert(t, containsAll(result, expected))
184
185
assert.Assert(t, !slices.Contains(result, "USER=testuser"))
186
})
187
}
188
189
func containsAll(slice, items []string) bool {
190
for _, item := range items {
191
if !slices.Contains(slice, item) {
192
return false
193
}
194
}
195
return true
196
}
197
198
func TestGetDefaultBlockList(t *testing.T) {
199
blocklist := GetDefaultBlockList()
200
201
if &blocklist[0] == &defaultBlockList[0] {
202
t.Error("GetDefaultBlockList should return a copy, not the original slice")
203
}
204
205
assert.DeepEqual(t, blocklist, defaultBlockList)
206
207
expectedItems := []string{"PATH", "HOME", "SSH_*", "USER"}
208
for _, item := range expectedItems {
209
found := slices.Contains(blocklist, item)
210
assert.Assert(t, found, "Expected builtin blocklist to contain %q", item)
211
}
212
}
213
214
func TestValidatePattern(t *testing.T) {
215
tests := []struct {
216
name string
217
pattern string
218
valid bool
219
}{
220
{"simple alphanumeric uppercase", "FOO", true},
221
{"simple alphanumeric lowercase", "foo", true},
222
{"mixed case", "FooBar", true},
223
{"with underscore", "FOO_BAR", true},
224
{"with numbers", "VAR123", true},
225
{"with trailing asterisk", "FOO*", true},
226
{"with multiple asterisks", "FOO*BAR*", true},
227
{"asterisk at beginning", "*FOO", true},
228
{"asterisk in middle", "FOO*BAR", true},
229
{"only asterisk", "*", true},
230
{"with dash", "FOO-BAR", false},
231
{"with space", "FOO BAR", false},
232
}
233
234
for _, tt := range tests {
235
t.Run(tt.name, func(t *testing.T) {
236
err := validatePattern(tt.pattern)
237
if tt.valid {
238
assert.NilError(t, err, "Expected pattern %q to be valid", tt.pattern)
239
} else {
240
assert.Assert(t, err != nil, "Expected pattern %q to be invalid", tt.pattern)
241
}
242
})
243
}
244
}
245
246
func TestValidatePatternErrorMessage(t *testing.T) {
247
err := validatePattern("FOO-BAR")
248
assert.Assert(t, err != nil, "Expected pattern with dash to be invalid")
249
expectedMsg := `pattern "FOO-BAR" contains invalid character "-" at position 3`
250
assert.Equal(t, err.Error(), expectedMsg)
251
}
252
253