From c375e3283b7718ab7da00ae9410081dc1bb48c59 Mon Sep 17 00:00:00 2001 From: Rafi Date: Fri, 8 Aug 2025 14:12:05 +0200 Subject: [PATCH 1/3] Add method to retrieve vulnerabilities from other asset versions Signed-off-by: Rafi --- .../core/assetversion/asset_version_service.go | 10 +++++----- internal/core/common_interfaces.go | 1 + .../repositories/dependency_vuln_repository.go | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/internal/core/assetversion/asset_version_service.go b/internal/core/assetversion/asset_version_service.go index 19137de65..bfa487dae 100644 --- a/internal/core/assetversion/asset_version_service.go +++ b/internal/core/assetversion/asset_version_service.go @@ -428,13 +428,13 @@ func (s *service) handleScanResult(userID string, scannerID string, assetVersion slog.Error("could not get existing dependencyVulns", "err", err) return []models.DependencyVuln{}, []models.DependencyVuln{}, []models.DependencyVuln{}, err } - // get all vulns from the default branch - existingVulnsOnDefaultBranch, err := s.dependencyVulnRepository.GetDependencyVulnsByDefaultAssetVersion(nil, assetVersion.AssetID, "") + // get all vulns from other branches + existingVulnsOnOtherBranch, err := s.dependencyVulnRepository.GetDependencyVulnsByOtherAssetVersions(nil, assetVersion.Name, assetVersion.AssetID, scannerID) if err != nil { slog.Error("could not get existing dependencyVulns on default branch", "err", err) return []models.DependencyVuln{}, []models.DependencyVuln{}, []models.DependencyVuln{}, err } - existingVulnsOnDefaultBranch = utils.Filter(existingVulnsOnDefaultBranch, func(dependencyVuln models.DependencyVuln) bool { + existingVulnsOnOtherBranch = utils.Filter(existingVulnsOnOtherBranch, func(dependencyVuln models.DependencyVuln) bool { return dependencyVuln.State != models.VulnStateFixed }) @@ -445,10 +445,10 @@ func (s *service) handleScanResult(userID string, scannerID string, assetVersion newDetectedVulns, fixedVulns, firstTimeDetectedByCurrentScanner, notDetectedByCurrentScannerAnymore := diffScanResults(scannerID, dependencyVulns, existingDependencyVulns) - newDetectedVulnsNotOnDefaultBranch, newDetectedButOnDefaultBranchExisting, existingEvents := diffVulnsBetweenBranches(scannerID, newDetectedVulns, existingVulnsOnDefaultBranch) + newDetectedVulnsNotOnDefaultBranch, newDetectedButOnOtherBranchExisting, existingEvents := diffVulnsBetweenBranches(scannerID, newDetectedVulns, existingVulnsOnOtherBranch) if err := s.dependencyVulnRepository.Transaction(func(tx core.DB) error { - if err := s.dependencyVulnService.UserDetectedExistingVulnOnDifferentBranch(tx, scannerID, newDetectedButOnDefaultBranchExisting, existingEvents, *assetVersion, asset); err != nil { + if err := s.dependencyVulnService.UserDetectedExistingVulnOnDifferentBranch(tx, scannerID, newDetectedButOnOtherBranchExisting, existingEvents, *assetVersion, asset); err != nil { slog.Error("error when trying to add events for existing vulnerability on different branch") return err // this will cancel the transaction } diff --git a/internal/core/common_interfaces.go b/internal/core/common_interfaces.go index 23d881998..80fd83592 100644 --- a/internal/core/common_interfaces.go +++ b/internal/core/common_interfaces.go @@ -151,6 +151,7 @@ type DependencyVulnRepository interface { ListUnfixedByAssetAndAssetVersionAndScannerID(assetVersionName string, assetID uuid.UUID, scannerID string) ([]models.DependencyVuln, error) GetHintsInOrganizationForVuln(tx DB, orgID uuid.UUID, pURL string, cveID string) (common.DependencyVulnHints, error) GetAllByAssetIDAndState(tx DB, assetID uuid.UUID, state models.VulnState, durationSinceStateChange time.Duration) ([]models.DependencyVuln, error) + GetDependencyVulnsByOtherAssetVersions(tx DB, assetVersionName string, assetID uuid.UUID, scannerID string) ([]models.DependencyVuln, error) } type FirstPartyVulnRepository interface { diff --git a/internal/database/repositories/dependency_vuln_repository.go b/internal/database/repositories/dependency_vuln_repository.go index e12aa2998..9efc296db 100644 --- a/internal/database/repositories/dependency_vuln_repository.go +++ b/internal/database/repositories/dependency_vuln_repository.go @@ -71,6 +71,22 @@ func (repository *dependencyVulnRepository) GetDependencyVulnsByAssetVersion(tx return dependencyVulns, nil } +func (repository *dependencyVulnRepository) GetDependencyVulnsByOtherAssetVersions(tx core.DB, assetVersionName string, assetID uuid.UUID, scannerID string) ([]models.DependencyVuln, error) { + var dependencyVulns = []models.DependencyVuln{} + + q := repository.Repository.GetDB(tx).Preload("Events").Preload("CVE").Preload("CVE.Exploits").Where("asset_id = ? AND asset_version_name != ?", assetID, assetVersionName) + + if scannerID != "" { + // scanner ids is a string array separated by whitespaces + q = q.Where("? = ANY(string_to_array(scanner_ids, ' '))", scannerID) + } + + if err := q.Find(&dependencyVulns).Error; err != nil { + return nil, err + } + return dependencyVulns, nil +} + func (repository *dependencyVulnRepository) GetDependencyVulnsByDefaultAssetVersion(tx core.DB, assetID uuid.UUID, scannerID string) ([]models.DependencyVuln, error) { subQuery := repository.Repository.GetDB(tx).Model(&models.AssetVersion{}).Select("name").Where("asset_id IN (?) AND default_branch = ?", assetID, true) From 7d137556a2c05db36870ef61821e55a56ef1760c Mon Sep 17 00:00:00 2001 From: Rafi Date: Fri, 8 Aug 2025 14:22:38 +0200 Subject: [PATCH 2/3] fix mocks Signed-off-by: Rafi --- mocks/mock_DependencyVulnRepository.go | 80 ++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/mocks/mock_DependencyVulnRepository.go b/mocks/mock_DependencyVulnRepository.go index 279af790a..0edeba8a4 100644 --- a/mocks/mock_DependencyVulnRepository.go +++ b/mocks/mock_DependencyVulnRepository.go @@ -1300,6 +1300,86 @@ func (_c *DependencyVulnRepository_GetDependencyVulnsByDefaultAssetVersion_Call) return _c } +// GetDependencyVulnsByOtherAssetVersions provides a mock function for the type DependencyVulnRepository +func (_mock *DependencyVulnRepository) GetDependencyVulnsByOtherAssetVersions(tx core.DB, assetVersionName string, assetID uuid.UUID, scannerID string) ([]models.DependencyVuln, error) { + ret := _mock.Called(tx, assetVersionName, assetID, scannerID) + + if len(ret) == 0 { + panic("no return value specified for GetDependencyVulnsByOtherAssetVersions") + } + + var r0 []models.DependencyVuln + var r1 error + if returnFunc, ok := ret.Get(0).(func(core.DB, string, uuid.UUID, string) ([]models.DependencyVuln, error)); ok { + return returnFunc(tx, assetVersionName, assetID, scannerID) + } + if returnFunc, ok := ret.Get(0).(func(core.DB, string, uuid.UUID, string) []models.DependencyVuln); ok { + r0 = returnFunc(tx, assetVersionName, assetID, scannerID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]models.DependencyVuln) + } + } + if returnFunc, ok := ret.Get(1).(func(core.DB, string, uuid.UUID, string) error); ok { + r1 = returnFunc(tx, assetVersionName, assetID, scannerID) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// DependencyVulnRepository_GetDependencyVulnsByOtherAssetVersions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetDependencyVulnsByOtherAssetVersions' +type DependencyVulnRepository_GetDependencyVulnsByOtherAssetVersions_Call struct { + *mock.Call +} + +// GetDependencyVulnsByOtherAssetVersions is a helper method to define mock.On call +// - tx core.DB +// - assetVersionName string +// - assetID uuid.UUID +// - scannerID string +func (_e *DependencyVulnRepository_Expecter) GetDependencyVulnsByOtherAssetVersions(tx interface{}, assetVersionName interface{}, assetID interface{}, scannerID interface{}) *DependencyVulnRepository_GetDependencyVulnsByOtherAssetVersions_Call { + return &DependencyVulnRepository_GetDependencyVulnsByOtherAssetVersions_Call{Call: _e.mock.On("GetDependencyVulnsByOtherAssetVersions", tx, assetVersionName, assetID, scannerID)} +} + +func (_c *DependencyVulnRepository_GetDependencyVulnsByOtherAssetVersions_Call) Run(run func(tx core.DB, assetVersionName string, assetID uuid.UUID, scannerID string)) *DependencyVulnRepository_GetDependencyVulnsByOtherAssetVersions_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 core.DB + if args[0] != nil { + arg0 = args[0].(core.DB) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 uuid.UUID + if args[2] != nil { + arg2 = args[2].(uuid.UUID) + } + var arg3 string + if args[3] != nil { + arg3 = args[3].(string) + } + run( + arg0, + arg1, + arg2, + arg3, + ) + }) + return _c +} + +func (_c *DependencyVulnRepository_GetDependencyVulnsByOtherAssetVersions_Call) Return(dependencyVulns []models.DependencyVuln, err error) *DependencyVulnRepository_GetDependencyVulnsByOtherAssetVersions_Call { + _c.Call.Return(dependencyVulns, err) + return _c +} + +func (_c *DependencyVulnRepository_GetDependencyVulnsByOtherAssetVersions_Call) RunAndReturn(run func(tx core.DB, assetVersionName string, assetID uuid.UUID, scannerID string) ([]models.DependencyVuln, error)) *DependencyVulnRepository_GetDependencyVulnsByOtherAssetVersions_Call { + _c.Call.Return(run) + return _c +} + // GetDependencyVulnsByPurl provides a mock function for the type DependencyVulnRepository func (_mock *DependencyVulnRepository) GetDependencyVulnsByPurl(tx core.DB, purls []string) ([]models.DependencyVuln, error) { ret := _mock.Called(tx, purls) From 40b67cf301041b5fd0e4276139a57b7b1e3ba746 Mon Sep 17 00:00:00 2001 From: Rafi Date: Fri, 8 Aug 2025 14:41:52 +0200 Subject: [PATCH 3/3] fix testing Signed-off-by: Rafi --- internal/core/vulndb/scan/scan_integration_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/core/vulndb/scan/scan_integration_test.go b/internal/core/vulndb/scan/scan_integration_test.go index c8d2a0d2a..95bbef890 100644 --- a/internal/core/vulndb/scan/scan_integration_test.go +++ b/internal/core/vulndb/scan/scan_integration_test.go @@ -186,7 +186,7 @@ func TestScanning(t *testing.T) { sbomFile := sbomWithVulnerability() req := httptest.NewRequest("POST", "/vulndb/scan/normalized-sboms", sbomFile) req.Header.Set("Content-Type", "application/json") - req.Header.Set("X-Scanner", "scanner-4") + req.Header.Set("X-Scanner", vulns[0].ScannerIDs) req.Header.Set("X-Asset-Ref", "some-other-branch") ctx := app.NewContext(req, recorder) setupContext(ctx) //setup context