vulncheck: ignore withdrawn vulnerabilities

Fixes golang/go#56181

Change-Id: I4f5dd44a664310e18dccbbde0a893d77b247da2e
Reviewed-on: https://go-review.googlesource.com/c/vuln/+/442498
Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Zvonimir Pavlinovic <zpavlinovic@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/vulncheck/vulncheck.go b/vulncheck/vulncheck.go
index b60abe9..77d45c0 100644
--- a/vulncheck/vulncheck.go
+++ b/vulncheck/vulncheck.go
@@ -10,6 +10,7 @@
 	"go/token"
 	"go/types"
 	"strings"
+	"time"
 
 	"golang.org/x/exp/slices"
 	"golang.org/x/tools/go/packages"
@@ -310,6 +311,7 @@
 }
 
 func (mv moduleVulnerabilities) filter(os, arch string) moduleVulnerabilities {
+	now := time.Now()
 	var filteredMod moduleVulnerabilities
 	for _, mod := range mv {
 		module := mod.mod
@@ -320,6 +322,11 @@
 		// TODO(https://golang.org/issues/49264): if modVersion == "", try vcs?
 		var filteredVulns []*osv.Entry
 		for _, v := range mod.vulns {
+			// Ignore vulnerabilities that have been withdrawn
+			if v.Withdrawn != nil && v.Withdrawn.Before(now) {
+				continue
+			}
+
 			var filteredAffected []osv.Affected
 			for _, a := range v.Affected {
 				// Vulnerabilities from some databases might contain
diff --git a/vulncheck/vulncheck_test.go b/vulncheck/vulncheck_test.go
index 689c7c5..3412553 100644
--- a/vulncheck/vulncheck_test.go
+++ b/vulncheck/vulncheck_test.go
@@ -8,6 +8,7 @@
 	"path"
 	"reflect"
 	"testing"
+	"time"
 
 	"github.com/google/go-cmp/cmp"
 	"golang.org/x/tools/go/packages/packagestest"
@@ -16,6 +17,7 @@
 )
 
 func TestFilterVulns(t *testing.T) {
+	past := time.Now().Add(-3 * time.Hour)
 	mv := moduleVulnerabilities{
 		{
 			mod: &Module{
@@ -111,6 +113,28 @@
 				}},
 			},
 		},
+		{
+			mod: &Module{
+				Path:    "example.mod/w",
+				Version: "v1.3.0",
+			},
+			vulns: []*osv.Entry{
+				{ID: "m", Withdrawn: &past, Affected: []osv.Affected{ // should be filtered out
+					{Package: osv.Package{Name: "example.mod/w"}, EcosystemSpecific: osv.EcosystemSpecific{
+						Imports: []osv.EcosystemSpecificImport{{
+							GOOS: []string{"linux"},
+						}},
+					}},
+				}},
+				{ID: "n", Affected: []osv.Affected{
+					{Package: osv.Package{Name: "example.mod/w"}, EcosystemSpecific: osv.EcosystemSpecific{
+						Imports: []osv.EcosystemSpecificImport{{
+							GOOS: []string{"linux"},
+						}},
+					}},
+				}},
+			},
+		},
 	}
 
 	expected := moduleVulnerabilities{
@@ -164,6 +188,21 @@
 				}}}},
 			},
 		},
+		{
+			mod: &Module{
+				Path:    "example.mod/w",
+				Version: "v1.3.0",
+			},
+			vulns: []*osv.Entry{
+				{ID: "n", Affected: []osv.Affected{
+					{Package: osv.Package{Name: "example.mod/w"}, EcosystemSpecific: osv.EcosystemSpecific{
+						Imports: []osv.EcosystemSpecificImport{{
+							GOOS: []string{"linux"},
+						}},
+					}},
+				}},
+			},
+		},
 	}
 
 	filtered := mv.filter("linux", "amd64")