Skip to content

Commit aeaebdd

Browse files
authored
[refactor] - Add DataOrErr (#3520)
* adjust error handling to make more explicit * Add DataOrErr * update * fix apk handler to use DataOrErr * fix * fix tests * remove timeout as it wont ever be used
1 parent af3e682 commit aeaebdd

14 files changed

+310
-150
lines changed

pkg/engine/engine_test.go

+5-6
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,16 @@ import (
1313

1414
"github.com/stretchr/testify/assert"
1515

16-
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/gitlab/v2"
17-
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
18-
1916
"github.com/trufflesecurity/trufflehog/v3/pkg/config"
2017
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
2118
"github.com/trufflesecurity/trufflehog/v3/pkg/custom_detectors"
2219
"github.com/trufflesecurity/trufflehog/v3/pkg/decoders"
2320
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
21+
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors/gitlab/v2"
2422
"github.com/trufflesecurity/trufflehog/v3/pkg/engine/ahocorasick"
2523
"github.com/trufflesecurity/trufflehog/v3/pkg/engine/defaults"
2624
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/custom_detectorspb"
25+
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
2726
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/source_metadatapb"
2827
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb"
2928
"github.com/trufflesecurity/trufflehog/v3/pkg/sources"
@@ -317,8 +316,8 @@ aws_secret_access_key = 5dkLVuqpZhD6V3Zym1hivdSHOzh6FGPjwplXD+5f`,
317316
{
318317
name: "secret with mixed whitespace before",
319318
content: `first line
320-
321-
319+
320+
322321
AKIA2OGYBAH6STMMNXNN
323322
aws_secret_access_key = 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`,
324323
expectedLine: 4,
@@ -1248,7 +1247,7 @@ def test_something():
12481247
conf := Config{
12491248
Concurrency: 1,
12501249
Decoders: decoders.DefaultDecoders(),
1251-
Detectors: DefaultDetectors(),
1250+
Detectors: defaults.DefaultDetectors(),
12521251
Verify: false,
12531252
SourceManager: sourceManager,
12541253
Dispatcher: NewPrinterDispatcher(new(discardPrinter)),

pkg/handlers/apk.go

+19-24
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ import (
1212
"strings"
1313
"time"
1414

15+
"github.com/avast/apkparser"
1516
dextk "github.com/csnewman/dextk"
1617

17-
"github.com/avast/apkparser"
1818
logContext "github.com/trufflesecurity/trufflehog/v3/pkg/context"
1919
"github.com/trufflesecurity/trufflehog/v3/pkg/engine/defaults"
2020
"github.com/trufflesecurity/trufflehog/v3/pkg/iobuf"
@@ -66,45 +66,40 @@ func newAPKHandler() *apkHandler {
6666
}
6767

6868
// HandleFile processes apk formatted files.
69-
func (h *apkHandler) HandleFile(ctx logContext.Context, input fileReader) (chan []byte, error) {
70-
apkChan := make(chan []byte, defaultBufferSize)
69+
func (h *apkHandler) HandleFile(ctx logContext.Context, input fileReader) chan DataOrErr {
70+
apkChan := make(chan DataOrErr, defaultBufferSize)
7171

7272
go func() {
73-
ctx, cancel := logContext.WithTimeout(ctx, maxTimeout)
74-
defer cancel()
7573
defer close(apkChan)
7674

77-
// Update the metrics for the file processing.
78-
start := time.Now()
79-
var err error
80-
defer func() {
81-
h.measureLatencyAndHandleErrors(start, err)
82-
h.metrics.incFilesProcessed()
83-
}()
84-
8575
// Defer a panic recovery to handle any panics that occur during the APK processing.
8676
defer func() {
8777
if r := recover(); r != nil {
8878
// Return the panic as an error.
79+
var panicErr error
8980
if e, ok := r.(error); ok {
90-
err = e
81+
panicErr = e
9182
} else {
92-
err = fmt.Errorf("panic occurred: %v", r)
83+
panicErr = fmt.Errorf("panic occurred: %v", r)
9384
}
94-
ctx.Logger().Error(err, "Panic occurred when reading apk archive")
85+
ctx.Logger().Error(panicErr, "Panic occurred when reading apk archive")
9586
}
9687
}()
9788

98-
if err = h.processAPK(ctx, input, apkChan); err != nil {
99-
ctx.Logger().Error(err, "error processing apk content")
89+
start := time.Now()
90+
err := h.processAPK(ctx, input, apkChan)
91+
if err == nil {
92+
h.metrics.incFilesProcessed()
10093
}
94+
95+
h.measureLatencyAndHandleErrors(ctx, start, err, apkChan)
10196
}()
102-
return apkChan, nil
97+
98+
return apkChan
10399
}
104100

105101
// processAPK processes the apk file and sends the extracted data to the provided channel.
106-
func (h *apkHandler) processAPK(ctx logContext.Context, input fileReader, apkChan chan []byte) error {
107-
102+
func (h *apkHandler) processAPK(ctx logContext.Context, input fileReader, apkChan chan DataOrErr) error {
108103
// Create a ZIP reader from the input fileReader
109104
zipReader, err := createZipReader(input)
110105
if err != nil {
@@ -132,7 +127,7 @@ func (h *apkHandler) processAPK(ctx logContext.Context, input fileReader, apkCha
132127
}
133128

134129
// processResources processes the resources.arsc file and sends the extracted data to the provided channel.
135-
func (h *apkHandler) processResources(ctx logContext.Context, resTable *apkparser.ResourceTable, apkChan chan []byte) error {
130+
func (h *apkHandler) processResources(ctx logContext.Context, resTable *apkparser.ResourceTable, apkChan chan DataOrErr) error {
136131
if resTable == nil {
137132
return errors.New("ResourceTable is nil")
138133
}
@@ -144,7 +139,7 @@ func (h *apkHandler) processResources(ctx logContext.Context, resTable *apkparse
144139
}
145140

146141
// processFile processes the file and sends the extracted data to the provided channel.
147-
func (h *apkHandler) processFile(ctx logContext.Context, file *zip.File, resTable *apkparser.ResourceTable, apkChan chan []byte) error {
142+
func (h *apkHandler) processFile(ctx logContext.Context, file *zip.File, resTable *apkparser.ResourceTable, apkChan chan DataOrErr) error {
148143
// check if the file is empty
149144
if file.UncompressedSize64 == 0 {
150145
return nil
@@ -177,7 +172,7 @@ func (h *apkHandler) processFile(ctx logContext.Context, file *zip.File, resTabl
177172
}
178173

179174
// handleAPKFileContent sends the extracted data to the provided channel via the handleNonArchiveContent function.
180-
func (h *apkHandler) handleAPKFileContent(ctx logContext.Context, rdr io.Reader, fileName string, apkChan chan []byte) error {
175+
func (h *apkHandler) handleAPKFileContent(ctx logContext.Context, rdr io.Reader, fileName string, apkChan chan DataOrErr) error {
181176
mimeReader, err := newMimeTypeReader(rdr)
182177
if err != nil {
183178
return fmt.Errorf("failed to create mimeTypeReader for file %s: %w", fileName, err)

pkg/handlers/apk_test.go

+4-10
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ func TestAPKHandler(t *testing.T) {
1919
expectedChunks int
2020
expectedSecrets int
2121
matchString string
22-
expectErr bool
2322
}{
2423
"apk_with_3_leaked_keys": {
2524
"https://github.com/joeleonjr/leakyAPK/raw/refs/heads/main/aws_leak.apk",
@@ -28,7 +27,6 @@ func TestAPKHandler(t *testing.T) {
2827
// we're just looking for a string match. There is one extra string match in the APK (but only 3 detected secrets).
2928
4,
3029
"AKIA2UC3BSXMLSCLTUUS",
31-
false,
3230
},
3331
}
3432

@@ -47,19 +45,15 @@ func TestAPKHandler(t *testing.T) {
4745
}
4846
defer newReader.Close()
4947

50-
archiveChan, err := handler.HandleFile(logContext.Background(), newReader)
51-
if testCase.expectErr {
52-
assert.NoError(t, err)
53-
return
54-
}
48+
archiveChan := handler.HandleFile(logContext.Background(), newReader)
5549

5650
chunkCount := 0
5751
secretCount := 0
5852
re := regexp.MustCompile(testCase.matchString)
5953
matched := false
6054
for chunk := range archiveChan {
6155
chunkCount++
62-
if re.Match(chunk) {
56+
if re.Match(chunk.Data) {
6357
secretCount++
6458
matched = true
6559
}
@@ -82,7 +76,7 @@ func TestOpenInvalidAPK(t *testing.T) {
8276
assert.NoError(t, err)
8377
defer rdr.Close()
8478

85-
archiveChan := make(chan []byte)
79+
archiveChan := make(chan DataOrErr)
8680

8781
err = handler.processAPK(ctx, rdr, archiveChan)
8882
assert.Contains(t, err.Error(), "zip: not a valid zip file")
@@ -106,7 +100,7 @@ func TestOpenValidZipInvalidAPK(t *testing.T) {
106100
assert.NoError(t, err)
107101
defer newReader.Close()
108102

109-
archiveChan := make(chan []byte)
103+
archiveChan := make(chan DataOrErr)
110104
ctx := logContext.AddLogger(context.Background())
111105

112106
err = handler.processAPK(ctx, newReader, archiveChan)

pkg/handlers/ar.go

+10-10
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,16 @@ func newARHandler() *arHandler {
2222

2323
// HandleFile processes AR formatted files. This function needs to be implemented to extract or
2424
// manage data from AR files according to specific requirements.
25-
func (h *arHandler) HandleFile(ctx logContext.Context, input fileReader) (chan []byte, error) {
26-
archiveChan := make(chan []byte, defaultBufferSize)
25+
func (h *arHandler) HandleFile(ctx logContext.Context, input fileReader) chan DataOrErr {
26+
dataOrErrChan := make(chan DataOrErr, defaultBufferSize)
2727

2828
if feature.ForceSkipArchives.Load() {
29-
close(archiveChan)
30-
return archiveChan, nil
29+
close(dataOrErrChan)
30+
return dataOrErrChan
3131
}
3232

3333
go func() {
34-
defer close(archiveChan)
34+
defer close(dataOrErrChan)
3535

3636
// Defer a panic recovery to handle any panics that occur during the AR processing.
3737
defer func() {
@@ -53,19 +53,19 @@ func (h *arHandler) HandleFile(ctx logContext.Context, input fileReader) (chan [
5353
return
5454
}
5555

56-
err = h.processARFiles(ctx, arReader, archiveChan)
56+
err = h.processARFiles(ctx, arReader, dataOrErrChan)
5757
if err == nil {
5858
h.metrics.incFilesProcessed()
5959
}
6060

6161
// Update the metrics for the file processing and handle any errors.
62-
h.measureLatencyAndHandleErrors(start, err)
62+
h.measureLatencyAndHandleErrors(ctx, start, err, dataOrErrChan)
6363
}()
6464

65-
return archiveChan, nil
65+
return dataOrErrChan
6666
}
6767

68-
func (h *arHandler) processARFiles(ctx logContext.Context, reader *deb.Ar, archiveChan chan []byte) error {
68+
func (h *arHandler) processARFiles(ctx logContext.Context, reader *deb.Ar, dataOrErrChan chan DataOrErr) error {
6969
for {
7070
select {
7171
case <-ctx.Done():
@@ -88,7 +88,7 @@ func (h *arHandler) processARFiles(ctx logContext.Context, reader *deb.Ar, archi
8888
return fmt.Errorf("error creating mime-type reader: %w", err)
8989
}
9090

91-
if err := h.handleNonArchiveContent(fileCtx, rdr, archiveChan); err != nil {
91+
if err := h.handleNonArchiveContent(fileCtx, rdr, dataOrErrChan); err != nil {
9292
fileCtx.Logger().Error(err, "error handling archive content in AR")
9393
h.metrics.incErrors()
9494
}

pkg/handlers/ar_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ func TestHandleARFile(t *testing.T) {
2323
defer rdr.Close()
2424

2525
handler := newARHandler()
26-
archiveChan, err := handler.HandleFile(context.AddLogger(ctx), rdr)
26+
dataOrErrChan := handler.HandleFile(context.AddLogger(ctx), rdr)
2727
assert.NoError(t, err)
2828

2929
wantChunkCount := 102
3030
count := 0
31-
for range archiveChan {
31+
for range dataOrErrChan {
3232
count++
3333
}
3434

pkg/handlers/archive.go

+19-14
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,16 @@ func newArchiveHandler() *archiveHandler {
4444
// utilizing a single output channel. It first tries to identify the input as an archive. If it is an archive,
4545
// it processes it accordingly; otherwise, it handles the input as non-archive content.
4646
// The function returns a channel that will receive the extracted data bytes and an error if the initial setup fails.
47-
func (h *archiveHandler) HandleFile(ctx logContext.Context, input fileReader) (chan []byte, error) {
48-
dataChan := make(chan []byte, defaultBufferSize)
47+
func (h *archiveHandler) HandleFile(ctx logContext.Context, input fileReader) chan DataOrErr {
48+
dataOrErrChan := make(chan DataOrErr, defaultBufferSize)
4949

5050
if feature.ForceSkipArchives.Load() {
51-
close(dataChan)
52-
return dataChan, nil
51+
close(dataOrErrChan)
52+
return dataOrErrChan
5353
}
5454

5555
go func() {
56-
defer close(dataChan)
56+
defer close(dataOrErrChan)
5757

5858
// The underlying 7zip library may panic when attempting to open an archive.
5959
// This is due to an Index Out Of Range (IOOR) error when reading the archive header.
@@ -71,16 +71,16 @@ func (h *archiveHandler) HandleFile(ctx logContext.Context, input fileReader) (c
7171
}()
7272

7373
start := time.Now()
74-
err := h.openArchive(ctx, 0, input, dataChan)
74+
err := h.openArchive(ctx, 0, input, dataOrErrChan)
7575
if err == nil {
7676
h.metrics.incFilesProcessed()
7777
}
7878

7979
// Update the metrics for the file processing and handle any errors.
80-
h.measureLatencyAndHandleErrors(start, err)
80+
h.measureLatencyAndHandleErrors(ctx, start, err, dataOrErrChan)
8181
}()
8282

83-
return dataChan, nil
83+
return dataOrErrChan
8484
}
8585

8686
var ErrMaxDepthReached = errors.New("max archive depth reached")
@@ -89,7 +89,12 @@ var ErrMaxDepthReached = errors.New("max archive depth reached")
8989
// It takes a reader from which it attempts to identify and process the archive format. Depending on the archive type,
9090
// it either decompresses or extracts the contents directly, sending data to the provided channel.
9191
// Returns an error if the archive cannot be processed due to issues like exceeding maximum depth or unsupported formats.
92-
func (h *archiveHandler) openArchive(ctx logContext.Context, depth int, reader fileReader, archiveChan chan []byte) error {
92+
func (h *archiveHandler) openArchive(
93+
ctx logContext.Context,
94+
depth int,
95+
reader fileReader,
96+
dataOrErrChan chan DataOrErr,
97+
) error {
9398
ctx.Logger().V(4).Info("Starting archive processing", "depth", depth)
9499
defer ctx.Logger().V(4).Info("Finished archive processing", "depth", depth)
95100

@@ -104,7 +109,7 @@ func (h *archiveHandler) openArchive(ctx logContext.Context, depth int, reader f
104109

105110
if reader.format == nil {
106111
if depth > 0 {
107-
return h.handleNonArchiveContent(ctx, newMimeTypeReaderFromFileReader(reader), archiveChan)
112+
return h.handleNonArchiveContent(ctx, newMimeTypeReaderFromFileReader(reader), dataOrErrChan)
108113
}
109114
return fmt.Errorf("unknown archive format")
110115
}
@@ -132,9 +137,9 @@ func (h *archiveHandler) openArchive(ctx logContext.Context, depth int, reader f
132137
}
133138
defer rdr.Close()
134139

135-
return h.openArchive(ctx, depth+1, rdr, archiveChan)
140+
return h.openArchive(ctx, depth+1, rdr, dataOrErrChan)
136141
case archiver.Extractor:
137-
err := archive.Extract(logContext.WithValue(ctx, depthKey, depth+1), reader, nil, h.extractorHandler(archiveChan))
142+
err := archive.Extract(logContext.WithValue(ctx, depthKey, depth+1), reader, nil, h.extractorHandler(dataOrErrChan))
138143
if err != nil {
139144
return fmt.Errorf("error extracting archive with format: %s: %w", reader.format.Name(), err)
140145
}
@@ -148,7 +153,7 @@ func (h *archiveHandler) openArchive(ctx logContext.Context, depth int, reader f
148153
// It logs the extraction, checks for cancellation, and decides whether to skip the file based on its name or type,
149154
// particularly for binary files if configured to skip. If the file is not skipped, it recursively calls openArchive
150155
// to handle nested archives or to continue processing based on the file's content and depth in the archive structure.
151-
func (h *archiveHandler) extractorHandler(archiveChan chan []byte) func(context.Context, archiver.File) error {
156+
func (h *archiveHandler) extractorHandler(dataOrErrChan chan DataOrErr) func(context.Context, archiver.File) error {
152157
return func(ctx context.Context, file archiver.File) error {
153158
lCtx := logContext.WithValues(
154159
logContext.AddLogger(ctx),
@@ -220,6 +225,6 @@ func (h *archiveHandler) extractorHandler(archiveChan chan []byte) func(context.
220225
h.metrics.observeFileSize(fileSize)
221226

222227
lCtx.Logger().V(4).Info("Processed file successfully", "filename", file.Name(), "size", file.Size())
223-
return h.openArchive(lCtx, depth, rdr, archiveChan)
228+
return h.openArchive(lCtx, depth, rdr, dataOrErrChan)
224229
}
225230
}

pkg/handlers/archive_test.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ func TestArchiveHandler(t *testing.T) {
9191
}
9292
defer newReader.Close()
9393

94-
archiveChan, err := handler.HandleFile(logContext.Background(), newReader)
94+
dataOrErrChan := handler.HandleFile(logContext.Background(), newReader)
9595
if testCase.expectErr {
9696
assert.NoError(t, err)
9797
return
@@ -100,9 +100,9 @@ func TestArchiveHandler(t *testing.T) {
100100
count := 0
101101
re := regexp.MustCompile(testCase.matchString)
102102
matched := false
103-
for chunk := range archiveChan {
103+
for chunk := range dataOrErrChan {
104104
count++
105-
if re.Match(chunk) {
105+
if re.Match(chunk.Data) {
106106
matched = true
107107
}
108108
}
@@ -123,8 +123,8 @@ func TestOpenInvalidArchive(t *testing.T) {
123123
assert.NoError(t, err)
124124
defer rdr.Close()
125125

126-
archiveChan := make(chan []byte)
126+
dataOrErrChan := make(chan DataOrErr)
127127

128-
err = handler.openArchive(ctx, 0, rdr, archiveChan)
128+
err = handler.openArchive(ctx, 0, rdr, dataOrErrChan)
129129
assert.Error(t, err)
130130
}

0 commit comments

Comments
 (0)