* Add TargetNotFoundError for targeted scan targets missing from the source * Check download response status in exact-path retry
96 lines
2.2 KiB
Go
96 lines
2.2 KiB
Go
package sources
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
// ScanErrors is used to collect errors encountered while scanning.
|
|
// It ensures that errors are collected in a thread-safe manner.
|
|
type ScanErrors struct {
|
|
mu sync.RWMutex
|
|
errors []error
|
|
}
|
|
|
|
// NewScanErrors creates a new thread safe error collector.
|
|
func NewScanErrors() *ScanErrors {
|
|
return &ScanErrors{errors: make([]error, 0)}
|
|
}
|
|
|
|
// Add an error to the collection in a thread-safe manner.
|
|
func (s *ScanErrors) Add(err error) {
|
|
if err == nil {
|
|
return
|
|
}
|
|
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
s.errors = append(s.errors, err)
|
|
}
|
|
|
|
// Count returns the number of errors collected.
|
|
func (s *ScanErrors) Count() uint64 {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
return uint64(len(s.errors))
|
|
}
|
|
|
|
func (s *ScanErrors) String() string {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
|
|
var sb strings.Builder
|
|
sb.WriteString("[")
|
|
for i, err := range s.errors {
|
|
sb.WriteString(`"` + err.Error() + `"`)
|
|
if i < len(s.errors)-1 {
|
|
sb.WriteString(", ")
|
|
}
|
|
}
|
|
sb.WriteString("]")
|
|
return sb.String()
|
|
}
|
|
|
|
func (s *ScanErrors) Errors() error {
|
|
s.mu.RLock()
|
|
defer s.mu.RUnlock()
|
|
return errors.Join(s.errors...)
|
|
}
|
|
|
|
// TargetedScanError is an error with a secret ID attached. Collections of them can be returned by targeted scans that
|
|
// scan multiple targets in order to associate individual errors with individual scan targets.
|
|
type TargetedScanError struct {
|
|
Err error
|
|
SecretID int64
|
|
}
|
|
|
|
var _ error = (*TargetedScanError)(nil)
|
|
|
|
func (t TargetedScanError) Error() string {
|
|
return t.Err.Error()
|
|
}
|
|
|
|
func (t TargetedScanError) Unwrap() error {
|
|
return t.Err
|
|
}
|
|
|
|
// TargetNotFoundError indicates a targeted scan failed because the requested
|
|
// target is definitively absent from the source (e.g. the file, commit, or
|
|
// message it pointed to was deleted), as opposed to inaccessible due to
|
|
// authorization or transient failures. Consumers can treat this as terminal:
|
|
// retrying cannot succeed until a fresh scan updates the stored location.
|
|
type TargetNotFoundError struct {
|
|
Err error
|
|
}
|
|
|
|
var _ error = (*TargetNotFoundError)(nil)
|
|
|
|
func (t TargetNotFoundError) Error() string {
|
|
return t.Err.Error()
|
|
}
|
|
|
|
func (t TargetNotFoundError) Unwrap() error {
|
|
return t.Err
|
|
}
|