diff --git a/cmd/common-main.go b/cmd/common-main.go index 7f6ead797..e859f881a 100644 --- a/cmd/common-main.go +++ b/cmd/common-main.go @@ -37,6 +37,7 @@ import ( "syscall" "time" "unicode" + "unicode/utf8" "github.com/dustin/go-humanize" fcolor "github.com/fatih/color" @@ -542,21 +543,17 @@ func (e envKV) String() string { } func isValidEnvName(name string) bool { - if name == "" || !isEnvNameStart(name[0]) { + if name == "" || !utf8.ValidString(name) { return false } - for i := 1; i < len(name); i++ { - if !isEnvNameStart(name[i]) && (name[i] < '0' || name[i] > '9') { + for _, ch := range name { + if ch == '=' || unicode.IsSpace(ch) || !unicode.IsGraphic(ch) { return false } } return true } -func isEnvNameStart(ch byte) bool { - return ch == '_' || ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z' -} - func trimExportPrefix(envEntry string) string { rest, ok := strings.CutPrefix(envEntry, "export") if !ok || rest == "" { diff --git a/cmd/common-main_test.go b/cmd/common-main_test.go index 341ddba49..8afcaaf2b 100644 --- a/cmd/common-main_test.go +++ b/cmd/common-main_test.go @@ -22,8 +22,11 @@ import ( "fmt" "os" "reflect" + "slices" "strings" "testing" + + "github.com/minio/minio/internal/config" ) func Test_readFromSecret(t *testing.T) { @@ -240,6 +243,19 @@ func Test_minioEnvironFromFileWhitespaceAndValidation(t *testing.T) { {Key: "_VALID_2", Value: "value"}, }, }, + { + name: "named target punctuation and unicode", + content: "MINIO_NOTIFY_WEBHOOK_ENABLE_my-hook=off\n" + + "MINIO_NOTIFY_WEBHOOK_ENABLE_site.eu=off\n" + + "MINIO_NOTIFY_WEBHOOK_ENABLE_team:blue=off\n" + + "MINIO_NOTIFY_WEBHOOK_ENABLE_目标=off", + want: []envKV{ + {Key: "MINIO_NOTIFY_WEBHOOK_ENABLE_my-hook", Value: "off"}, + {Key: "MINIO_NOTIFY_WEBHOOK_ENABLE_site.eu", Value: "off"}, + {Key: "MINIO_NOTIFY_WEBHOOK_ENABLE_team:blue", Value: "off"}, + {Key: "MINIO_NOTIFY_WEBHOOK_ENABLE_目标", Value: "off"}, + }, + }, { name: "missing separator redacts the line", content: "MINIO_ROOT_PASSWORD=valid\nsuper-secret-without-equals", @@ -255,18 +271,12 @@ func Test_minioEnvironFromFileWhitespaceAndValidation(t *testing.T) { errExcludes: "empty-name-secret", }, { - name: "digit leading name", - content: "1MINIO_ROOT_USER=digit-leading-secret", - errLine: 1, - errContains: `invalid environment variable name "1MINIO_ROOT_USER"`, - errExcludes: "digit-leading-secret", - }, - { - name: "hyphenated name", - content: "MINIO-ROOT-USER=hyphen-secret", - errLine: 1, - errContains: `invalid environment variable name "MINIO-ROOT-USER"`, - errExcludes: "hyphen-secret", + name: "os compatible leading digit and punctuation", + content: "1MINIO_ROOT_USER=digit-leading-secret\n-MINIO-ROOT-USER=hyphen-secret", + want: []envKV{ + {Key: "1MINIO_ROOT_USER", Value: "digit-leading-secret"}, + {Key: "-MINIO-ROOT-USER", Value: "hyphen-secret"}, + }, }, { name: "whitespace in name", @@ -282,6 +292,13 @@ func Test_minioEnvironFromFileWhitespaceAndValidation(t *testing.T) { errContains: "invalid environment variable name", errExcludes: "nul-name-secret", }, + { + name: "format character in name", + content: "MINIO\u200bROOT=format-secret", + errLine: 1, + errContains: "invalid environment variable name", + errExcludes: "format-secret", + }, { name: "NUL in value", content: "MINIO_ROOT_USER=before\x00nul-value-secret", @@ -342,3 +359,16 @@ func Test_minioEnvironFromFileWhitespaceAndValidation(t *testing.T) { }) } } + +func TestConfigEnvFileNamedTargetDiscovery(t *testing.T) { + key := "MINIO_NOTIFY_WEBHOOK_ENABLE_my-hook" + t.Setenv(key, "off") + + targets, err := (config.Config{}).GetAvailableTargets(config.NotifyWebhookSubSys) + if err != nil { + t.Fatal(err) + } + if !slices.Contains(targets, "my-hook") { + t.Fatalf("named target %q not discovered from %s: %v", "my-hook", key, targets) + } +}