From d714a76c2334f04ba5ac71c7abbe8dddbdf1baf0 Mon Sep 17 00:00:00 2001 From: Matthias Glastra Date: Thu, 10 Oct 2024 15:51:38 +0200 Subject: [PATCH] Refactor environment. Signed-off-by: Matthias Glastra --- attestation/commandrun/commandrun.go | 2 +- attestation/context.go | 4 + attestation/context_env.go | 52 +++++ attestation/environment/environment.go | 198 +++++------------ attestation/environment/environment_test.go | 208 ------------------ environment/environment.go | 115 ++++++++++ environment/environment_test.go | 208 ++++++++++++++++++ .../environment => environment}/filter.go | 2 +- .../environment => environment}/obfuscate.go | 0 .../sensitive_env_vars.go | 12 +- 10 files changed, 449 insertions(+), 352 deletions(-) create mode 100644 attestation/context_env.go delete mode 100644 attestation/environment/environment_test.go create mode 100644 environment/environment.go create mode 100644 environment/environment_test.go rename {attestation/environment => environment}/filter.go (97%) rename {attestation/environment => environment}/obfuscate.go (100%) rename {attestation/environment => environment}/sensitive_env_vars.go (96%) diff --git a/attestation/commandrun/commandrun.go b/attestation/commandrun/commandrun.go index 9b58a340..2495501f 100644 --- a/attestation/commandrun/commandrun.go +++ b/attestation/commandrun/commandrun.go @@ -21,7 +21,7 @@ import ( "os/exec" "github.com/in-toto/go-witness/attestation" - "github.com/in-toto/go-witness/attestation/environment" + "github.com/in-toto/go-witness/environment" "github.com/in-toto/go-witness/cryptoutil" "github.com/invopop/jsonschema" ) diff --git a/attestation/context.go b/attestation/context.go index 4f81086b..ae201ddf 100644 --- a/attestation/context.go +++ b/attestation/context.go @@ -24,6 +24,7 @@ import ( "github.com/gobwas/glob" "github.com/in-toto/go-witness/cryptoutil" + "github.com/in-toto/go-witness/environment" "github.com/in-toto/go-witness/log" ) @@ -117,6 +118,7 @@ type AttestationContext struct { materials map[string]cryptoutil.DigestSet stepName string mutex sync.RWMutex + environmentCapturer *environment.Capture } type Product struct { @@ -229,6 +231,8 @@ func (ctx *AttestationContext) DirHashGlob() []glob.Glob { return ctx.dirHashGlobCompiled } + + func (ctx *AttestationContext) CompletedAttestors() []CompletedAttestor { ctx.mutex.RLock() out := make([]CompletedAttestor, len(ctx.completedAttestors)) diff --git a/attestation/context_env.go b/attestation/context_env.go new file mode 100644 index 00000000..fa8936f4 --- /dev/null +++ b/attestation/context_env.go @@ -0,0 +1,52 @@ +// Copyright 2024 The Witness Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package attestation + +import ( + env "github.com/in-toto/go-witness/environment" +) + +func (ctx *AttestationContext) EnvironmentCapturer() *env.Capture { + return ctx.environmentCapturer +} + +// WithEnvFilterVarsEnabled will make the filter (removing) of vars the acting behavior. +// The default behavior is obfuscation of variables. +func WithEnvFilterVarsEnabled() AttestationContextOption { + return func(a *AttestationContext) { + env.WithFilterVarsEnabled()(a.environmentCapturer) + } +} + +// WithEnvAdditionalKeys add additional keys to final list that is checked for sensitive variables. +func WithEnvAdditionalKeys(additionalKeys []string) AttestationContextOption { + return func(a *AttestationContext) { + env.WithAdditionalKeys(additionalKeys)(a.environmentCapturer) + } +} + +// WithEnvExcludeKeys add additional keys to final list that is checked for sensitive variables. +func WithEnvExcludeKeys(excludeKeys []string) AttestationContextOption { + return func(a *AttestationContext) { + env.WithExcludeKeys(excludeKeys)(a.environmentCapturer) + } +} + +// WithEnvDisableDefaultSensitiveList will disable the default list and only use the additional keys. +func WithEnvDisableDefaultSensitiveList() AttestationContextOption { + return func(a *AttestationContext) { + env.WithDisableDefaultSensitiveList()(a.environmentCapturer) + } +} diff --git a/attestation/environment/environment.go b/attestation/environment/environment.go index f0dd1b09..ec954162 100644 --- a/attestation/environment/environment.go +++ b/attestation/environment/environment.go @@ -15,14 +15,11 @@ package environment import ( - "fmt" "os" "os/user" "runtime" - "strings" "github.com/in-toto/go-witness/attestation" - "github.com/in-toto/go-witness/registry" "github.com/invopop/jsonschema" ) @@ -51,64 +48,64 @@ type EnvironmentAttestor interface { } func init() { - attestation.RegisterAttestation(Name, Type, RunType, func() attestation.Attestor { return New() }, - registry.BoolConfigOption( - "filter-sensitive-vars", - "Switch from obfuscate to filtering variables which removes them from the output completely.", - defaultFilterSensitiveVarsEnabled, - func(a attestation.Attestor, filterSensitiveVarsEnabled bool) (attestation.Attestor, error) { - envAttestor, ok := a.(*Attestor) - if !ok { - return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) - } - - WithFilterVarsEnabled()(envAttestor) - return envAttestor, nil - }, - ), - registry.BoolConfigOption( - "disable-default-sensitive-vars", - "Disable the default list of sensitive vars and only use the items mentioned by --attestor-environment-sensitive-key.", - defaultDisableSensitiveVarsDefault, - func(a attestation.Attestor, disableSensitiveVarsDefault bool) (attestation.Attestor, error) { - envAttestor, ok := a.(*Attestor) - if !ok { - return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) - } - - WithDisableDefaultSensitiveList()(envAttestor) - return envAttestor, nil - }, - ), - registry.StringSliceConfigOption( - "add-sensitive-key", - "Add keys or globs (e.g. '*TEXT') to the list of sensitive environment keys.", - []string{}, - func(a attestation.Attestor, additionalKeys []string) (attestation.Attestor, error) { - envAttestor, ok := a.(*Attestor) - if !ok { - return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) - } - - WithAdditionalKeys(additionalKeys)(envAttestor) - return envAttestor, nil - }, - ), - registry.StringSliceConfigOption( - "exclude-sensitive-key", - "Exclude specific keys from the list of sensitive environment keys. Note: This does not support globs.", - []string{}, - func(a attestation.Attestor, excludeKeys []string) (attestation.Attestor, error) { - envAttestor, ok := a.(*Attestor) - if !ok { - return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) - } - - WithExcludeKeys(excludeKeys)(envAttestor) - return envAttestor, nil - }, - ), - ) + // attestation.RegisterAttestation(Name, Type, RunType, func() attestation.Attestor { return New() }, + // registry.BoolConfigOption( + // "filter-sensitive-vars", + // "Switch from obfuscate to filtering variables which removes them from the output completely.", + // defaultFilterSensitiveVarsEnabled, + // func(a attestation.Attestor, filterSensitiveVarsEnabled bool) (attestation.Attestor, error) { + // envAttestor, ok := a.(*Attestor) + // if !ok { + // return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) + // } + + // envCapture.WithFilterVarsEnabled()(envAttestor.capture) + // return envAttestor, nil + // }, + // ), + // registry.BoolConfigOption( + // "disable-default-sensitive-vars", + // "Disable the default list of sensitive vars and only use the items mentioned by --attestor-environment-sensitive-key.", + // defaultDisableSensitiveVarsDefault, + // func(a attestation.Attestor, disableSensitiveVarsDefault bool) (attestation.Attestor, error) { + // envAttestor, ok := a.(*Attestor) + // if !ok { + // return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) + // } + + // envCapture.WithDisableDefaultSensitiveList()(envAttestor.capture) + // return envAttestor, nil + // }, + // ), + // registry.StringSliceConfigOption( + // "add-sensitive-key", + // "Add keys or globs (e.g. '*TEXT') to the list of sensitive environment keys.", + // []string{}, + // func(a attestation.Attestor, additionalKeys []string) (attestation.Attestor, error) { + // envAttestor, ok := a.(*Attestor) + // if !ok { + // return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) + // } + + // envCapture.WithAdditionalKeys(additionalKeys)(envAttestor.capture) + // return envAttestor, nil + // }, + // ), + // registry.StringSliceConfigOption( + // "exclude-sensitive-key", + // "Exclude specific keys from the list of sensitive environment keys. Note: This does not support globs.", + // []string{}, + // func(a attestation.Attestor, excludeKeys []string) (attestation.Attestor, error) { + // envAttestor, ok := a.(*Attestor) + // if !ok { + // return a, fmt.Errorf("unexpected attestor type: %T is not a environment attestor", a) + // } + + // envCapture.WithExcludeKeys(excludeKeys)(envAttestor.capture) + // return envAttestor, nil + // }, + // ), + // ) } type Attestor struct { @@ -117,49 +114,11 @@ type Attestor struct { Username string `json:"username"` Variables map[string]string `json:"variables,omitempty"` - osEnviron func() []string - sensitiveVarsList map[string]struct{} - addSensitiveVarsList map[string]struct{} - excludeSensitiveVarsList map[string]struct{} - filterVarsEnabled bool - disableSensitiveVarsDefault bool + osEnviron func() []string } type Option func(*Attestor) -// WithFilterVarsEnabled will make the filter (removing) of vars the acting behavior. -// The default behavior is obfuscation of variables. -func WithFilterVarsEnabled() Option { - return func(a *Attestor) { - a.filterVarsEnabled = true - } -} - -// WithAdditionalKeys add additional keys to final list that is checked for sensitive variables. -func WithAdditionalKeys(additionalKeys []string) Option { - return func(a *Attestor) { - for _, value := range additionalKeys { - a.addSensitiveVarsList[value] = struct{}{} - } - } -} - -// WithExcludeKeys add additional keys to final list that is checked for sensitive variables. -func WithExcludeKeys(excludeKeys []string) Option { - return func(a *Attestor) { - for _, value := range excludeKeys { - a.excludeSensitiveVarsList[value] = struct{}{} - } - } -} - -// WithDisableDefaultSensitiveList will disable the default list and only use the additional keys. -func WithDisableDefaultSensitiveList() Option { - return func(a *Attestor) { - a.disableSensitiveVarsDefault = true - } -} - // WithCustomEnv will override the default os.Environ() method. This could be used to mock. func WithCustomEnv(osEnviron func() []string) Option { return func(a *Attestor) { @@ -168,11 +127,7 @@ func WithCustomEnv(osEnviron func() []string) Option { } func New(opts ...Option) *Attestor { - attestor := &Attestor{ - sensitiveVarsList: DefaultSensitiveEnvList(), - addSensitiveVarsList: map[string]struct{}{}, - excludeSensitiveVarsList: map[string]struct{}{}, - } + attestor := &Attestor{} attestor.osEnviron = os.Environ @@ -211,26 +166,7 @@ func (a *Attestor) Attest(ctx *attestation.AttestationContext) error { a.Username = user.Username } - // Prepare sensitive keys list. - var finalSensitiveKeysList map[string]struct{} - if a.disableSensitiveVarsDefault { - a.sensitiveVarsList = map[string]struct{}{} - } - finalSensitiveKeysList = a.sensitiveVarsList - for k, v := range a.addSensitiveVarsList { - finalSensitiveKeysList[k] = v - } - - // Filter or obfuscate - if a.filterVarsEnabled { - FilterEnvironmentArray(a.osEnviron(), finalSensitiveKeysList, a.excludeSensitiveVarsList, func(key, val, _ string) { - a.Variables[key] = val - }) - } else { - ObfuscateEnvironmentArray(a.osEnviron(), finalSensitiveKeysList, a.excludeSensitiveVarsList, func(key, val, _ string) { - a.Variables[key] = val - }) - } + a.Variables = ctx.EnvironmentCapturer().Capture(a.osEnviron()) return nil } @@ -238,15 +174,3 @@ func (a *Attestor) Attest(ctx *attestation.AttestationContext) error { func (a *Attestor) Data() *Attestor { return a } - -// splitVariable splits a string representing an environment variable in the format of -// "KEY=VAL" and returns the key and val separately. -func splitVariable(v string) (key, val string) { - parts := strings.SplitN(v, "=", 2) - key = parts[0] - if len(parts) > 1 { - val = parts[1] - } - - return -} diff --git a/attestation/environment/environment_test.go b/attestation/environment/environment_test.go deleted file mode 100644 index e8e0a7c8..00000000 --- a/attestation/environment/environment_test.go +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2021 The Witness Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package environment - -import ( - "os" - "testing" - - "github.com/in-toto/go-witness/attestation" - "github.com/stretchr/testify/require" -) - -// TestFilterVarsEnvironment tests if enabling filter behavior works correctly. -func TestFilterVarsEnvironment(t *testing.T) { - - customEnv := func() []string { - return []string{"AWS_ACCESS_KEY_ID=super secret"} - } - - attestor := New( - WithFilterVarsEnabled(), - WithCustomEnv(customEnv), - ) - - ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) - require.NoError(t, err) - - origVars := customEnv() - require.NoError(t, attestor.Attest(ctx)) - for _, env := range origVars { - origKey, _ := splitVariable(env) - if _, inBlockList := attestor.sensitiveVarsList[origKey]; inBlockList { - require.NotContains(t, attestor.Variables, origKey) - } else { - require.Contains(t, attestor.Variables, origKey) - } - } -} - -// TestExcludeVarsEnvironment tests if enabling filter behavior works correctly. -func TestExcludeVarsEnvironment(t *testing.T) { - - customEnv := func() []string { - return []string{"AWS_ACCESS_KEY_ID=super secret"} - } - - attestor := New( - WithExcludeKeys([]string{"AWS_ACCESS_KEY_ID"}), - WithCustomEnv(customEnv), - ) - - ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) - require.NoError(t, err) - - origVars := customEnv() - require.NoError(t, attestor.Attest(ctx)) - for _, env := range origVars { - origKey, _ := splitVariable(env) - if _, inList := attestor.excludeSensitiveVarsList[origKey]; inList { - require.Contains(t, attestor.Variables, origKey) - } else { - require.NotContains(t, attestor.Variables, origKey) - } - } -} - -// TestEnvironmentObfuscate tests if obfuscate normal behavior works correctly. -func TestEnvironmentObfuscate(t *testing.T) { - attestor := New() - ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) - require.NoError(t, err) - - obfuscateEnvs := map[string]struct{}{"API_TOKEN": {}, "SECRET_TEXT": {}} - secretVarValue := "secret var" - publicVarValue := "public var" - for k := range obfuscateEnvs { - t.Setenv(k, secretVarValue) - } - - notObfuscateEnvs := map[string]struct{}{"VAR_FOO": {}, "VAR_BAR": {}} - for k := range notObfuscateEnvs { - t.Setenv(k, publicVarValue) - } - - origVars := os.Environ() - require.NoError(t, attestor.Attest(ctx)) - for _, env := range origVars { - origKey, _ := splitVariable(env) - if _, inObfuscateList := obfuscateEnvs[origKey]; inObfuscateList { - require.NotEqual(t, attestor.Variables[origKey], secretVarValue) - require.Equal(t, attestor.Variables[origKey], "******") - } - - if _, inNotObfuscateList := notObfuscateEnvs[origKey]; inNotObfuscateList { - require.Equal(t, attestor.Variables[origKey], publicVarValue) - } - } -} - -// TestEnvironmentObfuscateAdditional tests if the default obfuscate with additional keys works correctly. -func TestEnvironmentObfuscateAdditional(t *testing.T) { - attestor := New(WithAdditionalKeys([]string{"MYNAME"})) - ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) - require.NoError(t, err) - - obfuscateEnvs := map[string]struct{}{"API_TOKEN": {}, "MYNAME": {}} - secretVarValue := "secret var" - publicVarValue := "public var" - for k := range obfuscateEnvs { - t.Setenv(k, secretVarValue) - } - - notObfuscateEnvs := map[string]struct{}{"VAR_FOO": {}, "VAR_BAR": {}} - for k := range notObfuscateEnvs { - t.Setenv(k, publicVarValue) - } - - origVars := os.Environ() - require.NoError(t, attestor.Attest(ctx)) - for _, env := range origVars { - origKey, _ := splitVariable(env) - if _, inObfuscateList := obfuscateEnvs[origKey]; inObfuscateList { - require.NotEqual(t, attestor.Variables[origKey], secretVarValue) - require.Equal(t, attestor.Variables[origKey], "******") - } - - if _, inNotObfuscateList := notObfuscateEnvs[origKey]; inNotObfuscateList { - require.Equal(t, attestor.Variables[origKey], publicVarValue) - } - } -} - -// TestEnvironmentCustomKeysAdditional tests if the default list is disabled the additional keys works correctly. -func TestEnvironmentCustomKeysAdditional(t *testing.T) { - attestor := New(WithDisableDefaultSensitiveList(), WithAdditionalKeys([]string{"MYNAME"})) - ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) - require.NoError(t, err) - - obfuscateEnvs := map[string]struct{}{"MYNAME": {}} - secretVarValue := "secret var" - publicVarValue := "public var" - for k := range obfuscateEnvs { - t.Setenv(k, secretVarValue) - } - - notObfuscateEnvs := map[string]struct{}{"API_TOKEN": {}} - for k := range notObfuscateEnvs { - t.Setenv(k, publicVarValue) - } - - origVars := os.Environ() - require.NoError(t, attestor.Attest(ctx)) - for _, env := range origVars { - origKey, _ := splitVariable(env) - if _, inObfuscateList := obfuscateEnvs[origKey]; inObfuscateList { - require.NotEqual(t, attestor.Variables[origKey], secretVarValue) - require.Equal(t, attestor.Variables[origKey], "******") - } - - if _, inNotObfuscateList := notObfuscateEnvs[origKey]; inNotObfuscateList { - require.Equal(t, attestor.Variables[origKey], publicVarValue) - } - } -} - -// TestEnvironmentFilterAdditional tests if enabling filter and adding additional keys works correctly. -func TestEnvironmentFilterAdditional(t *testing.T) { - attestor := New(WithFilterVarsEnabled(), WithAdditionalKeys([]string{"MYNAME"})) - ctx, err := attestation.NewContext("test", []attestation.Attestor{attestor}) - require.NoError(t, err) - - filterEnvs := map[string]struct{}{"API_TOKEN": {}, "MYNAME": {}} - secretVarValue := "secret var" - publicVarValue := "public var" - for k := range filterEnvs { - t.Setenv(k, secretVarValue) - } - - notFilterEnvs := map[string]struct{}{"VAR_FOO": {}, "VAR_BAR": {}} - for k := range notFilterEnvs { - t.Setenv(k, publicVarValue) - } - - origVars := os.Environ() - require.NoError(t, attestor.Attest(ctx)) - for _, env := range origVars { - origKey, _ := splitVariable(env) - if _, inFilterList := filterEnvs[origKey]; inFilterList { - require.NotContains(t, attestor.Variables, origKey) - } - - if _, inNotObfuscateList := notFilterEnvs[origKey]; inNotObfuscateList { - require.Equal(t, attestor.Variables[origKey], publicVarValue) - } - } -} diff --git a/environment/environment.go b/environment/environment.go new file mode 100644 index 00000000..4a23ce22 --- /dev/null +++ b/environment/environment.go @@ -0,0 +1,115 @@ +// Copyright 2024 The Witness Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package environment + +import ( + "strings" +) + +type Capture struct { + sensitiveVarsList map[string]struct{} + addSensitiveVarsList map[string]struct{} + excludeSensitiveVarsList map[string]struct{} + filterVarsEnabled bool + disableSensitiveVarsDefault bool +} + +type CaptureOption func(*Capture) + +// WithFilterVarsEnabled will make the filter (removing) of vars the acting behavior. +// The default behavior is obfuscation of variables. +func WithFilterVarsEnabled() CaptureOption { + return func(c *Capture) { + c.filterVarsEnabled = true + } +} + +// WithAdditionalKeys add additional keys to final list that is checked for sensitive variables. +func WithAdditionalKeys(additionalKeys []string) CaptureOption { + return func(c *Capture) { + for _, value := range additionalKeys { + c.addSensitiveVarsList[value] = struct{}{} + } + } +} + +// WithExcludeKeys add additional keys to final list that is checked for sensitive variables. +func WithExcludeKeys(excludeKeys []string) CaptureOption { + return func(c *Capture) { + for _, value := range excludeKeys { + c.excludeSensitiveVarsList[value] = struct{}{} + } + } +} + +// WithDisableDefaultSensitiveList will disable the default list and only use the additional keys. +func WithDisableDefaultSensitiveList() CaptureOption { + return func(c *Capture) { + c.disableSensitiveVarsDefault = true + } +} + +func New(opts ...CaptureOption) *Capture { + capture := &Capture{ + sensitiveVarsList: DefaultSensitiveEnvList(), + addSensitiveVarsList: map[string]struct{}{}, + excludeSensitiveVarsList: map[string]struct{}{}, + } + + for _, opt := range opts { + opt(capture) + } + + return capture +} + +func (c *Capture) Capture(env []string) map[string]string { + variables := make(map[string]string) + + // Prepare sensitive keys list. + var finalSensitiveKeysList map[string]struct{} + if c.disableSensitiveVarsDefault { + c.sensitiveVarsList = map[string]struct{}{} + } + finalSensitiveKeysList = c.sensitiveVarsList + for k, v := range c.addSensitiveVarsList { + finalSensitiveKeysList[k] = v + } + + // Filter or obfuscate + if c.filterVarsEnabled { + FilterEnvironmentArray(env, finalSensitiveKeysList, c.excludeSensitiveVarsList, func(key, val, _ string) { + variables[key] = val + }) + } else { + ObfuscateEnvironmentArray(env, finalSensitiveKeysList, c.excludeSensitiveVarsList, func(key, val, _ string) { + variables[key] = val + }) + } + + return variables +} + +// splitVariable splits a string representing an environment variable in the format of +// "KEY=VAL" and returns the key and val separately. +func splitVariable(v string) (key, val string) { + parts := strings.SplitN(v, "=", 2) + key = parts[0] + if len(parts) > 1 { + val = parts[1] + } + + return +} diff --git a/environment/environment_test.go b/environment/environment_test.go new file mode 100644 index 00000000..d9e9c93a --- /dev/null +++ b/environment/environment_test.go @@ -0,0 +1,208 @@ +package environment + +import ( + "reflect" + "testing" +) + +func Test_splitVariable(t *testing.T) { + type args struct { + v string + } + tests := []struct { + name string + args args + wantKey string + wantVal string + }{ + { + name: "KEY=VALUE", + args: args{ + v: "KEY=VALUE", + }, + wantKey: "KEY", + wantVal: "VALUE", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotKey, gotVal := splitVariable(tt.args.v) + if gotKey != tt.wantKey { + t.Errorf("splitVariable() gotKey = %v, want %v", gotKey, tt.wantKey) + } + if gotVal != tt.wantVal { + t.Errorf("splitVariable() gotVal = %v, want %v", gotVal, tt.wantVal) + } + }) + } +} + +func TestCapture_Capture(t *testing.T) { + type fields struct { + sensitiveVarsList map[string]struct{} + addSensitiveVarsList map[string]struct{} + excludeSensitiveVarsList map[string]struct{} + filterVarsEnabled bool + disableSensitiveVarsDefault bool + } + type args struct { + env []string + } + tests := []struct { + name string + fields fields + args args + want map[string]string + }{ + { + name: "Obfuscate *_TOKEN", + fields: fields{ + sensitiveVarsList: DefaultSensitiveEnvList(), + addSensitiveVarsList: map[string]struct{}{}, + excludeSensitiveVarsList: map[string]struct{}{}, + filterVarsEnabled: false, + disableSensitiveVarsDefault: false, + }, + args: args{ + env: []string{ + "TEST_TOKEN=password", + "TEST_TEXT=value", + }, + }, + want: map[string]string{ + "TEST_TOKEN": "******", + "TEST_TEXT": "value", + }, + }, + { + name: "Filter *_TOKEN", + fields: fields{ + sensitiveVarsList: DefaultSensitiveEnvList(), + addSensitiveVarsList: map[string]struct{}{}, + excludeSensitiveVarsList: map[string]struct{}{}, + filterVarsEnabled: true, + disableSensitiveVarsDefault: false, + }, + args: args{ + env: []string{ + "TEST_TOKEN=password", + "TEST_TEXT=value", + }, + }, + want: map[string]string{ + "TEST_TEXT": "value", + }, + }, + { + name: "Disable sensitive vars", + fields: fields{ + sensitiveVarsList: DefaultSensitiveEnvList(), + addSensitiveVarsList: map[string]struct{}{}, + excludeSensitiveVarsList: map[string]struct{}{}, + filterVarsEnabled: true, + disableSensitiveVarsDefault: true, + }, + args: args{ + env: []string{ + "TEST_TOKEN=password", + "TEST_TEXT=value", + }, + }, + want: map[string]string{ + "TEST_TOKEN": "password", + "TEST_TEXT": "value", + }, + }, + { + name: "Obfuscate custom sensitive vars", + fields: fields{ + sensitiveVarsList: DefaultSensitiveEnvList(), + addSensitiveVarsList: map[string]struct{}{ + "*_BLA": {}, + }, + excludeSensitiveVarsList: map[string]struct{}{}, + filterVarsEnabled: false, + disableSensitiveVarsDefault: true, + }, + args: args{ + env: []string{ + "TEST_BLA=password", + "TEST_TEXT=value", + }, + }, + want: map[string]string{ + "TEST_BLA": "******", + "TEST_TEXT": "value", + }, + }, + { + name: "Filter custom sensitive vars", + fields: fields{ + sensitiveVarsList: DefaultSensitiveEnvList(), + addSensitiveVarsList: map[string]struct{}{ + "*_BLA": {}, + }, + excludeSensitiveVarsList: map[string]struct{}{}, + filterVarsEnabled: true, + disableSensitiveVarsDefault: true, + }, + args: args{ + env: []string{ + "TEST_BLA=password", + "TEST_TEXT=value", + }, + }, + want: map[string]string{ + "TEST_TEXT": "value", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Capture{ + sensitiveVarsList: tt.fields.sensitiveVarsList, + addSensitiveVarsList: tt.fields.addSensitiveVarsList, + excludeSensitiveVarsList: tt.fields.excludeSensitiveVarsList, + filterVarsEnabled: tt.fields.filterVarsEnabled, + disableSensitiveVarsDefault: tt.fields.disableSensitiveVarsDefault, + } + if got := c.Capture(tt.args.env); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Capture.Capture() = %v, want %v", got, tt.want) + } + }) + } +} + +func _TestWith() CaptureOption { + return func(c *Capture) { + c.filterVarsEnabled = true + } +} + +func TestNew(t *testing.T) { + type args struct { + opts []CaptureOption + } + tests := []struct { + name string + args args + want *Capture + }{ + { + name: "With", + args: args{ + opts: []CaptureOption{_TestWith()}, + }, + want: &Capture{ + filterVarsEnabled: true, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := New(tt.args.opts...); got.filterVarsEnabled != tt.want.filterVarsEnabled { + t.Errorf("New() = %v, want %v", got.filterVarsEnabled, tt.want.filterVarsEnabled) + } + }) + } +} diff --git a/attestation/environment/filter.go b/environment/filter.go similarity index 97% rename from attestation/environment/filter.go rename to environment/filter.go index 46e09cf0..e2682c17 100644 --- a/attestation/environment/filter.go +++ b/environment/filter.go @@ -1,4 +1,4 @@ -// Copyright 2021 The Witness Contributors +// Copyright 2024 The Witness Contributors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/attestation/environment/obfuscate.go b/environment/obfuscate.go similarity index 100% rename from attestation/environment/obfuscate.go rename to environment/obfuscate.go diff --git a/attestation/environment/sensitive_env_vars.go b/environment/sensitive_env_vars.go similarity index 96% rename from attestation/environment/sensitive_env_vars.go rename to environment/sensitive_env_vars.go index 64f1ba24..f7282c34 100644 --- a/attestation/environment/sensitive_env_vars.go +++ b/environment/sensitive_env_vars.go @@ -21,11 +21,13 @@ func DefaultSensitiveEnvList() map[string]struct{} { return map[string]struct{}{ // Glob pattern list - "*TOKEN*": {}, - "*SECRET*": {}, - "*API_KEY*": {}, - "*PASSWORD*": {}, - "*JWT*": {}, + "*TOKEN*": {}, + "*SECRET*": {}, + "*API_KEY*": {}, + "*PASSWORD*": {}, + "*JWT*": {}, + "*sshKey*": {}, + "*passphrase*": {}, // Explicit list "AWS_ACCESS_KEY_ID": {},