mirror of
https://github.com/anchore/syft.git
synced 2026-10-11 21:57:22 +02:00
* 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>
64 lines
1.8 KiB
Go
64 lines
1.8 KiB
Go
package task
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"runtime/debug"
|
|
"slices"
|
|
"time"
|
|
|
|
"github.com/anchore/syft/internal/log"
|
|
"github.com/anchore/syft/internal/sbomsync"
|
|
"github.com/anchore/syft/internal/unknown"
|
|
"github.com/anchore/syft/syft/event/monitor"
|
|
"github.com/anchore/syft/syft/file"
|
|
"github.com/anchore/syft/syft/sbom"
|
|
)
|
|
|
|
func RunTask(ctx context.Context, tsk Task, resolver file.Resolver, s sbomsync.Builder, prog *monitor.TaskProgress) error {
|
|
err := runTaskSafely(ctx, tsk, resolver, s)
|
|
unknowns, remainingErrors := unknown.ExtractCoordinateErrors(err)
|
|
if len(unknowns) > 0 {
|
|
appendUnknowns(s, tsk.Name(), unknowns)
|
|
}
|
|
if remainingErrors != nil {
|
|
prog.SetError(remainingErrors)
|
|
}
|
|
prog.Increment()
|
|
return remainingErrors
|
|
}
|
|
|
|
func appendUnknowns(builder sbomsync.Builder, taskName string, unknowns []unknown.CoordinateError) {
|
|
if accessor, ok := builder.(sbomsync.Accessor); ok {
|
|
accessor.WriteToSBOM(func(sb *sbom.SBOM) {
|
|
for _, u := range unknowns {
|
|
if sb.Artifacts.Unknowns == nil {
|
|
sb.Artifacts.Unknowns = map[file.Coordinates][]string{}
|
|
}
|
|
unknownText := formatUnknown(u.Reason.Error(), taskName)
|
|
existing := sb.Artifacts.Unknowns[u.Coordinates]
|
|
// don't include duplicate unknowns
|
|
if slices.Contains(existing, unknownText) {
|
|
continue
|
|
}
|
|
sb.Artifacts.Unknowns[u.Coordinates] = append(existing, unknownText)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func runTaskSafely(ctx context.Context, t Task, resolver file.Resolver, s sbomsync.Builder) (err error) {
|
|
// handle individual cataloger panics
|
|
defer func() {
|
|
if e := recover(); e != nil {
|
|
log.WithFields("task", t.Name()).Debugf("task panic stack:\n%s", debug.Stack())
|
|
err = fmt.Errorf("panic in task %q: %v", t.Name(), e)
|
|
}
|
|
}()
|
|
|
|
start := time.Now()
|
|
res := t.Execute(ctx, resolver, s)
|
|
log.WithFields("task", t.Name(), "elapsed", time.Since(start)).Info("task completed")
|
|
return res
|
|
}
|