sigs.k8s.io/prow@v0.0.0-20240503223140-c5e374dc7eb1/pkg/logrusutil/logrusutil_test.go (about) 1 /* 2 Copyright 2019 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package logrusutil 18 19 import ( 20 "fmt" 21 "testing" 22 23 "github.com/google/go-cmp/cmp" 24 "github.com/sirupsen/logrus" 25 "sigs.k8s.io/prow/pkg/secretutil" 26 27 "k8s.io/apimachinery/pkg/util/sets" 28 ) 29 30 func TestCensoringFormatter(t *testing.T) { 31 32 testCases := []struct { 33 description string 34 entry *logrus.Entry 35 expected string 36 }{ 37 { 38 description: "all occurrences of a single secret in a message are censored", 39 entry: &logrus.Entry{Message: "A SECRET is a SECRET if it is secret"}, 40 expected: "level=panic msg=\"A XXXXXX is a XXXXXX if it is secret\"\n", 41 }, 42 { 43 description: "occurrences of a multiple secrets in a message are censored", 44 entry: &logrus.Entry{Message: "A SECRET is a MYSTERY"}, 45 expected: "level=panic msg=\"A XXXXXX is a XXXXXXX\"\n", 46 }, 47 { 48 description: "occurrences of multiple secrets in a field", 49 entry: &logrus.Entry{Message: "message", Data: logrus.Fields{"key": "A SECRET is a MYSTERY"}}, 50 expected: "level=panic msg=message key=\"A XXXXXX is a XXXXXXX\"\n", 51 }, 52 { 53 description: "occurrences of a secret in a non-string field", 54 entry: &logrus.Entry{Message: "message", Data: logrus.Fields{"key": fmt.Errorf("A SECRET is a MYSTERY")}}, 55 expected: "level=panic msg=message key=\"A XXXXXX is a XXXXXXX\"\n", 56 }, 57 } 58 59 baseFormatter := &logrus.TextFormatter{ 60 DisableColors: true, 61 DisableTimestamp: true, 62 } 63 formatter := NewCensoringFormatter(baseFormatter, func() sets.Set[string] { 64 return sets.New[string]("MYSTERY", "SECRET") 65 }) 66 67 for _, tc := range testCases { 68 t.Run(tc.description, func(t *testing.T) { 69 censored, err := formatter.Format(tc.entry) 70 if err != nil { 71 t.Errorf("Unexpected error: %v", err) 72 } 73 if string(censored) != tc.expected { 74 t.Errorf("Expected '%s', got '%s'", tc.expected, string(censored)) 75 } 76 }) 77 } 78 } 79 80 func TestCensoringFormatterDelegateFormatter(t *testing.T) { 81 delegate := &logrus.JSONFormatter{} 82 censorer := secretutil.NewCensorer() 83 message := `COMPLEX 84 secret 85 with "chars" that need fixing in JSON` 86 censorer.Refresh(message) 87 formatter := NewFormatterWithCensor(delegate, censorer) 88 censored, err := formatter.Format(&logrus.Entry{Message: message}) 89 if err != nil { 90 t.Fatalf("got an error from censoring: %v", err) 91 } 92 if diff := cmp.Diff(string(censored), `{"level":"panic","msg":"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","time":"0001-01-01T00:00:00Z"} 93 `); diff != "" { 94 t.Errorf("got incorrect output after censoring: %v", diff) 95 } 96 } 97 98 func TestCensoringFormatterWithCornerCases(t *testing.T) { 99 entry := &logrus.Entry{Message: "message", Data: logrus.Fields{"key": fmt.Errorf("A SECRET is a secret")}} 100 expectedEntry := "level=panic msg=message key=\"A XXXXXX is a secret\"\n" 101 102 testCases := []struct { 103 description string 104 secrets sets.Set[string] 105 expected string 106 }{ 107 { 108 description: "empty string", 109 secrets: sets.New[string]("SECRET", ""), 110 expected: expectedEntry, 111 }, 112 { 113 description: "leading line break", 114 secrets: sets.New[string]("\nSECRET", ""), 115 expected: expectedEntry, 116 }, 117 { 118 description: "tailing line break", 119 secrets: sets.New[string]("SECRET\n", ""), 120 expected: expectedEntry, 121 }, 122 { 123 description: "leading space and tailing space", 124 secrets: sets.New[string](" SECRET ", ""), 125 expected: expectedEntry, 126 }, 127 } 128 129 baseFormatter := &logrus.TextFormatter{ 130 DisableColors: true, 131 DisableTimestamp: true, 132 } 133 134 for _, tc := range testCases { 135 t.Run(tc.description, func(t *testing.T) { 136 formatter := NewCensoringFormatter(baseFormatter, func() sets.Set[string] { 137 return tc.secrets 138 }) 139 140 censored, err := formatter.Format(entry) 141 if err != nil { 142 t.Errorf("Unexpected error: %v", err) 143 } 144 if string(censored) != tc.expected { 145 t.Errorf("Expected '%s', got '%s'", tc.expected, string(censored)) 146 } 147 }) 148 } 149 } 150 151 func TestCensoringFormatterDoesntDeadLockWhenUsedWithStandardLogger(t *testing.T) { 152 // The whitespace makes the censoring fornmatter emit a warning. If it uses the same global 153 // logger, that results in a deadlock. 154 logrus.SetFormatter(NewCensoringFormatter(logrus.StandardLogger().Formatter, func() sets.Set[string] { 155 return sets.New[string](" untrimmed") 156 })) 157 logrus.Info("test") 158 }