Skip to content

Commit e3879ba

Browse files
committed
test(fanal): add regression test for surfacing analyzer errors
Verify that Inspect surfaces a fatal analyzer error (*types.UserError, e.g. a remote Maven 429) instead of the context.Canceled the file walk hits after errgroup cancels egCtx. Regression test for aquasecurity#10790.
1 parent 6c81fe2 commit e3879ba

1 file changed

Lines changed: 41 additions & 0 deletions

File tree

pkg/fanal/artifact/local/fs_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package local
22

33
import (
4+
"context"
5+
"fmt"
46
"os"
57
"path/filepath"
8+
"strings"
69
"testing"
710

811
"github.com/stretchr/testify/assert"
@@ -15,6 +18,7 @@ import (
1518
"github.com/aquasecurity/trivy/pkg/fanal/types"
1619
"github.com/aquasecurity/trivy/pkg/fanal/walker"
1720
"github.com/aquasecurity/trivy/pkg/misconf"
21+
trivytypes "github.com/aquasecurity/trivy/pkg/types"
1822
"github.com/aquasecurity/trivy/pkg/uuid"
1923

2024
_ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/all"
@@ -2663,3 +2667,40 @@ func Test_sanitizeRemoteURL(t *testing.T) {
26632667
})
26642668
}
26652669
}
2670+
2671+
// userErrorAnalyzer fails every matching file with a *types.UserError,
2672+
// emulating a fatal analyzer error such as a remote Maven 429.
2673+
type userErrorAnalyzer struct{}
2674+
2675+
func (userErrorAnalyzer) Type() analyzer.Type { return "user-error-test" }
2676+
func (userErrorAnalyzer) Version() int { return 1 }
2677+
func (userErrorAnalyzer) Required(filePath string, _ os.FileInfo) bool {
2678+
return strings.HasSuffix(filePath, ".usererror")
2679+
}
2680+
2681+
func (userErrorAnalyzer) Analyze(_ context.Context, _ analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) {
2682+
return nil, &trivytypes.UserError{Message: "429 Too Many Requests"}
2683+
}
2684+
2685+
// TestArtifact_Inspect_AnalyzeErrorNotMasked is a regression test for #10790:
2686+
// a fatal analyzer error (a remote Maven 429, as *types.UserError) must be
2687+
// surfaced, not masked by the context.Canceled the walk hits after egCtx cancels.
2688+
func TestArtifact_Inspect_AnalyzeErrorNotMasked(t *testing.T) {
2689+
dir := t.TempDir()
2690+
// Parallel=1 with several files: the first file cancels egCtx, so a later
2691+
// file's semaphore acquire fails with context.Canceled.
2692+
for i := 0; i < 10; i++ {
2693+
require.NoError(t, os.WriteFile(
2694+
filepath.Join(dir, fmt.Sprintf("%d.usererror", i)), []byte("x"), 0o600))
2695+
}
2696+
2697+
analyzer.RegisterAnalyzer(userErrorAnalyzer{})
2698+
t.Cleanup(func() { analyzer.DeregisterAnalyzer("user-error-test") })
2699+
2700+
a, err := NewArtifact(dir, cache.NewMemoryCache(), walker.NewFS(), artifact.Option{Parallel: 1})
2701+
require.NoError(t, err)
2702+
2703+
_, err = a.Inspect(t.Context())
2704+
require.Error(t, err)
2705+
assert.ErrorContains(t, err, "429 Too Many Requests")
2706+
}

0 commit comments

Comments
 (0)