sourcegraph/lib/errors/cockroach.go
Robert Lin ba29f2da26
lib/errors: document redaction, upgrade error deps (#53109)
Did you know: all args to `errors.Newf`, `errors.Wrapf`, etc are
considered sensitive, and redacted before errors are reported to Sentry?
That's where all the error reports that look useless come from:

```
x
x
x
x
x
```

This change documents how this works based on cockroachdb error docs,
and also registers a set of arg types that can automatically be
considered safe based on what is configured in cockroachdb itself
(basically most primitive types except string, such as ints for status
codes and whatnot).

Aside: PII is important to consider as we build out multi-tenant
services like Cody Gateway, and important if we want to consider using
nice third-party tools like Honeycomb/Sentry for Cloud instances in the
future.

Related: https://github.com/sourcegraph/sourcegraph/issues/51998

## Test plan


CI
2023-06-09 08:39:40 -07:00

113 lines
3.4 KiB
Go

package errors
import (
"fmt"
"os"
"reflect"
"time"
"github.com/cockroachdb/errors" //nolint:depguard
"github.com/cockroachdb/redact"
)
func init() {
registerCockroachSafeTypes()
}
var (
// Safe is a arg marker for non-PII arguments.
Safe = redact.Safe
New = errors.New
// Newf assumes all args are unsafe PII, except for types in registerCockroachSafeTypes.
// Use Safe to mark non-PII args. Contents of format are retained.
Newf = errors.Newf
// Errorf is the same as Newf. It assumes all args are unsafe PII, except for types
// in registerCockroachSafeTypes. Use Safe to mark non-PII args. Contents of format
// are retained.
Errorf = errors.Newf
Wrap = errors.Wrap
// Wrapf assumes all args are unsafe PII, except for types in registerCockroachSafeTypes.
// Use Safe to mark non-PII args. Contents of format are retained.
Wrapf = errors.Wrapf
// WithMessage is the same as Wrap.
WithMessage = errors.Wrap
// WithStack annotates err with a stack trace at the point WithStack was
// called. Useful for sentinel errors.
WithStack = errors.WithStack
Is = errors.Is
IsAny = errors.IsAny
As = errors.As
HasType = errors.HasType
Cause = errors.Cause
Unwrap = errors.Unwrap
UnwrapAll = errors.UnwrapAll
BuildSentryReport = errors.BuildSentryReport
)
// Extend multiError to work with cockroachdb errors. Implement here to keep imports in
// one place.
var _ fmt.Formatter = (*multiError)(nil)
func (e *multiError) Format(s fmt.State, verb rune) { errors.FormatError(e, s, verb) }
var _ errors.Formatter = (*multiError)(nil)
func (e *multiError) FormatError(p errors.Printer) error {
if len(e.errs) > 1 {
p.Printf("%d errors occurred:", len(e.errs))
}
// Simple output
for _, err := range e.errs {
if len(e.errs) > 1 {
p.Print("\n\t* ")
}
p.Printf("%v", err)
}
// Print additional details
if p.Detail() {
p.Print("-- details follow")
for i, err := range e.errs {
p.Printf("\n(%d) %+v", i+1, err)
}
}
return nil
}
// registerSafeTypes registers types that should not be considered PII by
// cockroachdb/errors.
//
// Sourced from https://sourcegraph.com/github.com/cockroachdb/cockroach/-/blob/pkg/util/log/redact.go?L141
func registerCockroachSafeTypes() {
// We consider booleans and numeric values to be always safe for
// reporting. A log call can opt out by using redact.Unsafe() around
// a value that would be otherwise considered safe.
redact.RegisterSafeType(reflect.TypeOf(true)) // bool
redact.RegisterSafeType(reflect.TypeOf(123)) // int
redact.RegisterSafeType(reflect.TypeOf(int8(0)))
redact.RegisterSafeType(reflect.TypeOf(int16(0)))
redact.RegisterSafeType(reflect.TypeOf(int32(0)))
redact.RegisterSafeType(reflect.TypeOf(int64(0)))
redact.RegisterSafeType(reflect.TypeOf(uint8(0)))
redact.RegisterSafeType(reflect.TypeOf(uint16(0)))
redact.RegisterSafeType(reflect.TypeOf(uint32(0)))
redact.RegisterSafeType(reflect.TypeOf(uint64(0)))
redact.RegisterSafeType(reflect.TypeOf(float32(0)))
redact.RegisterSafeType(reflect.TypeOf(float64(0)))
redact.RegisterSafeType(reflect.TypeOf(complex64(0)))
redact.RegisterSafeType(reflect.TypeOf(complex128(0)))
// Signal names are also safe for reporting.
redact.RegisterSafeType(reflect.TypeOf(os.Interrupt))
// Times and durations too.
redact.RegisterSafeType(reflect.TypeOf(time.Time{}))
redact.RegisterSafeType(reflect.TypeOf(time.Duration(0)))
}