Skip to content

Commit 6666333

Browse files
committed
scrub struct before log
1 parent 42115fc commit 6666333

File tree

5 files changed

+142
-12
lines changed

5 files changed

+142
-12
lines changed

components/scrubber/scrubber.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"reflect"
1111
"regexp"
1212
"strings"
13+
"unsafe"
1314

1415
"github.com/mitchellh/reflectwalk"
1516
)
@@ -86,6 +87,8 @@ type Scrubber interface {
8687
// }
8788
//
8889
Struct(val any) error
90+
91+
DeepCopyStruct(val any) any
8992
}
9093

9194
// Default is the default scrubber consumers of this package should use
@@ -189,6 +192,127 @@ func (s *scrubberImpl) Struct(val any) error {
189192
return nil
190193
}
191194

195+
func (s *scrubberImpl) deepCopyStruct(fieldName string, src reflect.Value, scrubTag string) reflect.Value {
196+
if src.Kind() == reflect.Ptr && src.IsNil() {
197+
return reflect.New(src.Type()).Elem()
198+
}
199+
200+
if src.Kind() == reflect.String {
201+
dst := reflect.New(src.Type())
202+
var (
203+
setExplicitValue bool
204+
explicitValue string
205+
)
206+
switch scrubTag {
207+
case "ignore":
208+
return dst
209+
case "hash":
210+
setExplicitValue = true
211+
explicitValue = SanitiseHash(src.String())
212+
case "redact":
213+
setExplicitValue = true
214+
explicitValue = SanitiseRedact(src.String())
215+
}
216+
217+
if setExplicitValue {
218+
dst.Elem().SetString(explicitValue)
219+
} else {
220+
sanitisatiser := s.getSanitisatiser(fieldName)
221+
if sanitisatiser != nil {
222+
dst.Elem().SetString(sanitisatiser(src.String()))
223+
}
224+
}
225+
if !dst.CanInterface() {
226+
return dst
227+
}
228+
return dst.Elem()
229+
}
230+
231+
switch src.Kind() {
232+
233+
case reflect.Struct:
234+
dst := reflect.New(src.Type())
235+
t := src.Type()
236+
237+
for i := 0; i < t.NumField(); i++ {
238+
f := t.Field(i)
239+
srcValue := src.Field(i)
240+
dstValue := dst.Elem().Field(i)
241+
242+
if !srcValue.CanInterface() {
243+
dstValue = reflect.NewAt(dstValue.Type(), unsafe.Pointer(dstValue.UnsafeAddr())).Elem()
244+
245+
if !srcValue.CanAddr() {
246+
switch {
247+
case srcValue.CanInt():
248+
dstValue.SetInt(srcValue.Int())
249+
case srcValue.CanUint():
250+
dstValue.SetUint(srcValue.Uint())
251+
case srcValue.CanFloat():
252+
dstValue.SetFloat(srcValue.Float())
253+
case srcValue.CanComplex():
254+
dstValue.SetComplex(srcValue.Complex())
255+
case srcValue.Kind() == reflect.Bool:
256+
dstValue.SetBool(srcValue.Bool())
257+
}
258+
259+
continue
260+
}
261+
262+
srcValue = reflect.NewAt(srcValue.Type(), unsafe.Pointer(srcValue.UnsafeAddr())).Elem()
263+
}
264+
265+
tagValue := f.Tag.Get("scrub")
266+
copied := s.deepCopyStruct(f.Name, srcValue, tagValue)
267+
dstValue.Set(copied)
268+
}
269+
return dst.Elem()
270+
271+
case reflect.Map:
272+
dst := reflect.MakeMap(src.Type())
273+
keys := src.MapKeys()
274+
for i := 0; i < src.Len(); i++ {
275+
mValue := src.MapIndex(keys[i])
276+
dst.SetMapIndex(keys[i], s.deepCopyStruct(keys[i].String(), mValue, ""))
277+
}
278+
return dst
279+
280+
case reflect.Slice:
281+
dst := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
282+
for i := 0; i < src.Len(); i++ {
283+
dst.Index(i).Set(s.deepCopyStruct(fieldName, src.Index(i), ""))
284+
}
285+
return dst
286+
287+
case reflect.Array:
288+
if src.Len() == 0 {
289+
return src // can not access to src.Index(0)
290+
}
291+
292+
dst := reflect.New(src.Type()).Elem()
293+
for i := 0; i < src.Len(); i++ {
294+
dst.Index(i).Set(s.deepCopyStruct(fieldName, src.Index(i), ""))
295+
}
296+
return dst
297+
298+
case reflect.Ptr:
299+
dst := reflect.New(src.Elem().Type())
300+
copied := s.deepCopyStruct(fieldName, src.Elem(), scrubTag)
301+
dst.Elem().Set(copied)
302+
return dst
303+
304+
default:
305+
dst := reflect.New(src.Type())
306+
dst.Elem().Set(src)
307+
return dst.Elem()
308+
}
309+
}
310+
311+
// Struct implements Scrubber
312+
func (s *scrubberImpl) DeepCopyStruct(val any) any {
313+
return s.deepCopyStruct("", reflect.ValueOf(val), "").Interface()
314+
}
315+
192316
func (s *scrubberImpl) scrubJsonObject(val map[string]interface{}) error {
193317
// fix https://github.com/gitpod-io/security/issues/64
194318
name, _ := val["name"].(string)

components/ws-manager-mk2/controllers/workspace_controller.go

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import (
2929
"sigs.k8s.io/controller-runtime/pkg/log"
3030

3131
wsk8s "github.com/gitpod-io/gitpod/common-go/kubernetes"
32-
"github.com/gitpod-io/gitpod/components/scrubber"
3332
"github.com/gitpod-io/gitpod/ws-manager-mk2/pkg/maintenance"
3433
config "github.com/gitpod-io/gitpod/ws-manager/api/config"
3534
workspacev1 "github.com/gitpod-io/gitpod/ws-manager/api/crd/v1"
@@ -126,20 +125,13 @@ func (r *WorkspaceReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
126125
r.updateMetrics(ctx, &workspace)
127126
r.emitPhaseEvents(ctx, &workspace, oldStatus)
128127

129-
var scrubbedPodStatus *corev1.PodStatus
128+
var podStatus *corev1.PodStatus
130129
if len(workspacePods.Items) > 0 {
131-
scrubbedPodStatus = workspacePods.Items[0].Status.DeepCopy()
132-
if err = scrubber.Default.Struct(scrubbedPodStatus); err != nil {
133-
log.Error(err, "failed to scrub pod status")
134-
}
135-
}
136-
scrubbedStatus := workspace.Status.DeepCopy()
137-
if err = scrubber.Default.Struct(scrubbedStatus); err != nil {
138-
log.Error(err, "failed to scrub workspace status")
130+
podStatus = &workspacePods.Items[0].Status
139131
}
140132

141133
if !equality.Semantic.DeepDerivative(oldStatus, workspace.Status) {
142-
log.Info("updating workspace status", "status", scrubbedStatus, "podStatus", scrubbedPodStatus)
134+
log.Info("updating workspace status", "status", workspace.Status, "podStatus", podStatus)
143135
}
144136

145137
err = r.Status().Update(ctx, &workspace)

components/ws-manager-mk2/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ require (
6262
github.com/json-iterator/go v1.1.12 // indirect
6363
github.com/mailru/easyjson v0.7.7 // indirect
6464
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
65+
github.com/mitchellh/copystructure v1.2.0 // indirect
6566
github.com/mitchellh/reflectwalk v1.0.2 // indirect
6667
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
6768
github.com/modern-go/reflect2 v1.0.2 // indirect

components/ws-manager-mk2/go.sum

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/ws-manager-mk2/main.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222

2323
"github.com/bombsimon/logrusr/v4"
2424
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
25+
"github.com/mitchellh/copystructure"
2526
"github.com/prometheus/client_golang/prometheus"
2627
"k8s.io/apimachinery/pkg/runtime"
2728
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
@@ -43,6 +44,7 @@ import (
4344
config "github.com/gitpod-io/gitpod/ws-manager/api/config"
4445
workspacev1 "github.com/gitpod-io/gitpod/ws-manager/api/crd/v1"
4546

47+
"github.com/gitpod-io/gitpod/components/scrubber"
4648
"github.com/gitpod-io/gitpod/ws-manager-mk2/controllers"
4749
"github.com/gitpod-io/gitpod/ws-manager-mk2/pkg/maintenance"
4850
imgproxy "github.com/gitpod-io/gitpod/ws-manager-mk2/pkg/proxy"
@@ -77,7 +79,16 @@ func main() {
7779
flag.Parse()
7880

7981
log.Init(ServiceName, Version, jsonLog, verbose)
80-
baseLogger := logrusr.New(log.Log)
82+
baseLogger := logrusr.New(log.Log, logrusr.WithFormatter(func(i interface{}) interface{} {
83+
copied, err := copystructure.Copy(i)
84+
if err != nil {
85+
return "[error:failed to copy struct]"
86+
}
87+
if err = scrubber.Default.Struct(copied); err != nil {
88+
return "[error:failed to scrub]"
89+
}
90+
return copied
91+
}))
8192
ctrl.SetLogger(baseLogger)
8293
// Set the logger used by k8s (e.g. client-go).
8394
klog.SetLogger(baseLogger)

0 commit comments

Comments
 (0)