Skip to content

Commit 53a40b3

Browse files
committed
fix: safeguard against attempting to (re)use partially loaded databases
1 parent d14e0b2 commit 53a40b3

File tree

3 files changed

+44
-0
lines changed

3 files changed

+44
-0
lines changed

internal/clients/clientimpl/localmatcher/localmatcher.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ func NewLocalMatcher(localDBPath string, userAgent string, downloadDB bool) (*Lo
4949
func (matcher *LocalMatcher) MatchVulnerabilities(ctx context.Context, invs []*extractor.Package) ([][]*osvschema.Vulnerability, error) {
5050
results := make([][]*osvschema.Vulnerability, 0, len(invs))
5151

52+
// ensure all databases loaded so far have been fully loaded; this is just a
53+
// basic safeguard since we don't actually currently attempt to reuse matchers
54+
// across scans, and its possible we never will, so we don't need to be smart
55+
for _, db := range matcher.dbs {
56+
if db.Partial {
57+
return nil, errors.New("local matcher cannot be (re)used with a partially loaded database")
58+
}
59+
}
60+
5261
for _, inv := range invs {
5362
if ctx.Err() != nil {
5463
return nil, ctx.Err()
@@ -86,6 +95,8 @@ func (matcher *LocalMatcher) MatchVulnerabilities(ctx context.Context, invs []*e
8695

8796
// LoadEcosystem tries to preload the ecosystem into the cache, and returns an error if the ecosystem
8897
// cannot be loaded.
98+
//
99+
// Preloaded databases include every advisory, so can be reused.
89100
func (matcher *LocalMatcher) LoadEcosystem(ctx context.Context, eco osvecosystem.Parsed) error {
90101
_, err := matcher.loadDBFromCache(ctx, eco, nil)
91102

internal/clients/clientimpl/localmatcher/zip.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ type ZipDB struct {
3636
Vulnerabilities []osvschema.Vulnerability
3737
// User agent to query with
3838
UserAgent string
39+
40+
// whether this database only has some of the advisories
41+
// loaded from the underlying zip file
42+
Partial bool
3943
}
4044

4145
var ErrOfflineDatabaseNotFound = errors.New("no offline version of the OSV database is available")
@@ -231,6 +235,9 @@ func NewZippedDB(ctx context.Context, dbBasePath, name, url, userAgent string, o
231235
Offline: offline,
232236
StoredAt: path.Join(dbBasePath, name, "all.zip"),
233237
UserAgent: userAgent,
238+
239+
// we only fully load the database if we're not provided a list of packages
240+
Partial: len(invs) != 0,
234241
}
235242
names := make([]string, 0, len(invs))
236243

internal/clients/clientimpl/localmatcher/zip_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@ func TestNewZippedDB_Offline_WithCache(t *testing.T) {
185185
t.Fatalf("unexpected error \"%v\"", err)
186186
}
187187

188+
if db.Partial != false {
189+
t.Errorf("db is incorrectly marked as partially loaded")
190+
}
188191
expectDBToHaveOSVs(t, db, osvs)
189192
}
190193

@@ -245,6 +248,9 @@ func TestNewZippedDB_Online_WithoutCache(t *testing.T) {
245248
t.Fatalf("unexpected error \"%v\"", err)
246249
}
247250

251+
if db.Partial != false {
252+
t.Errorf("db is incorrectly marked as partially loaded")
253+
}
248254
expectDBToHaveOSVs(t, db, osvs)
249255
}
250256

@@ -277,6 +283,9 @@ func TestNewZippedDB_Online_WithoutCacheAndNoHashHeader(t *testing.T) {
277283
t.Fatalf("unexpected error \"%v\"", err)
278284
}
279285

286+
if db.Partial != false {
287+
t.Errorf("db is incorrectly marked as partially loaded")
288+
}
280289
expectDBToHaveOSVs(t, db, osvs)
281290
}
282291

@@ -315,6 +324,9 @@ func TestNewZippedDB_Online_WithSameCache(t *testing.T) {
315324
t.Fatalf("unexpected error \"%v\"", err)
316325
}
317326

327+
if db.Partial != false {
328+
t.Errorf("db is incorrectly marked as partially loaded")
329+
}
318330
expectDBToHaveOSVs(t, db, osvs)
319331
}
320332

@@ -353,6 +365,9 @@ func TestNewZippedDB_Online_WithDifferentCache(t *testing.T) {
353365
t.Fatalf("unexpected error \"%v\"", err)
354366
}
355367

368+
if db.Partial != false {
369+
t.Errorf("db is incorrectly marked as partially loaded")
370+
}
356371
expectDBToHaveOSVs(t, db, osvs)
357372
}
358373

@@ -411,6 +426,9 @@ func TestNewZippedDB_Online_WithBadCache(t *testing.T) {
411426
t.Fatalf("unexpected error \"%v\"", err)
412427
}
413428

429+
if db.Partial != false {
430+
t.Errorf("db is incorrectly marked as partially loaded")
431+
}
414432
expectDBToHaveOSVs(t, db, osvs)
415433
}
416434

@@ -437,6 +455,9 @@ func TestNewZippedDB_FileChecks(t *testing.T) {
437455
t.Fatalf("unexpected error \"%v\"", err)
438456
}
439457

458+
if db.Partial != false {
459+
t.Errorf("db is incorrectly marked as partially loaded")
460+
}
440461
expectDBToHaveOSVs(t, db, osvs)
441462
}
442463

@@ -497,6 +518,11 @@ func TestNewZippedDB_WithSpecificPackages(t *testing.T) {
497518
t.Fatalf("unexpected error \"%v\"", err)
498519
}
499520

521+
// we are loaded for specific packages
522+
if db.Partial != true {
523+
t.Errorf("db is incorrectly marked as fully loaded")
524+
}
525+
500526
expectDBToHaveOSVs(t, db, []osvschema.Vulnerability{
501527
{
502528
ID: "GHSA-2",

0 commit comments

Comments
 (0)