Skip to content

Commit 2e4db5f

Browse files
authored
Skip reverification results during deduplication (#5069)
1 parent 4945fa3 commit 2e4db5f

2 files changed

Lines changed: 86 additions & 5 deletions

File tree

pkg/engine/engine.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,12 +1294,18 @@ func (e *Engine) notifierWorker(ctx context.Context) {
12941294
// custom detectors which have the same type.
12951295
// MD5 hash of the key is used to reduce memory usage of the dedupe cache,
12961296
// since the raw result and source metadata can be large.
1297-
h := md5.Sum([]byte(fmt.Sprintf("%s%s%s%s%+v", result.DetectorName, result.DetectorType.String(), result.Raw, result.RawV2, result.SourceMetadata)))
1298-
key := string(h[:])
1299-
if _, ok := e.dedupeCache.Get(key); ok {
1300-
continue
1297+
//
1298+
// This deduplication only applies to results that are *not*
1299+
// from reverification, since we are expected to see the same
1300+
// result from reverification and want to Dispatch it below.
1301+
if result.SecretID == 0 {
1302+
h := md5.Sum([]byte(fmt.Sprintf("%s%s%s%s%+v", result.DetectorName, result.DetectorType.String(), result.Raw, result.RawV2, result.SourceMetadata)))
1303+
key := string(h[:])
1304+
if _, ok := e.dedupeCache.Get(key); ok {
1305+
continue
1306+
}
1307+
e.dedupeCache.Add(key, struct{}{})
13011308
}
1302-
e.dedupeCache.Add(key, struct{}{})
13031309

13041310
if result.Verified {
13051311
atomic.AddUint64(&e.metrics.VerifiedSecretsFound, 1)

pkg/engine/engine_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"time"
1414

1515
"github.com/google/go-cmp/cmp"
16+
lru "github.com/hashicorp/golang-lru/v2"
1617
"github.com/stretchr/testify/assert"
1718
"github.com/stretchr/testify/require"
1819
"google.golang.org/protobuf/testing/protocmp"
@@ -1990,3 +1991,77 @@ func TestEngine_IterativeDecoding(t *testing.T) {
19901991
})
19911992
}
19921993
}
1994+
1995+
// captureDispatcher records every dispatched result for assertion in tests.
1996+
type captureDispatcher struct {
1997+
results []detectors.ResultWithMetadata
1998+
}
1999+
2000+
func (d *captureDispatcher) Dispatch(_ context.Context, result detectors.ResultWithMetadata) error {
2001+
d.results = append(d.results, result)
2002+
return nil
2003+
}
2004+
2005+
// TestNotifierWorker_ReverifiedResultsBypassDedupe verifies that the notifier's
2006+
// dedupe cache is skipped when a result carries a non-zero SecretID — i.e., when
2007+
// it originated from reverification — so that the dispatcher sees every
2008+
// reverification result even when the underlying secret has not changed.
2009+
func TestNotifierWorker_ReverifiedResultsBypassDedupe(t *testing.T) {
2010+
tests := []struct {
2011+
name string
2012+
secretID int64
2013+
wantDispatch int
2014+
}{
2015+
{
2016+
name: "non-reverified duplicates are deduplicated",
2017+
secretID: 0,
2018+
wantDispatch: 1,
2019+
},
2020+
{
2021+
name: "reverified duplicates bypass the dedupe cache",
2022+
secretID: 42,
2023+
wantDispatch: 2,
2024+
},
2025+
}
2026+
2027+
for _, tt := range tests {
2028+
t.Run(tt.name, func(t *testing.T) {
2029+
cache, err := lru.New[string, struct{}](16)
2030+
require.NoError(t, err)
2031+
2032+
disp := &captureDispatcher{}
2033+
e := &Engine{
2034+
results: make(chan detectors.ResultWithMetadata, 4),
2035+
dedupeCache: cache,
2036+
dispatcher: disp,
2037+
notifyVerifiedResults: true,
2038+
notifyUnverifiedResults: true,
2039+
notifyUnknownResults: true,
2040+
}
2041+
2042+
result := detectors.ResultWithMetadata{
2043+
SourceMetadata: &source_metadatapb.MetaData{
2044+
Data: &source_metadatapb.MetaData_Git{
2045+
Git: &source_metadatapb.Git{Line: 1},
2046+
},
2047+
},
2048+
SourceType: sourcespb.SourceType_SOURCE_TYPE_GIT,
2049+
SecretID: tt.secretID,
2050+
Result: detectors.Result{
2051+
DetectorType: detector_typepb.DetectorType(-1),
2052+
Raw: []byte("a-secret"),
2053+
Verified: true,
2054+
},
2055+
}
2056+
2057+
// Push the same result twice — identical hash inputs.
2058+
e.results <- result
2059+
e.results <- result
2060+
close(e.results)
2061+
2062+
e.notifierWorker(context.Background())
2063+
2064+
assert.Equal(t, tt.wantDispatch, len(disp.results))
2065+
})
2066+
}
2067+
}

0 commit comments

Comments
 (0)