internal/proxy, cmd/vulnreport: fix infinite loop on root module paths Prevent FindModule from looping indefinitely when path is "/" or contains a leading slash where path.Dir returns itself. Also ignore standalone slashes in vulnreport issue title parsing. Change-Id: I76f19ab826d4816a949686079fdd7f25009c0bba Reviewed-on: https://go-review.googlesource.com/c/vulndb/+/821280 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/cmd/vulnreport/creator.go b/cmd/vulnreport/creator.go index e7d601d..d2fb67a 100644 --- a/cmd/vulnreport/creator.go +++ b/cmd/vulnreport/creator.go
@@ -9,6 +9,7 @@ "fmt" "net/http" "os" + "regexp" "slices" "strings" @@ -319,21 +320,22 @@ return "" } +var modulePathRegexp = regexp.MustCompile(`^"?([[:alpha:]][\w./-]*[./][\w-]+)"?:?$`) + func modulePath(iss *issues.Issue) string { - for _, p := range strings.Fields(iss.Title) { + for p := range strings.FieldsSeq(iss.Title) { if p == "x/vulndb:" { continue } - if strings.HasSuffix(p, ":") || strings.Contains(p, "/") { - // Remove backslashes. - return strings.ReplaceAll(strings.TrimSuffix(p, ":"), "\"", "") + if m := modulePathRegexp.FindStringSubmatch(p); len(m) > 1 { + return m[1] } } return "" } func aliases(iss *issues.Issue) (aliases []string) { - for _, p := range strings.Fields(iss.Title) { + for p := range strings.FieldsSeq(iss.Title) { if idstr.IsAliasType(p) { aliases = append(aliases, strings.TrimSuffix(p, ",")) } @@ -417,7 +419,8 @@ todos := []*report.Reference{ {Type: osv.ReferenceTypeAdvisory, URL: "TODO: canonical security advisory"}, {Type: osv.ReferenceTypeReport, URL: "TODO: issue tracker link"}, - {Type: osv.ReferenceTypeFix, URL: "TODO: PR or commit (commit preferred)"}} + {Type: osv.ReferenceTypeFix, URL: "TODO: PR or commit (commit preferred)"}, + } types := make(map[osv.ReferenceType]bool) for _, r := range r.References {
diff --git a/cmd/vulnreport/vulnreport_test.go b/cmd/vulnreport/vulnreport_test.go index 4414354..31ba3c8 100644 --- a/cmd/vulnreport/vulnreport_test.go +++ b/cmd/vulnreport/vulnreport_test.go
@@ -6,6 +6,8 @@ import ( "testing" + + "golang.org/x/vulndb/internal/issues" ) func TestCreate(t *testing.T) { @@ -30,6 +32,51 @@ } } +func TestModulePath(t *testing.T) { + testCases := []struct { + title string + want string + }{ + { + title: "x/vulndb: potential Go vuln in github.com/foo/bar: GHSA-xxxx", + want: "github.com/foo/bar", + }, + { + title: "x/vulndb: update fixed versions for GO-2026-4513 / duplicate GO-2026-4740", + want: "", + }, + { + title: "x/vulndb: potential Go vuln in crypto/tls: CVE-2025-0001", + want: "crypto/tls", + }, + { + title: `x/vulndb: potential Go vuln in "github.com/foo/bar": GHSA-xxxx`, + want: "github.com/foo/bar", + }, + { + title: "x/vulndb: potential Go vuln in collectd.org: CVE-2021-0000", + want: "collectd.org", + }, + { + title: "x/vulndb: potential Go vuln in 1234/foo: GHSA-xxxx", + want: "", + }, + { + title: "x/vulndb: potential Go vuln in 4.15.2/foo: GHSA-xxxx", + want: "", + }, + } + + for _, tc := range testCases { + t.Run(tc.title, func(t *testing.T) { + iss := &issues.Issue{Title: tc.title} + if got := modulePath(iss); got != tc.want { + t.Errorf("modulePath(%q) = %q, want %q", tc.title, got, tc.want) + } + }) + } +} + func TestCreateExcluded(t *testing.T) { for _, tc := range []*testCase{ // TODO(tatianabradley): add test cases
diff --git a/internal/proxy/proxy.go b/internal/proxy/proxy.go index 13d019a..ad22111 100644 --- a/internal/proxy/proxy.go +++ b/internal/proxy/proxy.go
@@ -258,10 +258,15 @@ func (c *Client) FindModule(path string) (modPath string, err error) { derrors.Wrap(&err, "FindModule(%s)", path) - for candidate := path; candidate != "."; candidate = urlpath.Dir(candidate) { + for candidate := path; candidate != "." && candidate != "/"; { if c.ModuleExists(candidate) { return candidate, nil } + next := urlpath.Dir(candidate) + if next == candidate { + break + } + candidate = next } return "", errNoModuleFound
diff --git a/internal/proxy/proxy_test.go b/internal/proxy/proxy_test.go index 4261a81..23f0702 100644 --- a/internal/proxy/proxy_test.go +++ b/internal/proxy/proxy_test.go
@@ -286,6 +286,21 @@ path: "github.com/RobotsAndPencils/go-saml/util", want: "github.com/RobotsAndPencils/go-saml", }, + { + name: "slash path", + path: "/", + wantErr: errNoModuleFound, + }, + { + name: "leading slash path", + path: "/foo/bar", + wantErr: errNoModuleFound, + }, + { + name: "empty path", + path: "", + wantErr: errNoModuleFound, + }, } for _, tc := range tcs {