Skip to content

Commit c7f611f

Browse files
committed
improve flexibility of limactl shell cmd
Signed-off-by: olalekan odukoya <[email protected]>
1 parent 7dcdf6a commit c7f611f

File tree

5 files changed

+157
-156
lines changed

5 files changed

+157
-156
lines changed

hack/bats/tests/preserve-env.bats

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,13 @@ local_setup() {
9393
assert_line BAR=bar
9494
}
9595

96-
@test 'wildcard does only work at the end of the pattern' {
96+
@test 'wildcard works at the start of the pattern' {
9797
export LIMA_SHELLENV_BLOCK="*FOO"
9898
export FOO=foo
9999
export BARFOO=barfoo
100100
run -0 limactl shell --preserve-env "$NAME" printenv
101-
assert_line FOO=foo
102-
assert_line BARFOO=barfoo
101+
refute_line --regexp '^BARFOO='
102+
refute_line --regexp '^FOO='
103103
}
104104

105105
@test 'block list can use a , separated list with whitespace ignored' {
@@ -114,37 +114,74 @@ local_setup() {
114114
assert_line BARBAZ=barbaz
115115
}
116116

117-
@test 'allow list overrides block list but blocks everything else' {
118-
export LIMA_SHELLENV_ALLOW=SSH_FOO
117+
@test 'allow list can use a , separated list with whitespace ignored' {
118+
export LIMA_SHELLENV_ALLOW="SSH_FOO, , BAR*, LD_UID"
119119
export SSH_FOO=ssh_foo
120120
export SSH_BAR=ssh_bar
121+
export SSH_BLOCK=ssh_block
121122
export BAR=bar
123+
export BARBAZ=barbaz
124+
export LD_UID=randomuid
122125
run -0 limactl shell --preserve-env "$NAME" printenv
126+
123127
assert_line SSH_FOO=ssh_foo
128+
assert_line BAR=bar
129+
assert_line BARBAZ=barbaz
130+
assert_line LD_UID=randomuid
131+
124132
refute_line --regexp '^SSH_BAR='
125-
refute_line --regexp '^BAR='
133+
refute_line --regexp '^SSH_BLOCK='
126134
}
127135

128-
@test 'allow list can use a , separated list with whitespace ignored' {
129-
export LIMA_SHELLENV_ALLOW="FOO*, , BAR"
136+
@test 'wildcard patterns work in all positions' {
137+
export LIMA_SHELLENV_BLOCK="*FOO*BAR*"
130138
export FOO=foo
131139
export FOOBAR=foobar
140+
export FOOXYZBAR=fooxyzbar
141+
export FOOBAZ=foobaz
142+
export BAZBAR=bazbar
132143
export BAR=bar
133-
export BARBAZ=barbaz
144+
export XFOOYBARZDOTCOM=xfooybarzdotcom
145+
export NORMAL_VAR=normal_var
146+
export UNRELATED=unrelated
134147
run -0 limactl shell --preserve-env "$NAME" printenv
135-
assert_line FOO=foo
136-
assert_line FOOBAR=foobar
148+
149+
# Should block *FOO*BAR* pattern
150+
refute_line --regexp '^FOOBAR='
151+
refute_line --regexp '^FOOXYZBAR='
152+
refute_line --regexp '^XFOOYBARZDOTCOM='
153+
154+
# Should allow variables that don't match any pattern
155+
assert_line FOOBAZ=foobaz
156+
assert_line NORMAL_VAR=normal_var
157+
assert_line UNRELATED=unrelated
158+
assert_line BAZBAR=bazbar
137159
assert_line BAR=bar
138-
refute_line --regexp '^BARBAZ='
160+
assert_line FOO=foo
139161
}
140162

141-
@test 'setting both allow list and block list generates a warning' {
142-
export LIMA_SHELLENV_ALLOW=FOO
143-
export LIMA_SHELLENV_BLOCK=BAR
144-
export FOO=foo
145-
run -0 --separate-stderr limactl shell --preserve-env "$NAME" printenv FOO
146-
assert_output foo
147-
assert_stderr --regexp 'level=warning msg="Both LIMA_SHELLENV_BLOCK and LIMA_SHELLENV_ALLOW are set'
163+
@test 'allowlist overrides default blocklist with wildcards' {
164+
export LIMA_SHELLENV_ALLOW="SSH_*,CUSTOM*"
165+
export LIMA_SHELLENV_BLOCK="+*TOKEN"
166+
export SSH_AUTH_SOCK=ssh_auth_sock
167+
export SSH_CONNECTION=ssh_connection
168+
export CUSTOM_VAR=custom_var
169+
export MY_TOKEN=my_token
170+
export UNRELATED=unrelated
171+
run -0 limactl shell --preserve-env "$NAME" printenv
172+
173+
assert_line SSH_AUTH_SOCK=ssh_auth_sock
174+
assert_line SSH_CONNECTION=ssh_connection
175+
assert_line CUSTOM_VAR=custom_var
176+
refute_line --regexp '^MY_TOKEN='
177+
assert_line UNRELATED=unrelated
178+
}
179+
180+
@test 'invalid characters in patterns cause fatal errors' {
181+
export LIMA_SHELLENV_BLOCK="FOO-BAR"
182+
run ! limactl shell --preserve-env "$NAME" printenv
183+
assert_output --partial "Invalid LIMA_SHELLENV_BLOCK pattern"
184+
assert_output --partial "contains invalid character"
148185
}
149186

150187
@test 'limactl info includes the default block list' {

hack/test-preserve-env.sh

Lines changed: 0 additions & 94 deletions
This file was deleted.

hack/test-templates.sh

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,10 +339,6 @@ if [[ -n ${CHECKS["mount-home"]} ]]; then
339339
"${scriptdir}"/test-mount-home.sh "$NAME"
340340
fi
341341

342-
if [[ -n ${CHECKS["preserve-env"]} ]]; then
343-
"${scriptdir}"/test-preserve-env.sh "$NAME"
344-
fi
345-
346342
if [[ -n ${CHECKS["ssh-over-vsock"]} ]]; then
347343
if [[ "$(limactl ls "${NAME}" --yq .vmType)" == "vz" ]]; then
348344
INFO "Testing SSH over vsock"

pkg/envutil/envutil.go

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
package envutil
55

66
import (
7+
"fmt"
78
"os"
9+
"regexp"
810
"slices"
911
"strings"
1012

@@ -42,27 +44,55 @@ var defaultBlockList = []string{
4244
"_*", // Variables starting with underscore are typically internal
4345
}
4446

47+
func validatePattern(pattern string) error {
48+
invalidChar := regexp.MustCompile(`([^a-zA-Z0-9_*])`)
49+
if matches := invalidChar.FindStringSubmatch(pattern); matches != nil {
50+
invalidCharacter := matches[1]
51+
pos := strings.Index(pattern, invalidCharacter)
52+
return fmt.Errorf("pattern %q contains invalid character %q at position %d",
53+
pattern, invalidCharacter, pos)
54+
}
55+
return nil
56+
}
57+
4558
// getBlockList returns the list of environment variable patterns to be blocked.
46-
// The second return value indicates whether the list was explicitly set via LIMA_SHELLENV_BLOCK.
47-
func getBlockList() ([]string, bool) {
59+
func getBlockList() []string {
4860
blockEnv := os.Getenv("LIMA_SHELLENV_BLOCK")
4961
if blockEnv == "" {
50-
return defaultBlockList, false
62+
return defaultBlockList
5163
}
52-
after, found := strings.CutPrefix(blockEnv, "+")
53-
if !found {
54-
return parseEnvList(blockEnv), true
64+
65+
shouldAppend := strings.HasPrefix(blockEnv, "+")
66+
patterns := parseEnvList(strings.TrimPrefix(blockEnv, "+"))
67+
68+
for _, pattern := range patterns {
69+
if err := validatePattern(pattern); err != nil {
70+
logrus.Fatalf("Invalid LIMA_SHELLENV_BLOCK pattern: %v", err)
71+
}
72+
}
73+
74+
if shouldAppend {
75+
return slices.Concat(defaultBlockList, patterns)
5576
}
56-
return slices.Concat(defaultBlockList, parseEnvList(after)), true
77+
return patterns
5778
}
5879

5980
// getAllowList returns the list of environment variable patterns to be allowed.
60-
// The second return value indicates whether the list was explicitly set via LIMA_SHELLENV_ALLOW.
61-
func getAllowList() ([]string, bool) {
62-
if allowEnv := os.Getenv("LIMA_SHELLENV_ALLOW"); allowEnv != "" {
63-
return parseEnvList(allowEnv), true
81+
func getAllowList() []string {
82+
allowEnv := os.Getenv("LIMA_SHELLENV_ALLOW")
83+
if allowEnv == "" {
84+
return nil
6485
}
65-
return nil, false
86+
87+
patterns := parseEnvList(allowEnv)
88+
89+
for _, pattern := range patterns {
90+
if err := validatePattern(pattern); err != nil {
91+
logrus.Fatalf("Invalid LIMA_SHELLENV_ALLOW pattern: %v", err)
92+
}
93+
}
94+
95+
return patterns
6696
}
6797

6898
func parseEnvList(envList string) []string {
@@ -82,8 +112,14 @@ func matchesPattern(name, pattern string) bool {
82112
return true
83113
}
84114

85-
prefix, found := strings.CutSuffix(pattern, "*")
86-
return found && strings.HasPrefix(name, prefix)
115+
regexPattern := strings.ReplaceAll(pattern, "*", ".*")
116+
regexPattern = "^" + regexPattern + "$"
117+
118+
match, err := regexp.MatchString(regexPattern, name)
119+
if err != nil {
120+
return false
121+
}
122+
return match
87123
}
88124

89125
func matchesAnyPattern(name string, patterns []string) bool {
@@ -96,17 +132,10 @@ func matchesAnyPattern(name string, patterns []string) bool {
96132
// It returns a slice of environment variables that are not blocked by the current configuration.
97133
// The filtering is controlled by LIMA_SHELLENV_BLOCK and LIMA_SHELLENV_ALLOW environment variables.
98134
func FilterEnvironment() []string {
99-
allowList, isAllowListSet := getAllowList()
100-
blockList, isBlockListSet := getBlockList()
101-
102-
if isBlockListSet && isAllowListSet {
103-
logrus.Warn("Both LIMA_SHELLENV_BLOCK and LIMA_SHELLENV_ALLOW are set. Block list will be ignored.")
104-
blockList = nil
105-
}
106135
return filterEnvironmentWithLists(
107136
os.Environ(),
108-
allowList,
109-
blockList,
137+
getAllowList(),
138+
getBlockList(),
110139
)
111140
}
112141

@@ -121,10 +150,7 @@ func filterEnvironmentWithLists(env, allowList, blockList []string) []string {
121150

122151
name := parts[0]
123152

124-
if len(allowList) > 0 {
125-
if !matchesAnyPattern(name, allowList) {
126-
continue
127-
}
153+
if len(allowList) > 0 && matchesAnyPattern(name, allowList) {
128154
filtered = append(filtered, envVar)
129155
continue
130156
}

0 commit comments

Comments
 (0)