vulndb/govulncheck: make extractModules output unique

For large projects, such as k8s, the number of modules different in
memory but with the same import path can be large. This can result in
many db queries for the same import path, which can be a problem if the
db is remote and no caching is turned on. This CL optimizes the loading
by making sure module extraction returns the same module up to import
paths.

This CL also updates the dependencies on vulndb.

Change-Id: I63f09382e318fa33f7e9280c8cc1ddb5694983b7
Reviewed-on: https://go-review.googlesource.com/c/exp/+/342110
Trust: Zvonimir Pavlinovic <zpavlinovic@google.com>
Run-TryBot: Zvonimir Pavlinovic <zpavlinovic@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
diff --git a/vulndb/go.mod b/vulndb/go.mod
index dfd0a60..28f5166 100644
--- a/vulndb/go.mod
+++ b/vulndb/go.mod
@@ -4,7 +4,7 @@
 
 require (
 	golang.org/x/tools v0.1.4-0.20210618183400-d25f90668280
-	golang.org/x/vulndb v0.0.0-20210709184646-3361bb77ec41
+	golang.org/x/vulndb v0.0.0-20210812203154-5d84be3c9e14
 )
 
 require (
diff --git a/vulndb/go.sum b/vulndb/go.sum
index a0670ca..1ee3c60 100644
--- a/vulndb/go.sum
+++ b/vulndb/go.sum
@@ -24,8 +24,8 @@
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.1.4-0.20210618183400-d25f90668280 h1:bvZzMlhjbBrvAqAeuknuBOeOUnTHzR5zqg+y2mrOGKY=
 golang.org/x/tools v0.1.4-0.20210618183400-d25f90668280/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/vulndb v0.0.0-20210709184646-3361bb77ec41 h1:METXr+o1U7KGuNxQW40bfHFnFG/KhF2M1bkRujWUoo0=
-golang.org/x/vulndb v0.0.0-20210709184646-3361bb77ec41/go.mod h1:zjTClCE7c55KnXf1MqfecbAQyuVrc24QEcrThAnl3A0=
+golang.org/x/vulndb v0.0.0-20210812203154-5d84be3c9e14 h1:fGz1pt31Ygv69LkbU9kkWMChI2ZPUeZ/IzqEce/NA7s=
+golang.org/x/vulndb v0.0.0-20210812203154-5d84be3c9e14/go.mod h1:xh7j0yEDggyETQM2RIfHFmzOcnAwzHg8j8heomkN1Dc=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/vulndb/govulncheck/main.go b/vulndb/govulncheck/main.go
index 9248d6a..092ce4c 100644
--- a/vulndb/govulncheck/main.go
+++ b/vulndb/govulncheck/main.go
@@ -148,16 +148,25 @@
 	r.presentTo(os.Stdout)
 }
 
+// extractModules collects modules in `pkgs` up to uniqueness of
+// module path and version.
 func extractModules(pkgs []*packages.Package) []*packages.Module {
-	modMap := map[*packages.Module]bool{}
+	modMap := map[string]*packages.Module{}
+	modKey := func(mod *packages.Module) string {
+		if mod.Replace != nil {
+			return fmt.Sprintf("%s@%s", mod.Replace.Path, mod.Replace.Version)
+		}
+		return fmt.Sprintf("%s@%s", mod.Path, mod.Version)
+	}
+
 	seen := map[*packages.Package]bool{}
-	var extract func(*packages.Package, map[*packages.Module]bool)
-	extract = func(pkg *packages.Package, modMap map[*packages.Module]bool) {
+	var extract func(*packages.Package, map[string]*packages.Module)
+	extract = func(pkg *packages.Package, modMap map[string]*packages.Module) {
 		if pkg == nil || seen[pkg] {
 			return
 		}
 		if pkg.Module != nil {
-			modMap[pkg.Module] = true
+			modMap[modKey(pkg.Module)] = pkg.Module
 		}
 		seen[pkg] = true
 		for _, imp := range pkg.Imports {
@@ -167,8 +176,9 @@
 	for _, pkg := range pkgs {
 		extract(pkg, modMap)
 	}
+
 	modules := []*packages.Module{}
-	for mod := range modMap {
+	for _, mod := range modMap {
 		modules = append(modules, mod)
 	}
 	return modules