Skip to content

Commit 676eef5

Browse files
authored
Merge pull request #94 from knz/20220304-barrier-details
2 parents 7261bff + feb9d32 commit 676eef5

18 files changed

+10912
-4227
lines changed

barriers/barriers.go

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -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) {
106115
func 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.
115124
func 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+
120146
func 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
}

barriers/barriers_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ woo
118118
| woo
119119
| (1) woo
120120
| Error types: (1) *errors.errorString
121-
Error types: (1) *barriers.barrierError`},
121+
Error types: (1) *barriers.barrierErr`},
122122

123123
{"handled + handled", barriers.Handled(barriers.Handled(goErr.New("woo"))), woo, `
124124
woo
@@ -130,8 +130,8 @@ woo
130130
| | woo
131131
| | (1) woo
132132
| | Error types: (1) *errors.errorString
133-
| Error types: (1) *barriers.barrierError
134-
Error types: (1) *barriers.barrierError`},
133+
| Error types: (1) *barriers.barrierErr
134+
Error types: (1) *barriers.barrierErr`},
135135

136136
{"handledmsg", barriers.HandledWithMessage(goErr.New("woo"), "waa"), "waa", `
137137
waa
@@ -140,7 +140,7 @@ waa
140140
| woo
141141
| (1) woo
142142
| Error types: (1) *errors.errorString
143-
Error types: (1) *barriers.barrierError`},
143+
Error types: (1) *barriers.barrierErr`},
144144

145145
{"handledmsg + handledmsg", barriers.HandledWithMessage(
146146
barriers.HandledWithMessage(
@@ -154,8 +154,8 @@ wuu
154154
| | woo
155155
| | (1) woo
156156
| | Error types: (1) *errors.errorString
157-
| Error types: (1) *barriers.barrierError
158-
Error types: (1) *barriers.barrierError`},
157+
| Error types: (1) *barriers.barrierErr
158+
Error types: (1) *barriers.barrierErr`},
159159

160160
{"handled + wrapper",
161161
barriers.Handled(
@@ -172,7 +172,7 @@ waa: woo
172172
| | multi-line wrapper payload
173173
| Wraps: (2) woo
174174
| Error types: (1) *barriers_test.werrFmt (2) *errors.errorString
175-
Error types: (1) *barriers.barrierError`},
175+
Error types: (1) *barriers.barrierErr`},
176176
}
177177

178178
for _, test := range testCases {

errutil/message_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ Wraps: (4) wuu: woo
124124
| | multi-line payload
125125
| Wraps: (2) woo
126126
| Error types: (1) *errutil_test.werrFmt (2) *errors.errorString
127-
Error types: (1) *assert.withAssertionFailure (2) *withstack.withStack (3) *errutil.withPrefix (4) *barriers.barrierError`,
127+
Error types: (1) *assert.withAssertionFailure (2) *withstack.withStack (3) *errutil.withPrefix (4) *barriers.barrierErr`,
128128
},
129129

130130
{"assert + wrap empty",
@@ -148,7 +148,7 @@ Wraps: (3) wuu: woo
148148
| | multi-line payload
149149
| Wraps: (2) woo
150150
| Error types: (1) *errutil_test.werrFmt (2) *errors.errorString
151-
Error types: (1) *assert.withAssertionFailure (2) *withstack.withStack (3) *barriers.barrierError`,
151+
Error types: (1) *assert.withAssertionFailure (2) *withstack.withStack (3) *barriers.barrierErr`,
152152
},
153153

154154
{"assert + wrap empty+arg",
@@ -173,7 +173,7 @@ Wraps: (4) wuu: woo
173173
| | multi-line payload
174174
| Wraps: (2) woo
175175
| Error types: (1) *errutil_test.werrFmt (2) *errors.errorString
176-
Error types: (1) *assert.withAssertionFailure (2) *withstack.withStack (3) *errutil.withPrefix (4) *barriers.barrierError`,
176+
Error types: (1) *assert.withAssertionFailure (2) *withstack.withStack (3) *errutil.withPrefix (4) *barriers.barrierErr`,
177177
},
178178
}
179179

0 commit comments

Comments
 (0)