fix: don't fail the whole SBOM when a cataloger panics on one file (#5342)

* fix(generic): recover from parser and processor panics

- a panic while parsing one file becomes an unknown for that location instead of failing the whole SBOM
- a panic in a package processor is logged as a warning and the unprocessed results are kept
- stacks go to the trace log, not into the unknown text

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* fix(unknown): keep errors that unwrap to nil

`sync.PanicError` with a non-error panic value (e.g. `panic("boom")`) unwraps to nil, and was being dropped entirely from the error graph instead of being kept as a leaf.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* fix(task): don't put the stack trace in task panic errors

Task panics are still fatal, but the error now reads `panic in task "<name>": <value>` and the stack goes to the debug log.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* test(generic): cover chained processors when a later one panics

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

* fix(file): recover from panics in the executable and file digest catalogers

A panic while reading one file is now recorded as an unknown for that file instead of failing the whole SBOM, the same as generic catalogers.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

---------

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
Alex Goodman
2026-09-29 09:21:03 -04:00
committed by GitHub
parent f7f3c6efc3
commit 10af8342c0
10 changed files with 261 additions and 12 deletions
+4
View File
@@ -183,6 +183,10 @@ func visitErrors(err error, fn func(error) error) error {
// unwrap singly wrapped errors
if e, ok := err.(interface{ Unwrap() error }); ok {
wrapped := e.Unwrap()
if wrapped == nil {
// nothing is wrapped (e.g. a sync.PanicError with a non-error value), so this is a leaf
return fn(err)
}
got := visitErrors(wrapped, fn)
if got == nil {
return nil
@@ -8,6 +8,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/anchore/go-sync"
"github.com/anchore/syft/syft/file"
)
@@ -234,3 +235,11 @@ func Test_Append(t *testing.T) {
e3 = Appendf(e2, file.NewLocation("l3"), "%s", "e3")
require.Equal(t, "l1: e1\nl3: e3", e3.Error())
}
func Test_ExtractCoordinateErrors_keepsNilUnwrap(t *testing.T) {
// sync.PanicError unwraps to nil when the panic value is not an error
err := sync.PanicError{Value: "x"}
unknowns, remaining := ExtractCoordinateErrors(err)
require.Empty(t, unknowns)
require.Equal(t, err, remaining)
}