Require secrets for ProviderError redaction and omit unredactable bodies
Independent review Codex gpt-6-sol high: APPROVED (0 findings)
CI / ci (push) Successful in 1m28s
CI / ci (pull_request) Successful in 1m27s

NewProviderError now takes the secrets to redact as a required []string
instead of an optional variadic. When no non-empty secret is given the
body cannot be redacted, so no excerpt is stored and Body()/Error() never
expose raw vendor output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 15:56:32 -04:00
co-authored by Claude Opus 5.5
parent cb925618bc
commit 518e78db54
2 changed files with 36 additions and 11 deletions
+14 -6
View File
@@ -56,17 +56,24 @@ type ProviderError struct {
body string
}
// NewProviderError returns the error for an unexpected HTTP status. Every
// occurrence of each non-empty secret (the API key, at least) in body is
// replaced before the body is cut to MaxBodyExcerpt bytes, so no part of a
// secret survives.
func NewProviderError(status int, body []byte, secrets ...string) *ProviderError {
// NewProviderError returns the error for an unexpected HTTP status.
// secrets must hold the API key (and any other credential sent with the
// request). Every occurrence of each non-empty secret in body is replaced
// before the body is cut to MaxBodyExcerpt bytes, so no part of a secret
// survives. If secrets holds no non-empty value the body cannot be
// redacted, so no excerpt is kept at all.
func NewProviderError(status int, body []byte, secrets []string) *ProviderError {
s := string(body)
redactedAny := false
for _, secret := range secrets {
if secret != "" {
s = strings.ReplaceAll(s, secret, redacted)
redactedAny = true
}
}
if !redactedAny {
return &ProviderError{status: status}
}
s = strings.TrimSpace(s)
if len(s) > MaxBodyExcerpt {
cut := MaxBodyExcerpt
@@ -81,7 +88,8 @@ func NewProviderError(status int, body []byte, secrets ...string) *ProviderError
// Status returns the HTTP status code.
func (e *ProviderError) Status() int { return e.status }
// Body returns the redacted, truncated response-body excerpt.
// Body returns the redacted, truncated response-body excerpt; it is empty
// when the vendor sent no body or no secret was given to redact it with.
func (e *ProviderError) Body() string { return e.body }
func (e *ProviderError) Error() string {