From a945994e40b71108f1f747b452ca68a863b3d902 Mon Sep 17 00:00:00 2001 From: Jess Lowe Date: Tue, 28 Jul 2026 01:36:17 +0000 Subject: [PATCH 1/5] fix alpine duplication --- vulnfeeds/vulns/vulns.go | 99 ++++++++++++++++++++++++++--------- vulnfeeds/vulns/vulns_test.go | 95 +++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 25 deletions(-) diff --git a/vulnfeeds/vulns/vulns.go b/vulnfeeds/vulns/vulns.go index a68f609de3d..fd5a429db8c 100644 --- a/vulnfeeds/vulns/vulns.go +++ b/vulnfeeds/vulns/vulns.go @@ -228,21 +228,46 @@ type Vulnerability struct { // AddPkgInfo converts a PackageInfo struct to the corresponding Affected and adds it to the OSV vulnerability object. func (v *Vulnerability) AddPkgInfo(pkgInfo PackageInfo) { - affected := &osvschema.Affected{} - + var affected *osvschema.Affected if pkgInfo.PkgName != "" && pkgInfo.Ecosystem != "" { - affected.Package = &osvschema.Package{ - Name: pkgInfo.PkgName, - Ecosystem: pkgInfo.Ecosystem, - Purl: pkgInfo.PURL, + for _, a := range v.Affected { + if a.GetPackage().GetName() == pkgInfo.PkgName && a.GetPackage().GetEcosystem() == pkgInfo.Ecosystem { + affected = a + break + } } } + if affected == nil { + affected = &osvschema.Affected{} + if pkgInfo.PkgName != "" && pkgInfo.Ecosystem != "" { + affected.Package = &osvschema.Package{ + Name: pkgInfo.PkgName, + Ecosystem: pkgInfo.Ecosystem, + Purl: pkgInfo.PURL, + } + } + v.Affected = append(v.Affected, affected) + } + // Aggregate commits by their repo, and synthesize a zero introduced commit if necessary. if len(pkgInfo.VersionInfo.AffectedCommits) > 0 { gitCommitRangesByRepo := make(map[string]*osvschema.Range) + for _, r := range affected.GetRanges() { + if r.GetType() == osvschema.Range_GIT { + gitCommitRangesByRepo[r.GetRepo()] = r + } + } hasAddedZeroIntroduced := make(map[string]bool) + for repo, r := range gitCommitRangesByRepo { + for _, e := range r.GetEvents() { + if e.GetIntroduced() == "0" { + hasAddedZeroIntroduced[repo] = true + break + } + } + } for _, ac := range pkgInfo.VersionInfo.AffectedCommits { entry, ok := gitCommitRangesByRepo[ac.Repo] @@ -253,16 +278,18 @@ func (v *Vulnerability) AddPkgInfo(pkgInfo PackageInfo) { Events: []*osvschema.Event{}, Repo: ac.Repo, } + gitCommitRangesByRepo[ac.Repo] = entry + affected.Ranges = append(affected.Ranges, entry) + } - if !pkgInfo.VersionInfo.HasIntroducedCommits(ac.Repo) && !hasAddedZeroIntroduced[ac.Repo] { - // There was no explicitly defined introduced commit, so create one at 0. - entry.Events = append(entry.Events, - &osvschema.Event{ - Introduced: "0", - }, - ) - hasAddedZeroIntroduced[ac.Repo] = true - } + if !pkgInfo.VersionInfo.HasIntroducedCommits(ac.Repo) && !hasAddedZeroIntroduced[ac.Repo] { + // There was no explicitly defined introduced commit, so create one at 0. + entry.Events = append(entry.Events, + &osvschema.Event{ + Introduced: "0", + }, + ) + hasAddedZeroIntroduced[ac.Repo] = true } if ac.Introduced != "" { @@ -277,23 +304,43 @@ func (v *Vulnerability) AddPkgInfo(pkgInfo PackageInfo) { if ac.Limit != "" { entry.Events = append(entry.Events, &osvschema.Event{Limit: ac.Limit}) } - gitCommitRangesByRepo[ac.Repo] = entry - } - - for repo := range gitCommitRangesByRepo { - affected.Ranges = append(affected.Ranges, gitCommitRangesByRepo[repo]) } } if len(pkgInfo.VersionInfo.AffectedVersions) > 0 { - versionRange := &osvschema.Range{ - Type: osvschema.Range_ECOSYSTEM, - Events: []*osvschema.Event{}, + var versionRange *osvschema.Range + for _, r := range affected.GetRanges() { + if r.GetType() == osvschema.Range_ECOSYSTEM { + versionRange = r + break + } } + + isNewRange := false + if versionRange == nil { + versionRange = &osvschema.Range{ + Type: osvschema.Range_ECOSYSTEM, + Events: []*osvschema.Event{}, + } + isNewRange = true + } + seenIntroduced := map[string]bool{} seenFixed := map[string]bool{} seenLastAffected := map[string]bool{} + for _, e := range versionRange.GetEvents() { + if e.GetIntroduced() != "" { + seenIntroduced[e.GetIntroduced()] = true + } + if e.GetFixed() != "" { + seenFixed[e.GetFixed()] = true + } + if e.GetLastAffected() != "" { + seenLastAffected[e.GetLastAffected()] = true + } + } + for _, av := range pkgInfo.VersionInfo.AffectedVersions { var introduced string if av.Introduced == "" { @@ -323,7 +370,10 @@ func (v *Vulnerability) AddPkgInfo(pkgInfo PackageInfo) { seenLastAffected[av.LastAffected] = true } } - affected.Ranges = append(affected.Ranges, versionRange) + + if isNewRange { + affected.Ranges = append(affected.Ranges, versionRange) + } } // Sort affected[].ranges (by type) for stability. @@ -342,7 +392,6 @@ func (v *Vulnerability) AddPkgInfo(pkgInfo PackageInfo) { } else { affected.EcosystemSpecific = spec } - v.Affected = append(v.Affected, affected) } // getBestSeverity finds the best CVSS severity vector from the provided metrics data. diff --git a/vulnfeeds/vulns/vulns_test.go b/vulnfeeds/vulns/vulns_test.go index 98dea015a9c..4c17e824e99 100644 --- a/vulnfeeds/vulns/vulns_test.go +++ b/vulnfeeds/vulns/vulns_test.go @@ -757,3 +757,98 @@ func TestToYAMLFromYAMLRoundTripLastAffected(t *testing.T) { t.Errorf("last_affected '2.12.1' did not survive the YAML round-trip; events=%v", events) } } + +func TestAddPkgInfo_MergeAffected(t *testing.T) { + vuln := &Vulnerability{ + Vulnerability: &osvschema.Vulnerability{ + Id: "TEST-VULN", + }, + } + + // 1. Add PackageA in EcosystemA + vuln.AddPkgInfo(PackageInfo{ + PkgName: "PackageA", + Ecosystem: "EcosystemA", + VersionInfo: models.VersionInfo{ + AffectedVersions: []models.AffectedVersion{ + {Introduced: "1.0.0", Fixed: "1.1.0"}, + }, + }, + }) + + // 2. Add PackageA in EcosystemA again with different version + vuln.AddPkgInfo(PackageInfo{ + PkgName: "PackageA", + Ecosystem: "EcosystemA", + VersionInfo: models.VersionInfo{ + AffectedVersions: []models.AffectedVersion{ + {Introduced: "1.0.0", Fixed: "2.1.0"}, + }, + }, + }) + + // 3. Add PackageB in EcosystemA + vuln.AddPkgInfo(PackageInfo{ + PkgName: "PackageB", + Ecosystem: "EcosystemA", + VersionInfo: models.VersionInfo{ + AffectedVersions: []models.AffectedVersion{ + {Introduced: "1.0.0", Fixed: "1.1.0"}, + }, + }, + }) + + if len(vuln.Affected) != 2 { + t.Fatalf("Expected 2 affected entries, got %d", len(vuln.Affected)) + } + + // Find PackageA + var pkgA *osvschema.Affected + for _, a := range vuln.Affected { + if a.GetPackage().GetName() == "PackageA" && a.GetPackage().GetEcosystem() == "EcosystemA" { + pkgA = a + break + } + } + + if pkgA == nil { + t.Fatalf("Could not find PackageA in EcosystemA") + } + + // Check ranges for PackageA + // It should be a single range of type ECOSYSTEM + if len(pkgA.GetRanges()) != 1 { + t.Fatalf("Expected 1 range for PackageA, got %d", len(pkgA.GetRanges())) + } + + r := pkgA.GetRanges()[0] + if r.GetType() != osvschema.Range_ECOSYSTEM { + t.Errorf("Expected range type ECOSYSTEM, got %v", r.GetType()) + } + + // It should have merged events + // Expected: Introduced "1.0.0", Fixed "1.1.0", Fixed "2.1.0" + if len(r.GetEvents()) != 3 { + t.Errorf("Expected 3 events for PackageA, got %d", len(r.GetEvents())) + } + + expectedEvents := []struct { + Introduced string + Fixed string + }{ + {Introduced: "1.0.0"}, + {Fixed: "1.1.0"}, + {Fixed: "2.1.0"}, + } + + for i, e := range r.GetEvents() { + if i >= len(expectedEvents) { + t.Errorf("Unexpected event at index %d: %+v", i, e) + continue + } + if expectedEvents[i].Introduced != e.GetIntroduced() || expectedEvents[i].Fixed != e.GetFixed() { + t.Errorf("Event at index %d mismatch: got %+v, want %+v", i, e, expectedEvents[i]) + } + } + +} From a1d606fe291665cb2060568be0a165c8b453c791 Mon Sep 17 00:00:00 2001 From: Jess Lowe Date: Tue, 28 Jul 2026 03:45:57 +0000 Subject: [PATCH 2/5] lint --- vulnfeeds/vulns/vulns_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/vulnfeeds/vulns/vulns_test.go b/vulnfeeds/vulns/vulns_test.go index 4c17e824e99..b3be78c02ef 100644 --- a/vulnfeeds/vulns/vulns_test.go +++ b/vulnfeeds/vulns/vulns_test.go @@ -850,5 +850,4 @@ func TestAddPkgInfo_MergeAffected(t *testing.T) { t.Errorf("Event at index %d mismatch: got %+v, want %+v", i, e, expectedEvents[i]) } } - } From 69b5070e94bb0c99fecfcb59e99d36057c872d52 Mon Sep 17 00:00:00 2001 From: Jess Lowe Date: Thu, 6 Aug 2026 05:59:16 +0000 Subject: [PATCH 3/5] no affectedcommits anymore - addpkginfo only used by debian/alpine/pypi --- vulnfeeds/vulns/vulns.go | 73 ++++------------------------ vulnfeeds/vulns/vulns_test.go | 89 +++-------------------------------- 2 files changed, 17 insertions(+), 145 deletions(-) diff --git a/vulnfeeds/vulns/vulns.go b/vulnfeeds/vulns/vulns.go index fd5a429db8c..592309ac3c6 100644 --- a/vulnfeeds/vulns/vulns.go +++ b/vulnfeeds/vulns/vulns.go @@ -250,63 +250,6 @@ func (v *Vulnerability) AddPkgInfo(pkgInfo PackageInfo) { v.Affected = append(v.Affected, affected) } - // Aggregate commits by their repo, and synthesize a zero introduced commit if necessary. - if len(pkgInfo.VersionInfo.AffectedCommits) > 0 { - gitCommitRangesByRepo := make(map[string]*osvschema.Range) - for _, r := range affected.GetRanges() { - if r.GetType() == osvschema.Range_GIT { - gitCommitRangesByRepo[r.GetRepo()] = r - } - } - - hasAddedZeroIntroduced := make(map[string]bool) - for repo, r := range gitCommitRangesByRepo { - for _, e := range r.GetEvents() { - if e.GetIntroduced() == "0" { - hasAddedZeroIntroduced[repo] = true - break - } - } - } - - for _, ac := range pkgInfo.VersionInfo.AffectedCommits { - entry, ok := gitCommitRangesByRepo[ac.Repo] - // Create the stub for the repo if necessary. - if !ok { - entry = &osvschema.Range{ - Type: osvschema.Range_GIT, - Events: []*osvschema.Event{}, - Repo: ac.Repo, - } - gitCommitRangesByRepo[ac.Repo] = entry - affected.Ranges = append(affected.Ranges, entry) - } - - if !pkgInfo.VersionInfo.HasIntroducedCommits(ac.Repo) && !hasAddedZeroIntroduced[ac.Repo] { - // There was no explicitly defined introduced commit, so create one at 0. - entry.Events = append(entry.Events, - &osvschema.Event{ - Introduced: "0", - }, - ) - hasAddedZeroIntroduced[ac.Repo] = true - } - - if ac.Introduced != "" { - entry.Events = append(entry.Events, &osvschema.Event{Introduced: ac.Introduced}) - } - if ac.Fixed != "" { - entry.Events = append(entry.Events, &osvschema.Event{Fixed: ac.Fixed}) - } - if ac.LastAffected != "" { - entry.Events = append(entry.Events, &osvschema.Event{LastAffected: ac.LastAffected}) - } - if ac.Limit != "" { - entry.Events = append(entry.Events, &osvschema.Event{Limit: ac.Limit}) - } - } - } - if len(pkgInfo.VersionInfo.AffectedVersions) > 0 { var versionRange *osvschema.Range for _, r := range affected.GetRanges() { @@ -344,16 +287,20 @@ func (v *Vulnerability) AddPkgInfo(pkgInfo PackageInfo) { for _, av := range pkgInfo.VersionInfo.AffectedVersions { var introduced string if av.Introduced == "" { - introduced = "0" + if len(versionRange.Events) == 0 { + introduced = "0" + } } else { introduced = av.Introduced } - if _, seen := seenIntroduced[introduced]; !seen { - versionRange.Events = append(versionRange.Events, &osvschema.Event{ - Introduced: introduced, - }) - seenIntroduced[introduced] = true + if introduced != "" { + if _, seen := seenIntroduced[introduced]; !seen { + versionRange.Events = append(versionRange.Events, &osvschema.Event{ + Introduced: introduced, + }) + seenIntroduced[introduced] = true + } } if _, seen := seenFixed[av.Fixed]; av.Fixed != "" && !seen { diff --git a/vulnfeeds/vulns/vulns_test.go b/vulnfeeds/vulns/vulns_test.go index b3be78c02ef..e94cb71acc2 100644 --- a/vulnfeeds/vulns/vulns_test.go +++ b/vulnfeeds/vulns/vulns_test.go @@ -1,7 +1,6 @@ package vulns import ( - "cmp" "encoding/json" "fmt" "log" @@ -12,8 +11,6 @@ import ( "testing" "time" - "slices" - gocmp "github.com/google/go-cmp/cmp" "github.com/google/osv/vulnfeeds/models" "github.com/google/osv/vulnfeeds/utility" @@ -248,16 +245,6 @@ func TestAddPkgInfo(t *testing.T) { }, }, } - testPkgInfoCommits := PackageInfo{ - VersionInfo: models.VersionInfo{ - AffectedCommits: []models.AffectedCommit{ - { - Fixed: "dsafwefwfe370a9e65d68d62ef37345597e4100b0e87021dfb", - Repo: "github.com/foo/bar", - }, - }, - }, - } testPkgInfoHybrid := PackageInfo{ PkgName: "apackage", Ecosystem: "Debian", @@ -268,35 +255,6 @@ func TestAddPkgInfo(t *testing.T) { Fixed: "1.2.3-4", }, }, - AffectedCommits: []models.AffectedCommit{ - { - Fixed: "0xdeadbeef", - Repo: "github.com/foo/bar", - }, - { - Fixed: "0xdeadbeef", - Repo: "github.com/baz/quux", - }, - }, - }, - } - testPkgInfoCommitsMultiple := PackageInfo{ - VersionInfo: models.VersionInfo{ - AffectedCommits: []models.AffectedCommit{ - { - Introduced: "0xdeadbeef", - Fixed: "dsafwefwfe370a9e65d68d62ef37345597e4100b0e87021dfb", - Repo: "github.com/foo/bar", - }, - { - Fixed: "658fe213", - Repo: "github.com/foo/bar", - }, - { - LastAffected: "0xdeadf00d", - Repo: "github.com/foo/baz", - }, - }, }, } testPkgInfoEcoMultiple := PackageInfo{ @@ -311,12 +269,10 @@ func TestAddPkgInfo(t *testing.T) { }, }, } - vuln.AddPkgInfo(testPkgInfoNameEco) // This will end up in vuln.Affected[0] - vuln.AddPkgInfo(testPkgInfoPURL) // This will end up in vuln.Affected[1] - vuln.AddPkgInfo(testPkgInfoCommits) // This will end up in vuln.Affected[2] - vuln.AddPkgInfo(testPkgInfoHybrid) // This will end up in vuln.Affected[3] - vuln.AddPkgInfo(testPkgInfoCommitsMultiple) // This will end up in vuln.Affected[4] - vuln.AddPkgInfo(testPkgInfoEcoMultiple) // This will end up in vuln.Affected[5] + vuln.AddPkgInfo(testPkgInfoNameEco) // This will end up in vuln.Affected[0] + vuln.AddPkgInfo(testPkgInfoPURL) // This will end up in vuln.Affected[1] + vuln.AddPkgInfo(testPkgInfoHybrid) // This will end up in vuln.Affected[2] + vuln.AddPkgInfo(testPkgInfoEcoMultiple) // This will end up in vuln.Affected[3] t.Logf("Resulting vuln: %+v", &vuln) @@ -354,42 +310,11 @@ func TestAddPkgInfo(t *testing.T) { } // testPkgInfoPURL ^^^^^^^^^^^^^^^ - // testPkgInfoCommits vvvvvvvvvvvvvv - if vuln.Affected[2].GetRanges()[0].GetRepo() != "github.com/foo/bar" { - t.Errorf("AddPkgInfo has not corrected add ranges repo. %#v", vuln.Affected[2]) - } - - if vuln.Affected[2].GetRanges()[0].GetType() != osvschema.Range_GIT { - t.Errorf("AddPkgInfo has not correctly added ranges type.") - } - if vuln.Affected[2].GetRanges()[0].GetEvents()[1].GetFixed() != testPkgInfoCommits.VersionInfo.AffectedCommits[0].Fixed { - t.Errorf("AddPkgInfo has not correctly added ranges fixed.") - } - if vuln.Affected[2].GetPackage() != nil { - t.Errorf("AddPkgInfo has not correctly avoided setting a package field for an ecosystem-less vulnerability.") - } - if !slices.IsSortedFunc(vuln.Affected[3].GetRanges(), func(a, b *osvschema.Range) int { - if n := cmp.Compare(a.GetType(), b.GetType()); n != 0 { - return n - } - - return cmp.Compare(a.GetRepo(), b.GetRepo()) - }) { - t.Errorf("AddPkgInfo has not generated a correctly sorted range.") - } - // testPkgInfoCommits ^^^^^^^^^^^^^^^ - - // testPkgInfoCommitsMultiple vvvvvvvvvvvvv - if len(vuln.Affected[4].GetRanges()[0].GetEvents()) != 3 { - t.Errorf("AddPkgInfo has not correctly added distinct range events from commits: %+v", vuln.Affected[4].GetRanges()) - } - // testPkgInfoCommitsMultiple ^^^^^^^^^^^^^ - // testPkgInfoEcoMultiple vvvvvvvvvvvvv - if len(vuln.Affected[5].GetRanges()[0].GetEvents()) != 2 { - t.Errorf("AddPkgInfo has not correctly added distinct range events from versions: %+v", vuln.Affected[5].GetRanges()) + if len(vuln.Affected[2].GetRanges()[0].GetEvents()) != 2 { + t.Errorf("AddPkgInfo has not correctly added distinct range events from versions: %+v", vuln.Affected[3].GetRanges()) } - // testPkgInfoEcoMultiple ^^^^^^^^^^^^^ + // testPkgInfoEcoMultiple ^^^^^^^^^^^^ for _, a := range vuln.Affected { perRepoZeroIntroducedCommitHashCount := make(map[string]int) From ce74e18218d9179799f1d757bac2da3f481774d6 Mon Sep 17 00:00:00 2001 From: Jess Lowe Date: Thu, 6 Aug 2026 06:12:09 +0000 Subject: [PATCH 4/5] fix lint --- vulnfeeds/vulns/vulns.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vulnfeeds/vulns/vulns.go b/vulnfeeds/vulns/vulns.go index 592309ac3c6..1cdd98b1984 100644 --- a/vulnfeeds/vulns/vulns.go +++ b/vulnfeeds/vulns/vulns.go @@ -287,7 +287,7 @@ func (v *Vulnerability) AddPkgInfo(pkgInfo PackageInfo) { for _, av := range pkgInfo.VersionInfo.AffectedVersions { var introduced string if av.Introduced == "" { - if len(versionRange.Events) == 0 { + if len(versionRange.GetEvents()) == 0 { introduced = "0" } } else { From 48bb2bb2d476aedb9bc3a49f5419e9466ada5c10 Mon Sep 17 00:00:00 2001 From: Jess Lowe Date: Thu, 6 Aug 2026 23:47:32 +0000 Subject: [PATCH 5/5] edit testcase to cover merging vals --- vulnfeeds/vulns/vulns_test.go | 83 +++++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 19 deletions(-) diff --git a/vulnfeeds/vulns/vulns_test.go b/vulnfeeds/vulns/vulns_test.go index e94cb71acc2..c43c6a2af28 100644 --- a/vulnfeeds/vulns/vulns_test.go +++ b/vulnfeeds/vulns/vulns_test.go @@ -723,11 +723,31 @@ func TestAddPkgInfo_MergeAffected(t *testing.T) { }, }) + // 4. Add PackageB in EcosystemA again with no introduced + vuln.AddPkgInfo(PackageInfo{ + PkgName: "PackageB", + Ecosystem: "EcosystemA", + VersionInfo: models.VersionInfo{ + AffectedVersions: []models.AffectedVersion{ + {Fixed: "2.1.0"}, + }, + }, + }) + if len(vuln.Affected) != 2 { t.Fatalf("Expected 2 affected entries, got %d", len(vuln.Affected)) } - // Find PackageA + expectedEvents := []struct { + Introduced string + Fixed string + }{ + {Introduced: "1.0.0"}, + {Fixed: "1.1.0"}, + {Fixed: "2.1.0"}, + } + + // Find and verify PackageA var pkgA *osvschema.Affected for _, a := range vuln.Affected { if a.GetPackage().GetName() == "PackageA" && a.GetPackage().GetEcosystem() == "EcosystemA" { @@ -741,38 +761,63 @@ func TestAddPkgInfo_MergeAffected(t *testing.T) { } // Check ranges for PackageA - // It should be a single range of type ECOSYSTEM if len(pkgA.GetRanges()) != 1 { t.Fatalf("Expected 1 range for PackageA, got %d", len(pkgA.GetRanges())) } - r := pkgA.GetRanges()[0] - if r.GetType() != osvschema.Range_ECOSYSTEM { - t.Errorf("Expected range type ECOSYSTEM, got %v", r.GetType()) + rA := pkgA.GetRanges()[0] + if rA.GetType() != osvschema.Range_ECOSYSTEM { + t.Errorf("Expected range type ECOSYSTEM for PackageA, got %v", rA.GetType()) } - // It should have merged events - // Expected: Introduced "1.0.0", Fixed "1.1.0", Fixed "2.1.0" - if len(r.GetEvents()) != 3 { - t.Errorf("Expected 3 events for PackageA, got %d", len(r.GetEvents())) + if len(rA.GetEvents()) != 3 { + t.Errorf("Expected 3 events for PackageA, got %d", len(rA.GetEvents())) } - expectedEvents := []struct { - Introduced string - Fixed string - }{ - {Introduced: "1.0.0"}, - {Fixed: "1.1.0"}, - {Fixed: "2.1.0"}, + for i, e := range rA.GetEvents() { + if i >= len(expectedEvents) { + t.Errorf("Unexpected event at index %d for PackageA: %+v", i, e) + continue + } + if expectedEvents[i].Introduced != e.GetIntroduced() || expectedEvents[i].Fixed != e.GetFixed() { + t.Errorf("Event at index %d mismatch for PackageA: got %+v, want %+v", i, e, expectedEvents[i]) + } + } + + // Find and verify PackageB + var pkgB *osvschema.Affected + for _, a := range vuln.Affected { + if a.GetPackage().GetName() == "PackageB" && a.GetPackage().GetEcosystem() == "EcosystemA" { + pkgB = a + break + } + } + + if pkgB == nil { + t.Fatalf("Could not find PackageB in EcosystemA") + } + + // Check ranges for PackageB + if len(pkgB.GetRanges()) != 1 { + t.Fatalf("Expected 1 range for PackageB, got %d", len(pkgB.GetRanges())) + } + + rB := pkgB.GetRanges()[0] + if rB.GetType() != osvschema.Range_ECOSYSTEM { + t.Errorf("Expected range type ECOSYSTEM for PackageB, got %v", rB.GetType()) + } + + if len(rB.GetEvents()) != 3 { + t.Errorf("Expected 3 events for PackageB, got %d", len(rB.GetEvents())) } - for i, e := range r.GetEvents() { + for i, e := range rB.GetEvents() { if i >= len(expectedEvents) { - t.Errorf("Unexpected event at index %d: %+v", i, e) + t.Errorf("Unexpected event at index %d for PackageB: %+v", i, e) continue } if expectedEvents[i].Introduced != e.GetIntroduced() || expectedEvents[i].Fixed != e.GetFixed() { - t.Errorf("Event at index %d mismatch: got %+v, want %+v", i, e, expectedEvents[i]) + t.Errorf("Event at index %d mismatch for PackageB: got %+v, want %+v", i, e, expectedEvents[i]) } } }