diff --git a/internal/vulncheck/emit.go b/internal/vulncheck/emit.go index ce60eab..bceecd4 100644 --- a/internal/vulncheck/emit.go +++ b/internal/vulncheck/emit.go @@ -41,6 +41,33 @@ func emitModuleFindings(handler govulncheck.Handler, affVulns affectingVulns) er return nil } +// emitPackageFinding emits package-level findings fod vulnerabilities in vulns. +// +// It does not emit imported symbols. Only the package information is emitted. +func emitPackageFindings(handler govulncheck.Handler, vulns []*Vuln) error { + emitted := make(map[Vuln]bool) + for _, vuln := range vulns { + v := Vuln{ + Package: vuln.Package, + OSV: vuln.OSV, + } + if emitted[v] { + // do not emit the same finding all over again + continue + } + emitted[v] = true + + if err := handler.Finding(&govulncheck.Finding{ + OSV: v.OSV.ID, + FixedVersion: FixedVersion(modPath(v.Package.Module), modVersion(v.Package.Module), v.OSV.Affected), + Trace: []*govulncheck.Frame{frameFromPackage(v.Package)}, + }); err != nil { + return err + } + } + return nil +} + // emitCallFindings emits call-level findings for vulnerabilities // that have a call stack in callstacks. func emitCallFindings(handler govulncheck.Handler, callstacks map[*Vuln]CallStack) error { @@ -70,14 +97,6 @@ func emitCallFindings(handler govulncheck.Handler, callstacks map[*Vuln]CallStac return nil } -func emitPackageFinding(handler govulncheck.Handler, vuln *Vuln) error { - return handler.Finding(&govulncheck.Finding{ - OSV: vuln.OSV.ID, - FixedVersion: FixedVersion(modPath(vuln.Package.Module), modVersion(vuln.Package.Module), vuln.OSV.Affected), - Trace: []*govulncheck.Frame{frameFromPackage(vuln.Package)}, - }) -} - // tracefromEntries creates a sequence of // frames from vcs. Position of a Frame is the // call position of the corresponding stack entry. diff --git a/internal/vulncheck/source.go b/internal/vulncheck/source.go index 88f5c93..67cb9a7 100644 --- a/internal/vulncheck/source.go +++ b/internal/vulncheck/source.go @@ -81,7 +81,13 @@ func source(ctx context.Context, handler govulncheck.Handler, pkgs []*packages.P return result, nil } - importedVulnSymbols(pkgs, affVulns, result, handler) + importedVulnSymbols(pkgs, affVulns, result) + // Emit information on imported vulnerable packages now as + // call graph computation might take a while. + if err := emitPackageFindings(handler, result.Vulns); err != nil { + return nil, err + } + // Return result immediately if not in symbol mode or // if there are no vulnerabilities imported. if !cfg.ScanLevel.WantSymbols() || len(result.Vulns) == 0 { @@ -98,7 +104,7 @@ func source(ctx context.Context, handler govulncheck.Handler, pkgs []*packages.P } // importedVulnSymbols detects imported vulnerable symbols. -func importedVulnSymbols(pkgs []*packages.Package, affVulns affectingVulns, result *Result, handler govulncheck.Handler) { +func importedVulnSymbols(pkgs []*packages.Package, affVulns affectingVulns, result *Result) { analyzed := make(map[*packages.Package]bool) // skip analyzing the same package multiple times var vulnImports func(pkg *packages.Package) vulnImports = func(pkg *packages.Package) { @@ -119,10 +125,6 @@ func importedVulnSymbols(pkgs []*packages.Package, affVulns affectingVulns, resu if len(symbols) == 0 { symbols = allSymbols(pkg.Types) } - emitPackageFinding(handler, &Vuln{ - OSV: osv, - Package: pkg, - }) for _, symbol := range symbols { vuln := &Vuln{ OSV: osv,