@@ -19,6 +19,7 @@ import (
1919 "fmt"
2020
2121 "github.com/cockroachdb/errors/errbase"
22+ "github.com/cockroachdb/redact"
2223 "github.com/gogo/protobuf/proto"
2324)
2425
@@ -36,7 +37,7 @@ func Handled(err error) error {
3637 if err == nil {
3738 return nil
3839 }
39- return HandledWithMessage (err , err . Error ( ))
40+ return HandledWithSafeMessage (err , redact . Sprint ( err ))
4041}
4142
4243// HandledWithMessage is like Handled except the message is overridden.
@@ -46,7 +47,14 @@ func HandledWithMessage(err error, msg string) error {
4647 if err == nil {
4748 return nil
4849 }
49- return & barrierError {maskedErr : err , msg : msg }
50+ return HandledWithSafeMessage (err , redact .Sprint (msg ))
51+ }
52+
53+ // HandledWithSafeMessage is like Handled except the message is overridden.
54+ // This can be used e.g. to hide message details or to prevent
55+ // downstream code to make assertions on the message's contents.
56+ func HandledWithSafeMessage (err error , msg redact.RedactableString ) error {
57+ return & barrierErr {maskedErr : err , smsg : msg }
5058}
5159
5260// HandledWithMessagef is like HandledWithMessagef except the message
@@ -55,47 +63,48 @@ func HandledWithMessagef(err error, format string, args ...interface{}) error {
5563 if err == nil {
5664 return nil
5765 }
58- return & barrierError {maskedErr : err , msg : fmt .Sprintf (format , args ... )}
66+ return & barrierErr {maskedErr : err , smsg : redact .Sprintf (format , args ... )}
5967}
6068
61- // barrierError is a leaf error type. It encapsulates a chain of
69+ // barrierErr is a leaf error type. It encapsulates a chain of
6270// original causes, but these causes are hidden so that they inhibit
6371// matching via Is() and the Cause()/Unwrap() recursions.
64- type barrierError struct {
72+ type barrierErr struct {
6573 // Message for the barrier itself.
6674 // In the common case, the message from the masked error
6775 // is used as-is (see Handled() above) however it is
6876 // useful to cache it here since the masked error may
6977 // have a long chain of wrappers and its Error() call
7078 // may be expensive.
71- msg string
79+ smsg redact. RedactableString
7280 // Masked error chain.
7381 maskedErr error
7482}
7583
76- var _ error = (* barrierError )(nil )
77- var _ errbase.SafeDetailer = (* barrierError )(nil )
78- var _ errbase.SafeFormatter = (* barrierError )(nil )
79- var _ fmt.Formatter = (* barrierError )(nil )
84+ var _ error = (* barrierErr )(nil )
85+ var _ errbase.SafeDetailer = (* barrierErr )(nil )
86+ var _ errbase.SafeFormatter = (* barrierErr )(nil )
87+ var _ fmt.Formatter = (* barrierErr )(nil )
8088
81- // barrierError is an error.
82- func (e * barrierError ) Error () string { return e .msg }
89+ // barrierErr is an error.
90+ func (e * barrierErr ) Error () string { return e .smsg . StripMarkers () }
8391
8492// SafeDetails reports the PII-free details from the masked error.
85- func (e * barrierError ) SafeDetails () []string {
93+ func (e * barrierErr ) SafeDetails () []string {
8694 var details []string
8795 for err := e .maskedErr ; err != nil ; err = errbase .UnwrapOnce (err ) {
8896 sd := errbase .GetSafeDetails (err )
8997 details = sd .Fill (details )
9098 }
99+ details = append (details , redact .Sprintf ("masked error: %+v" , e .maskedErr ).Redact ().StripMarkers ())
91100 return details
92101}
93102
94103// Printing a barrier reveals the details.
95- func (e * barrierError ) Format (s fmt.State , verb rune ) { errbase .FormatError (e , s , verb ) }
104+ func (e * barrierErr ) Format (s fmt.State , verb rune ) { errbase .FormatError (e , s , verb ) }
96105
97- func (e * barrierError ) SafeFormatError (p errbase.Printer ) (next error ) {
98- p .Print (e .msg )
106+ func (e * barrierErr ) SafeFormatError (p errbase.Printer ) (next error ) {
107+ p .Print (e .smsg )
99108 if p .Detail () {
100109 p .Printf ("-- cause hidden behind barrier\n %+v" , e .maskedErr )
101110 }
@@ -106,19 +115,37 @@ func (e *barrierError) SafeFormatError(p errbase.Printer) (next error) {
106115func encodeBarrier (
107116 ctx context.Context , err error ,
108117) (msg string , details []string , payload proto.Message ) {
109- e := err .(* barrierError )
118+ e := err .(* barrierErr )
110119 enc := errbase .EncodeError (ctx , e .maskedErr )
111- return e . msg , e .SafeDetails (), & enc
120+ return string ( e . smsg ) , e .SafeDetails (), & enc
112121}
113122
114123// A barrier error is decoded exactly.
115124func decodeBarrier (ctx context.Context , msg string , _ []string , payload proto.Message ) error {
116125 enc := payload .(* errbase.EncodedError )
117- return & barrierError { msg : msg , maskedErr : errbase .DecodeError (ctx , * enc )}
126+ return & barrierErr { smsg : redact . RedactableString ( msg ) , maskedErr : errbase .DecodeError (ctx , * enc )}
118127}
119128
129+ // Previous versions of barrier errors.
130+ func decodeBarrierPrev (ctx context.Context , msg string , _ []string , payload proto.Message ) error {
131+ enc := payload .(* errbase.EncodedError )
132+ return & barrierErr {smsg : redact .Sprint (msg ), maskedErr : errbase .DecodeError (ctx , * enc )}
133+ }
134+
135+ // barrierError is the "old" type name of barrierErr. We use a new
136+ // name now to ensure a different decode function is used when
137+ // importing barriers from the previous structure, where the
138+ // message is not redactable.
139+ type barrierError struct {
140+ msg string
141+ maskedErr error
142+ }
143+
144+ func (b * barrierError ) Error () string { return "" }
145+
120146func init () {
121- tn := errbase .GetTypeKey ((* barrierError )(nil ))
147+ errbase .RegisterLeafDecoder (errbase .GetTypeKey ((* barrierError )(nil )), decodeBarrierPrev )
148+ tn := errbase .GetTypeKey ((* barrierErr )(nil ))
122149 errbase .RegisterLeafDecoder (tn , decodeBarrier )
123150 errbase .RegisterLeafEncoder (tn , encodeBarrier )
124151}
0 commit comments