@@ -12,6 +12,7 @@ import (
1212 "time"
1313
1414 "github.com/stretchr/testify/assert"
15+ "github.com/stretchr/testify/require"
1516
1617 "github.com/trufflesecurity/trufflehog/v3/pkg/config"
1718 "github.com/trufflesecurity/trufflehog/v3/pkg/context"
@@ -26,6 +27,7 @@ import (
2627 "github.com/trufflesecurity/trufflehog/v3/pkg/pb/source_metadatapb"
2728 "github.com/trufflesecurity/trufflehog/v3/pkg/pb/sourcespb"
2829 "github.com/trufflesecurity/trufflehog/v3/pkg/sources"
30+ "github.com/trufflesecurity/trufflehog/v3/pkg/verificationcache"
2931)
3032
3133const fakeDetectorKeyword = "fakedetector"
@@ -1318,3 +1320,223 @@ def test_something():
13181320 })
13191321 }
13201322}
1323+
1324+ type passthroughDetector struct {
1325+ detectorType detectorspb.DetectorType
1326+ keywords []string
1327+ secret string
1328+ }
1329+
1330+ func (p passthroughDetector ) FromData (_ aCtx.Context , verify bool , data []byte ) ([]detectors.Result , error ) {
1331+ raw := data
1332+ if p .secret != "" {
1333+ raw = []byte (p .secret )
1334+ }
1335+ return []detectors.Result {
1336+ {
1337+ Raw : raw ,
1338+ Verified : verify ,
1339+ },
1340+ }, nil
1341+ }
1342+
1343+ func (p passthroughDetector ) Keywords () []string { return p .keywords }
1344+ func (p passthroughDetector ) Type () detectorspb.DetectorType { return p .detectorType }
1345+ func (p passthroughDetector ) Description () string { return "fake detector for testing" }
1346+
1347+ type passthroughDecoder struct {}
1348+
1349+ func (p passthroughDecoder ) FromChunk (chunk * sources.Chunk ) * decoders.DecodableChunk {
1350+ return & decoders.DecodableChunk {
1351+ Chunk : chunk ,
1352+ DecoderType : detectorspb .DecoderType (- 1 ),
1353+ }
1354+ }
1355+
1356+ func (p passthroughDecoder ) Type () detectorspb.DecoderType { return detectorspb .DecoderType (- 1 ) }
1357+
1358+ func TestEngine_DetectChunk_UsesVerifyFlag (t * testing.T ) {
1359+ ctx := context .Background ()
1360+
1361+ // Arrange: Create a minimal engine.
1362+ e := & Engine {
1363+ results : make (chan detectors.ResultWithMetadata , 1 ),
1364+ verificationCache : verificationcache .New (nil , & verificationcache.InMemoryMetrics {}),
1365+ }
1366+
1367+ // Arrange: Create a detector match. We can't create one directly, so we have to use a minimal A-H core.
1368+ ahcore := ahocorasick .NewAhoCorasickCore ([]detectors.Detector {passthroughDetector {keywords : []string {"keyword" }}})
1369+ detectorMatches := ahcore .FindDetectorMatches ([]byte ("keyword" ))
1370+ require .Len (t , detectorMatches , 1 )
1371+
1372+ // Arrange: Create a chunk to detect.
1373+ chunk := detectableChunk {
1374+ chunk : sources.Chunk {
1375+ Verify : true ,
1376+ },
1377+ detector : detectorMatches [0 ],
1378+ wgDoneFn : func () {},
1379+ }
1380+
1381+ // Act
1382+ e .detectChunk (ctx , chunk )
1383+ close (e .results )
1384+
1385+ // Assert: Confirm that a result was generated and that it has the expected verify flag.
1386+ select {
1387+ case result := <- e .results :
1388+ assert .True (t , result .Result .Verified )
1389+ default :
1390+ t .Errorf ("expected a result but did not get one" )
1391+ }
1392+ }
1393+
1394+ func TestEngine_ScannerWorker_DetectableChunkHasCorrectVerifyFlag (t * testing.T ) {
1395+ ctx := context .Background ()
1396+
1397+ // Arrange: Create a minimal engine.
1398+ detector := & passthroughDetector {keywords : []string {"keyword" }}
1399+ e := & Engine {
1400+ AhoCorasickCore : ahocorasick .NewAhoCorasickCore ([]detectors.Detector {detector }),
1401+ decoders : []decoders.Decoder {passthroughDecoder {}},
1402+ detectableChunksChan : make (chan detectableChunk , 1 ),
1403+ sourceManager : sources .NewManager (),
1404+ verify : true ,
1405+ }
1406+
1407+ // Arrange: Create a chunk to scan.
1408+ chunk := sources.Chunk {
1409+ Data : []byte ("keyword" ),
1410+ Verify : true ,
1411+ }
1412+
1413+ // Arrange: Enqueue a chunk to be scanned.
1414+ e .sourceManager .ScanChunk (& chunk )
1415+
1416+ // Act
1417+ go e .scannerWorker (ctx )
1418+
1419+ // Assert: Confirm that a chunk was generated and that it has the expected verify flag.
1420+ select {
1421+ case chunk := <- e .detectableChunksChan :
1422+ assert .True (t , chunk .chunk .Verify )
1423+ case <- time .After (1 * time .Second ):
1424+ t .Errorf ("expected a detectableChunk but did not get one" )
1425+ }
1426+ }
1427+
1428+ func TestEngine_VerificationOverlapWorker_DetectableChunkHasCorrectVerifyFlag (t * testing.T ) {
1429+ ctx := context .Background ()
1430+
1431+ t .Run ("overlap" , func (t * testing.T ) {
1432+ // Arrange: Create a minimal engine
1433+ e := & Engine {
1434+ detectableChunksChan : make (chan detectableChunk , 2 ),
1435+ results : make (chan detectors.ResultWithMetadata , 2 ),
1436+ retainFalsePositives : true ,
1437+ verificationOverlapChunksChan : make (chan verificationOverlapChunk , 2 ),
1438+ verify : true ,
1439+ }
1440+
1441+ // Arrange: Set up a fake detectableChunk processor so that any chunks (incorrectly) sent to
1442+ // e.detectableChunksChan don't block the test.
1443+ processedDetectableChunks := make (chan detectableChunk , 2 )
1444+ go func () {
1445+ for chunk := range e .detectableChunksChan {
1446+ chunk .wgDoneFn ()
1447+ processedDetectableChunks <- chunk
1448+ }
1449+ }()
1450+
1451+ // Arrange: Create a chunk to "scan."
1452+ chunk := sources.Chunk {
1453+ Data : []byte ("keyword ;oahpow8heg;blaisd" ),
1454+ Verify : true ,
1455+ }
1456+
1457+ // Arrange: Create overlapping detector matches. We can't create them directly, so we have to use a minimal A-H
1458+ // core.
1459+ ahcore := ahocorasick .NewAhoCorasickCore ([]detectors.Detector {
1460+ passthroughDetector {detectorType : detectorspb .DetectorType (- 1 ), keywords : []string {"keyw" }},
1461+ passthroughDetector {detectorType : detectorspb .DetectorType (- 2 ), keywords : []string {"keyword" }},
1462+ })
1463+ detectorMatches := ahcore .FindDetectorMatches (chunk .Data )
1464+ require .Len (t , detectorMatches , 2 )
1465+
1466+ // Arrange: Enqueue a verification overlap chunk
1467+ e .verificationOverlapChunksChan <- verificationOverlapChunk {
1468+ chunk : chunk ,
1469+ detectors : detectorMatches ,
1470+ verificationOverlapWgDoneFn : func () { close (e .verificationOverlapChunksChan ) },
1471+ }
1472+
1473+ // Act
1474+ e .verificationOverlapWorker (ctx )
1475+ close (e .results )
1476+ close (e .detectableChunksChan )
1477+ close (processedDetectableChunks )
1478+
1479+ // Assert: Confirm that every generated result is unverified (because overlap detection precluded it).
1480+ for result := range e .results {
1481+ assert .False (t , result .Result .Verified )
1482+ }
1483+
1484+ // Assert: Confirm that every generated detectable chunk carries the original Verify flag.
1485+ // CMR: There should be not be any of these chunks. However, due to what I believe is an unrelated bug, there
1486+ // are. This test ensures that even in that erroneous case, their Verify flag is correct.
1487+ for detectableChunk := range processedDetectableChunks {
1488+ assert .True (t , detectableChunk .chunk .Verify )
1489+ }
1490+ })
1491+ t .Run ("no overlap" , func (t * testing.T ) {
1492+ // Arrange: Create a minimal engine
1493+ e := & Engine {
1494+ detectableChunksChan : make (chan detectableChunk , 2 ),
1495+ retainFalsePositives : true ,
1496+ verificationOverlapChunksChan : make (chan verificationOverlapChunk , 2 ),
1497+ verify : true ,
1498+ }
1499+
1500+ // Arrange: Set up a fake detectableChunk processor so that any chunks sent to e.detectableChunksChan don't
1501+ // block the test.
1502+ processedDetectableChunks := make (chan detectableChunk , 2 )
1503+ go func () {
1504+ for chunk := range e .detectableChunksChan {
1505+ chunk .wgDoneFn ()
1506+ processedDetectableChunks <- chunk
1507+ }
1508+ }()
1509+
1510+ // Arrange: Create a chunk to "scan."
1511+ chunk := sources.Chunk {
1512+ Data : []byte ("keyword ;oahpow8heg;blaisd" ),
1513+ Verify : true ,
1514+ }
1515+
1516+ // Arrange: Create non-overlapping detector matches. We can't create them directly, so we have to use a minimal
1517+ // A-H core.
1518+ ahcore := ahocorasick .NewAhoCorasickCore ([]detectors.Detector {
1519+ passthroughDetector {detectorType : detectorspb .DetectorType (- 1 ), keywords : []string {"keyw" }, secret : "oahpow" },
1520+ passthroughDetector {detectorType : detectorspb .DetectorType (- 2 ), keywords : []string {"keyword" }, secret : "blaisd" },
1521+ })
1522+ detectorMatches := ahcore .FindDetectorMatches (chunk .Data )
1523+ require .Len (t , detectorMatches , 2 )
1524+
1525+ // Arrange: Enqueue a verification overlap chunk
1526+ e .verificationOverlapChunksChan <- verificationOverlapChunk {
1527+ chunk : chunk ,
1528+ detectors : detectorMatches ,
1529+ verificationOverlapWgDoneFn : func () { close (e .verificationOverlapChunksChan ) },
1530+ }
1531+
1532+ // Act
1533+ e .verificationOverlapWorker (ctx )
1534+ close (e .detectableChunksChan )
1535+ close (processedDetectableChunks )
1536+
1537+ // Assert: Confirm that every generated detectable chunk carries the original Verify flag.
1538+ for detectableChunk := range processedDetectableChunks {
1539+ assert .True (t , detectableChunk .chunk .Verify )
1540+ }
1541+ })
1542+ }
0 commit comments