Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion cmd/limactl/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ func newShellCommand() *cobra.Command {
shellCmd.Flags().Bool("reconnect", false, "Reconnect to the SSH session")
shellCmd.Flags().Bool("preserve-env", false, "Propagate environment variables to the shell")
shellCmd.Flags().Bool("start", false, "Start the instance if it is not already running")
shellCmd.Flags().StringSlice("allow-env", []string{}, "Comma-separated list of environment variable patterns to allow when --preserve-env is set (overrides LIMA_SHELLENV_ALLOW)")
Copy link
Copy Markdown
Member

@jandubois jandubois Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#4263 says:

They would (just for this command) append the pattern to the respective lists and automatically enable --preserve-env.

These options are convenience methods to make it easier to append custom patterns for just a single command (otherwise you would change the env variables if you want the changes to persist for longer). So it makes no sense to require the user to also specify --preserve-env as well.

Suggested change
shellCmd.Flags().StringSlice("allow-env", []string{}, "Comma-separated list of environment variable patterns to allow when --preserve-env is set (overrides LIMA_SHELLENV_ALLOW)")
shellCmd.Flags().StringSlice("allow-env", []string{}, "Comma-separated list of additional environment variable patterns to allow (implies --preserve-env)")

shellCmd.Flags().StringSlice("block-env", []string{}, "Comma-separated list of environment variable patterns to allow when --preserve-env is set (overrides LIMA_SHELLENV_BLOCK)")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as the line above, but the description here has a cut&pasto: needs to say to block instead of to allow.

return shellCmd
}

Expand Down Expand Up @@ -216,8 +218,16 @@ func shellAction(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
allowListRaw, err := cmd.Flags().GetStringSlice("allow-env")
if err != nil {
return err
}
blockListRaw, err := cmd.Flags().GetStringSlice("block-env")
if err != nil {
return err
}
if preserveEnv {
filteredEnv := envutil.FilterEnvironment()
filteredEnv := envutil.FilterEnvironment(allowListRaw, blockListRaw)
if len(filteredEnv) > 0 {
envPrefix = "env "
for _, envVar := range filteredEnv {
Expand Down
39 changes: 23 additions & 16 deletions pkg/envutil/envutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,20 @@ func validatePattern(pattern string) error {
}

// getBlockList returns the list of environment variable patterns to be blocked.
func getBlockList() []string {
blockEnv := os.Getenv("LIMA_SHELLENV_BLOCK")
if blockEnv == "" {
return defaultBlockList
func getBlockList(blockListRaw []string) []string {
var shouldAppend bool
patterns := blockListRaw
if len(patterns) == 0 {
blockEnv := os.Getenv("LIMA_SHELLENV_BLOCK")
Comment on lines +62 to +63
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are replacing the environment variable with the content of the --block-env option. #4263 specifies that the option has to be appended to the env variable list. In addition, it says it has to be appended to the default block list if the env variable is empty.

Same thing applies to the allow list (with the exception that there is no default allow list).

Please re-read the issue, and implement the functionality as specified. Or start a discussion in the issue if you think the requested semantics are wrong!

if blockEnv == "" {
return defaultBlockList
}
shouldAppend = strings.HasPrefix(blockEnv, "+")
patterns = parseEnvList(strings.TrimPrefix(blockEnv, "+"))
} else {
shouldAppend = strings.HasPrefix(patterns[0], "+")
}

shouldAppend := strings.HasPrefix(blockEnv, "+")
patterns := parseEnvList(strings.TrimPrefix(blockEnv, "+"))

for _, pattern := range patterns {
if err := validatePattern(pattern); err != nil {
logrus.Fatalf("Invalid LIMA_SHELLENV_BLOCK pattern: %v", err)
Expand All @@ -78,14 +83,16 @@ func getBlockList() []string {
}

// getAllowList returns the list of environment variable patterns to be allowed.
func getAllowList() []string {
allowEnv := os.Getenv("LIMA_SHELLENV_ALLOW")
if allowEnv == "" {
return nil
func getAllowList(allowListRaw []string) []string {
patterns := allowListRaw
if len(patterns) == 0 {
allowEnv := os.Getenv("LIMA_SHELLENV_ALLOW")
if allowEnv == "" {
return nil
}
patterns = parseEnvList(allowEnv)
}

patterns := parseEnvList(allowEnv)

for _, pattern := range patterns {
if err := validatePattern(pattern); err != nil {
logrus.Fatalf("Invalid LIMA_SHELLENV_ALLOW pattern: %v", err)
Expand Down Expand Up @@ -131,11 +138,11 @@ func matchesAnyPattern(name string, patterns []string) bool {
// FilterEnvironment filters environment variables based on configuration from environment variables.
// It returns a slice of environment variables that are not blocked by the current configuration.
// The filtering is controlled by LIMA_SHELLENV_BLOCK and LIMA_SHELLENV_ALLOW environment variables.
func FilterEnvironment() []string {
func FilterEnvironment(allowListRaw, blockListRaw []string) []string {
return filterEnvironmentWithLists(
os.Environ(),
getAllowList(),
getBlockList(),
getAllowList(allowListRaw),
getBlockList(blockListRaw),
)
}

Expand Down
10 changes: 5 additions & 5 deletions pkg/envutil/envutil_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ func TestGetBlockAndAllowLists(t *testing.T) {
t.Setenv("LIMA_SHELLENV_BLOCK", "")
t.Setenv("LIMA_SHELLENV_ALLOW", "")

blockList := getBlockList()
allowList := getAllowList()
blockList := getBlockList([]string{})
allowList := getAllowList([]string{})

assert.Assert(t, isUsingDefaultBlockList())
assert.DeepEqual(t, blockList, defaultBlockList)
Expand All @@ -99,7 +99,7 @@ func TestGetBlockAndAllowLists(t *testing.T) {
t.Run("custom blocklist", func(t *testing.T) {
t.Setenv("LIMA_SHELLENV_BLOCK", "PATH,HOME")

blockList := getBlockList()
blockList := getBlockList([]string{})
assert.Assert(t, !isUsingDefaultBlockList())
expected := []string{"PATH", "HOME"}
assert.DeepEqual(t, blockList, expected)
Expand All @@ -108,7 +108,7 @@ func TestGetBlockAndAllowLists(t *testing.T) {
t.Run("additive blocklist", func(t *testing.T) {
t.Setenv("LIMA_SHELLENV_BLOCK", "+CUSTOM_VAR")

blockList := getBlockList()
blockList := getBlockList([]string{})
assert.Assert(t, isUsingDefaultBlockList())
expected := slices.Concat(GetDefaultBlockList(), []string{"CUSTOM_VAR"})
assert.DeepEqual(t, blockList, expected)
Expand All @@ -117,7 +117,7 @@ func TestGetBlockAndAllowLists(t *testing.T) {
t.Run("allowlist", func(t *testing.T) {
t.Setenv("LIMA_SHELLENV_ALLOW", "FOO,BAR")

allowList := getAllowList()
allowList := getAllowList([]string{})
expected := []string{"FOO", "BAR"}
assert.DeepEqual(t, allowList, expected)
})
Expand Down