From 2a121c141b3d9981675c6e680b5673258a726bc2 Mon Sep 17 00:00:00 2001 From: Alexey Kamenskiy Date: Sun, 22 Jan 2023 13:33:21 +1100 Subject: [PATCH] Add an option to unset env after parsing --- envparse.go | 11 +++++++++++ envparse_test.go | 23 +++++++++++++++++++++++ options.go | 9 +++++++++ options_test.go | 11 +++++++++++ 4 files changed, 54 insertions(+) diff --git a/envparse.go b/envparse.go index aeb04fc..867d761 100644 --- a/envparse.go +++ b/envparse.go @@ -2,6 +2,7 @@ package envparse import ( "fmt" + "os" "reflect" "strconv" "strings" @@ -10,6 +11,7 @@ import ( var ( defaultPrefix = "APP" defaultMaxDepth = 100 + unsetEnv = false ) // Parse scans through environment variables using mapping provided in interface @@ -26,6 +28,15 @@ func Parse(ptr interface{}, envs []string) error { errorList := newErrorList() structValue.Set(parseStruct(structValue.Type(), env.GetPrefix(defaultPrefix), 0, errorList)) + + if unsetEnv { + for k := range env { + if strings.HasPrefix(k, defaultPrefix) { + _ = os.Unsetenv(k) + } + } + } + if !errorList.IsEmpty() { return errorList } diff --git a/envparse_test.go b/envparse_test.go index 89adabb..12adcca 100644 --- a/envparse_test.go +++ b/envparse_test.go @@ -1,6 +1,7 @@ package envparse import ( + "os" "reflect" "testing" ) @@ -379,3 +380,25 @@ func TestParse_8(t *testing.T) { t.Errorf("expected '%v', but got '%v'", e2, c2) } } + +func TestParse_9(t *testing.T) { + _ = os.Setenv("APP_TEST", "1") + _ = os.Setenv("APP_TEST", "1") + type testType struct { + I int `env:"name=TEST,required"` + } + c := &testType{} + origUnsetEnv := unsetEnv + unsetEnv = true + err := Parse(c, os.Environ()) + unsetEnv = origUnsetEnv + if err != nil { + t.Errorf("expected err == nil, but got '%v'", FullError(err)) + } + if c.I != 1 { + t.Errorf("expected c.I == 1, but got c.I == %d", c.I) + } + if os.Getenv("APP_TEST") != "" { + t.Errorf("expected APP_TEST == '', but got APP_TEST == '%s'", os.Getenv("APP_TEST")) + } +} diff --git a/options.go b/options.go index 1d3db3c..4f1a94f 100644 --- a/options.go +++ b/options.go @@ -16,3 +16,12 @@ func SetPrefix(s string) { func SetMaxDepth(i int) { defaultMaxDepth = i } + +// SetUnsetEnv sets a flag that if `true` will ensure that all environment variables using defined prefix +// will not be readable by the process or by the children of the process. +// +// NOTE: the original environment variable is still available to be read from `/proc//environ` or `ps eww ` +// as there are no system mechanisms available to overwrite those. +func SetUnsetEnv(unset bool) { + unsetEnv = unset +} diff --git a/options_test.go b/options_test.go index 8f96e1e..0cbc5e5 100644 --- a/options_test.go +++ b/options_test.go @@ -39,3 +39,14 @@ func TestSetMaxDepth(t *testing.T) { defaultMaxDepth = originalMaxDepth } + +func TestSetUnsetEnv(t *testing.T) { + originalUnsetEnv := unsetEnv + + SetUnsetEnv(true) + if !unsetEnv { + t.Errorf("expected unsetEnv == true, but got unsetEnv == false") + } + + unsetEnv = originalUnsetEnv +}