Repository: google/osv-scanner
Pull request #431 (2023-07-02 20:14:08)

update govulncheck integration

julieqiu: > Thanks! Implementation looks good!, can you move the deleted test-project fixtures into sourceanalysis so we can still have the integration test?

Added

Patch:
diff --git a/go.mod b/go.mod
index 2b8d94b..55e959c 100644
--- a/go.mod
+++ b/go.mod
@@ -19,7 +19,7 @@ require (
 	golang.org/x/sync v0.3.0
 	golang.org/x/term v0.9.0
 	golang.org/x/tools v0.10.0
-	golang.org/x/vuln v0.0.0-20230303230808-d3042fecc4e3
+	golang.org/x/vuln v0.2.1-0.20230630202714-a443f34b1a4a
 	gopkg.in/yaml.v3 v3.0.1
 )
 
diff --git a/go.sum b/go.sum
index 41f9126..a2291d6 100644
--- a/go.sum
+++ b/go.sum
@@ -169,6 +169,8 @@ golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg=
 golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM=
 golang.org/x/vuln v0.0.0-20230303230808-d3042fecc4e3 h1:9GJsAwSzB/ztwMwsEm3ihUgCXHCULbNsubxqIrdKa44=
 golang.org/x/vuln v0.0.0-20230303230808-d3042fecc4e3/go.mod h1:LTLnfk/dpXDNKsX6aCg/cI4LyCVnTyrQhgV/yLJuly0=
+golang.org/x/vuln v0.2.1-0.20230630202714-a443f34b1a4a h1:lWjZIBGEop6+ED8P8qyyKkbZ8sdOxw6n+jGtlgN6V3g=
+golang.org/x/vuln v0.2.1-0.20230630202714-a443f34b1a4a/go.mod h1:V0eyhHwaAaHrt42J9bgrN6rd12f6GU4T0Lu0ex2wDg4=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/internal/govulncheckshim/client.go b/internal/govulncheckshim/client.go
deleted file mode 100644
index d1740d3..0000000
--- a/internal/govulncheckshim/client.go
+++ /dev/null
@@ -1,121 +0,0 @@
-package govulncheckshim
-
-import (
-	"context"
-	"encoding/json"
-	"fmt"
-	"time"
-
-	"golang.org/x/vuln/client"
-	gvcOSV "golang.org/x/vuln/osv"
-
-	"github.com/google/osv-scanner/pkg/models"
-)
-
-type localSource struct {
-	vulnList         []models.Vulnerability
-	vulnsByID        map[string]*models.Vulnerability
-	vulnsByAlias     map[string][]*models.Vulnerability
-	vulnsByModule    map[string][]*models.Vulnerability
-	lastModifiedTime time.Time
-	client.Client
-}
-
-func newClient(vulns []models.Vulnerability) *localSource {
-	client := localSource{
-		vulnList:         vulns,
-		vulnsByID:        make(map[string]*models.Vulnerability),
-		vulnsByAlias:     make(map[string][]*models.Vulnerability),
-		vulnsByModule:    make(map[string][]*models.Vulnerability),
-		lastModifiedTime: time.Unix(0, 0),
-	}
-	for idx := range vulns {
-		// Iterate on reference to avoid copying entire data structure
-		v := &client.vulnList[idx]
-		client.vulnsByID[v.ID] = v
-		for _, alias := range v.Aliases {
-			client.vulnsByAlias[alias] = append(client.vulnsByAlias[alias], v)
-		}
-		for _, affected := range v.Affected {
-			client.vulnsByModule[affected.Package.Name] = append(client.vulnsByModule[affected.Package.Name], v)
-		}
-		if client.lastModifiedTime.Before(v.Modified) {
-			client.lastModifiedTime = v.Modified
-		}
-	}
-
-	return &client
-}
-
-func convertToGvcOSV(osv models.Vulnerability) (gvcOSV.Entry, error) {
-	val, err := json.Marshal(osv)
-	if err != nil {
-		return gvcOSV.Entry{}, fmt.Errorf("failed to convert vuln to JSON: %w", err)
-	}
-	response := gvcOSV.Entry{}
-	err = json.Unmarshal(val, &response)
-	if err != nil {
-		return gvcOSV.Entry{}, fmt.Errorf("gvc format is no longer compatible with osv format: %w", err)
-	}
-
-	return response, nil
-}
-
-func (ls *localSource) GetByModule(ctx context.Context, modulePath string) ([]*gvcOSV.Entry, error) {
-	//nolint:prealloc // Need to be nil if none exists
-	var entries []*gvcOSV.Entry
-	for _, v := range ls.vulnsByModule[modulePath] {
-		res, err := convertToGvcOSV(*v)
-		if err != nil {
-			return nil, err
-		}
-		entries = append(entries, &res)
-	}
-
-	return entries, nil
-}
-
-func (ls *localSource) GetByID(ctx context.Context, id string) (*gvcOSV.Entry, error) {
-	entry, ok := ls.vulnsByID[id]
-	if !ok {
-		//nolint:nilnil // This follows govulncheck's client implementation
-		// See: https://github.com/golang/vuln/blob/master/client/client.go
-		return nil, nil
-	}
-	response, err := convertToGvcOSV(*entry)
-	if err != nil {
-		return nil, err
-	}
-
-	return &response, nil
-}
-
-func (ls *localSource) GetByAlias(ctx context.Context, alias string) ([]*gvcOSV.Entry, error) {
-	//nolint:prealloc // Need to be nil if none exists
-	var entries []*gvcOSV.Entry
-
-	for _, v := range ls.vulnsByAlias[alias] {
-		res, err := convertToGvcOSV(*v)
-		if err != nil {
-			return nil, err
-		}
-		entries = append(entries, &res)
-	}
-
-	return entries, nil
-}
-
-func (ls *localSource) ListIDs(ctx context.Context) ([]string, error) {
-	//nolint:prealloc // Need to be nil if none exists
-	var ids []string
-	for i := range ls.vulnList {
-		ids = append(ids, ls.vulnList[i].ID)
-	}
-
-	return ids, nil
-}
-
-func (ls *localSource) LastModifiedTime(context.Context) (time.Time, error) {
-	// Assume that if anything changes, the index does.
-	return ls.lastModifiedTime, nil
-}
diff --git a/internal/govulncheckshim/fixtures/client/GHSA-cx3w-xqmc-84g5.json b/internal/govulncheckshim/fixtures/client/GHSA-cx3w-xqmc-84g5.json
deleted file mode 100644
index e3b3e89..0000000
--- a/internal/govulncheckshim/fixtures/client/GHSA-cx3w-xqmc-84g5.json
+++ /dev/null
@@ -1,72 +0,0 @@
-{
-  "schema_version": "1.3.0",
-  "id": "GHSA-cx3w-xqmc-84g5",
-  "modified": "2022-04-20T16:24:41Z",
-  "published": "2022-02-15T00:30:37Z",
-  "aliases": [
-    "CVE-2021-21237"
-  ],
-  "summary": "Git LFS can execute a Git binary from the current directory on Windows",
-  "details": "### Impact\nOn Windows, if Git LFS operates on a malicious repository with a git.bat or git.exe file in the current directory, that program would be executed, permitting the attacker to execute arbitrary code. This does not affect Unix systems.\n\nThis is the result of an incomplete fix for CVE-2020-27955.\n\nThis issue occurs because on Windows, [Go includes (and prefers) the current directory when the name of a command run does not contain a directory separator](https://github.com/golang/go/issues/38736).\n\n### Patches\nThis version should be patched in v2.13.2, which will be released in coordination with this security advisory.\n\n### Workarounds\nOther than avoiding untrusted repositories or using a different operating system, there is no workaround.\n\n### References\n_Are there any links users can visit to find out more?_\n\n### For more information\nIf you have any questions or comments about this advisory:\n\n- Start a discussion in [the Git LFS discussion page](https://github.com/git-lfs/git-lfs/discussions).\n- If you cannot open a discussion, please email the core team using their usernames at `github.com`.",
-  "severity": [
-    {
-      "type": "CVSS_V3",
-      "score": "CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:N"
-    }
-  ],
-  "affected": [
-    {
-      "package": {
-        "ecosystem": "Go",
-        "name": "github.com/git-lfs/git-lfs"
-      },
-      "ranges": [
-        {
-          "type": "ECOSYSTEM",
-          "events": [
-            {
-              "introduced": "0"
-            },
-            {
-              "fixed": "2.13.2"
-            }
-          ]
-        }
-      ]
-    }
-  ],
-  "references": [
-    {
-      "type": "WEB",
-      "url": "https://github.com/git-lfs/git-lfs/security/advisories/GHSA-cx3w-xqmc-84g5"
-    },
-    {
-      "type": "ADVISORY",
-      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-21237"
-    },
-    {
-      "type": "WEB",
-      "url": "https://github.com/git-lfs/git-lfs/commit/fc664697ed2c2081ee9633010de0a7f9debea72a"
-    },
-    {
-      "type": "WEB",
-      "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-27955"
-    },
-    {
-      "type": "PACKAGE",
-      "url": "https://github.com/git-lfs/git-lfs"
-    },
-    {
-      "type": "WEB",
-      "url": "https://github.com/git-lfs/git-lfs/releases/tag/v2.13.2"
-    }
-  ],
-  "database_specific": {
-    "cwe_ids": [
-      "CWE-426",
-      "CWE-94"
-    ],
-    "severity": "HIGH",
-    "github_reviewed": true
-  }
-}
\ No newline at end of file
diff --git a/internal/govulncheckshim/fixtures/client/GHSA-vc3p-29h2-gpcp.json b/internal/govulncheckshim/fixtures/client/GHSA-vc3p-29h2-gpcp.json
deleted file mode 100644
index 8182957..0000000
--- a/internal/govulncheckshim/fixtures/client/GHSA-vc3p-29h2-gpcp.json
+++ /dev/null
@@ -1,85 +0,0 @@
-{
-  "schema_version": "1.3.0",
-  "id": "GHSA-vc3p-29h2-gpcp",
-  "modified": "2023-02-08T00:37:41Z",
-  "published": "2022-01-02T00:00:48Z",
-  "aliases": [
-    "CVE-2021-44716"
-  ],
-  "summary": "golang.org/x/net/http2 allows uncontrolled memory consumption",
-  "details": "net/http in Go before 1.16.12 and 1.17.x before 1.17.5 allows uncontrolled memory consumption in the header canonicalization cache via HTTP/2 requests.",
-  "severity": [
-    {
-      "type": "CVSS_V3",
-      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
-    }
-  ],
-  "affected": [
-    {
-      "package": {
-        "ecosystem": "Go",
-        "name": "golang.org/x/net/http2"
-      },
-      "ranges": [
-        {
-          "type": "ECOSYSTEM",
-          "events": [
-            {
-              "introduced": "0"
-            },
-            {
-              "fixed": "0.0.0-20211209124913-491a49abca63"
-            }
-          ]
-        }
-      ]
-    }
-  ],
-  "references": [
-    {
-      "type": "ADVISORY",
-      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-44716"
-    },
-    {
-      "type": "WEB",
-      "url": "https://go.dev/cl/369794"
-    },
-    {
-      "type": "WEB",
-      "url": "https://go.dev/issue/50058"
-    },
-    {
-      "type": "WEB",
-      "url": "https://groups.google.com/g/golang-announce/c/hcmEScgc00k"
-    },
-    {
-      "type": "WEB",
-      "url": "https://lists.debian.org/debian-lts-announce/2022/01/msg00016.html"
-    },
-    {
-      "type": "WEB",
-      "url": "https://lists.debian.org/debian-lts-announce/2022/01/msg00017.html"
-    },
-    {
-      "type": "WEB",
-      "url": "https://pkg.go.dev/vuln/GO-2022-0288"
-    },
-    {
-      "type": "WEB",
-      "url": "https://security.gentoo.org/glsa/202208-02"
-    },
-    {
-      "type": "WEB",
-      "url": "https://security.netapp.com/advisory/ntap-20220121-0002/"
-    }
-  ],
-  "database_specific": {
-    "cwe_ids": [
-      "CWE-400"
-    ],
-    "severity": "HIGH",
-    "github_reviewed": true,
-    "github_reviewed_at": "2023-02-08T00:37:41Z",
-    "nvd_published_at": "2022-01-01T05:15:00Z"
-  }
-}
\ No newline at end of file
diff --git a/internal/govulncheckshim/fixtures/client/GO-2021-0098.json b/internal/govulncheckshim/fixtures/client/GO-2021-0098.json
deleted file mode 100644
index 9018139..0000000
--- a/internal/govulncheckshim/fixtures/client/GO-2021-0098.json
+++ /dev/null
@@ -1,107 +0,0 @@
-{
-    "id": "GO-2021-0098",
-    "published": "2021-04-14T20:04:52Z",
-    "modified": "2023-02-07T16:05:32Z",
-    "aliases": [
-        "CVE-2021-21237",
-        "GHSA-cx3w-xqmc-84g5"
-    ],
-    "details": "Due to the standard library behavior of exec.LookPath on Windows a number of methods may result in arbitrary code execution when cloning or operating on untrusted Git repositories.",
-    "affected": [
-        {
-            "package": {
-                "name": "github.com/git-lfs/git-lfs",
-                "ecosystem": "Go"
-            },
-            "ranges": [
-                {
-                    "type": "SEMVER",
-                    "events": [
-                        {
-                            "introduced": "0"
-                        },
-                        {
-                            "fixed": "1.5.1-0.20210113180018-fc664697ed2c"
-                        }
-                    ]
-                }
-            ],
-            "database_specific": {
-                "url": "https://pkg.go.dev/vuln/GO-2021-0098"
-            },
-            "ecosystem_specific": {
-                "imports": [
-                    {
-                        "path": "github.com/git-lfs/git-lfs/commands",
-                        "goos": [
-                            "windows"
-                        ],
-                        "symbols": [
-                            "PipeCommand",
-                            "PipeMediaCommand",
-                            "Run",
-                            "lockVerifier.Verify",
-                            "singleCheckout.Run",
-                            "singleCheckout.RunToPath",
-                            "uploadContext.NewQueue",
-                            "uploadContext.UploadPointers"
-                        ]
-                    },
-                    {
-                        "path": "github.com/git-lfs/git-lfs/creds",
-                        "goos": [
-                            "windows"
-                        ],
-                        "symbols": [
-                            "AskPassCredentialHelper.Fill",
-                            "AskPassCredentialHelper.getFromProgram",
-                            "CredentialHelperWrapper.FillCreds",
-                            "CredentialHelpers.Approve",
-                            "CredentialHelpers.Fill",
-                            "commandCredentialHelper.Approve"
-                        ]
-                    },
-                    {
-                        "path": "github.com/git-lfs/git-lfs/lfs",
-                        "goos": [
-                            "windows"
-                        ],
-                        "symbols": [
-                            "GitFilter.Clean",
-                            "GitFilter.Smudge",
-                            "GitFilter.SmudgeToFile",
-                            "pipeExtensions"
-                        ]
-                    },
-                    {
-                        "path": "github.com/git-lfs/git-lfs/lfshttp",
-                        "goos": [
-                            "windows"
-                        ],
-                        "symbols": [
-                            "Client.Do",
-                            "Client.DoWithAccess",
-                            "Client.HttpClient",
-                            "Client.NewRequest",
-                            "Client.Transport",
-                            "sshAuthClient.Resolve",
-                            "sshCache.Resolve"
-                        ]
-                    }
-                ]
-            }
-        }
-    ],
-    "references": [
-        {
-            "type": "FIX",
-            "url": "https://github.com/git-lfs/git-lfs/commit/fc664697ed2c2081ee9633010de0a7f9debea72a"
-        }
-    ],
-    "credits": [
-        {
-            "name": "@Ry0taK"
-        }
-    ],
-    "schema_version": "1.3.1"
-}
\ No newline at end of file
diff --git a/internal/govulncheckshim/fixtures/client/GO-2022-0569.json b/internal/govulncheckshim/fixtures/client/GO-2022-0569.json
deleted file mode 100644
index 3991535..0000000
--- a/internal/govulncheckshim/fixtures/client/GO-2022-0569.json
+++ /dev/null
@@ -1,316 +0,0 @@
-{
-    "id": "GO-2022-0569",
-    "published": "2022-08-23T13:24:17Z",
-    "modified": "2023-02-07T16:05:55Z",
-    "aliases": [
-        "CVE-2022-31836",
-        "GHSA-95f9-94vc-665h"
-    ],
-    "details": "The leafInfo.match() function uses path.join() to deal with wildcard values which can lead to cross directory risk.",
-    "affected": [
-        {
-            "package": {
-                "name": "github.com/beego/beego",
-                "ecosystem": "Go"
-            },
-            "ranges": [
-                {
-                    "type": "SEMVER",
-                    "events": [
-                        {
-                            "introduced": "0"
-                        },
-                        {
-                            "fixed": "1.12.11"
-                        }
-                    ]
-                }
-            ],
-            "database_specific": {
-                "url": "https://pkg.go.dev/vuln/GO-2022-0569"
-            },
-            "ecosystem_specific": {
-                "imports": [
-                    {
-                        "path": "github.com/beego/beego",
-                        "symbols": [
-                            "App.Run",
-                            "ControllerRegister.FindPolicy",
-                            "ControllerRegister.FindRouter",
-                            "ControllerRegister.ServeHTTP",
-                            "FilterRouter.ValidRouter",
-                            "InitBeegoBeforeTest",
-                            "Run",
-                            "RunWithMiddleWares",
-                            "TestBeegoInit",
-                            "Tree.Match",
-                            "adminApp.Run"
-                        ]
-                    }
-                ]
-            }
-        },
-        {
-            "package": {
-                "name": "github.com/beego/beego/v2",
-                "ecosystem": "Go"
-            },
-            "ranges": [
-                {
-                    "type": "SEMVER",
-                    "events": [
-                        {
-                            "introduced": "2.0.0"
-                        },
-                        {
-                            "fixed": "2.0.4"
-                        }
-                    ]
-                }
-            ],
-            "database_specific": {
-                "url": "https://pkg.go.dev/vuln/GO-2022-0569"
-            },
-            "ecosystem_specific": {
-                "imports": [
-                    {
-                        "path": "github.com/beego/beego/v2/server/web",
-                        "symbols": [
-                            "AddNamespace",
-                            "AddViewPath",
-                            "Any",
-                            "AutoPrefix",
-                            "AutoRouter",
-                            "BuildTemplate",
-                            "Compare",
-                            "CompareNot",
-                            "Controller.Abort",
-                            "Controller.Bind",
-                            "Controller.BindForm",
-                            "Controller.BindJSON",
-                            "Controller.BindProtobuf",
-                            "Controller.BindXML",
-                            "Controller.BindYAML",
-                            "Controller.CheckXSRFCookie",
-                            "Controller.CustomAbort",
-                            "Controller.Delete",
-                            "Controller.DestroySession",
-                            "Controller.Get",
-                            "Controller.GetBool",
-                            "Controller.GetFile",
-                            "Controller.GetFloat",
-                            "Controller.GetInt",
-                            "Controller.GetInt16",
-                            "Controller.GetInt32",
-                            "Controller.GetInt64",
-                            "Controller.GetInt8",
-                            "Controller.GetSecureCookie",
-                            "Controller.GetString",
-                            "Controller.GetStrings",
-                            "Controller.GetUint16",
-                            "Controller.GetUint32",
-                            "Controller.GetUint64",
-                            "Controller.GetUint8",
-                            "Controller.Head",
-                            "Controller.Input",
-                            "Controller.IsAjax",
-                            "Controller.JSONResp",
-                            "Controller.Options",
-                            "Controller.ParseForm",
-                            "Controller.Patch",
-                            "Controller.Post",
-                            "Controller.Put",
-                            "Controller.Redirect",
-                            "Controller.Render",
-                            "Controller.RenderBytes",
-                            "Controller.RenderString",
-                            "Controller.Resp",
-                            "Controller.SaveToFile",
-                            "Controller.SaveToFileWithBuffer",
-                            "Controller.ServeFormatted",
-                            "Controller.ServeJSON",
-                            "Controller.ServeJSONP",
-                            "Controller.ServeXML",
-                            "Controller.ServeYAML",
-                            "Controller.SessionRegenerateID",
-                            "Controller.SetData",
-                            "Controller.SetSecureCookie",
-                            "Controller.Trace",
-                            "Controller.URLFor",
-                            "Controller.XMLResp",
-                            "Controller.XSRFFormHTML",
-                            "Controller.XSRFToken",
-                            "Controller.YamlResp",
-                            "ControllerRegister.Add",
-                            "ControllerRegister.AddAuto",
-                            "ControllerRegister.AddAutoPrefix",
-                            "ControllerRegister.AddMethod",
-                            "ControllerRegister.AddRouterMethod",
-                            "ControllerRegister.Any",
-                            "ControllerRegister.CtrlAny",
-                            "ControllerRegister.CtrlDelete",
-                            "ControllerRegister.CtrlGet",
-                            "ControllerRegister.CtrlHead",
-                            "ControllerRegister.CtrlOptions",
-                            "ControllerRegister.CtrlPatch",
-                            "ControllerRegister.CtrlPost",
-                            "ControllerRegister.CtrlPut",
-                            "ControllerRegister.Delete",
-                            "ControllerRegister.FindPolicy",
-                            "ControllerRegister.FindRouter",
-                            "ControllerRegister.Get",
-                            "ControllerRegister.GetContext",
-                            "ControllerRegister.Handler",
-                            "ControllerRegister.Head",
-                            "ControllerRegister.Include",
-                            "ControllerRegister.Init",
-                            "ControllerRegister.InsertFilter",
-                            "ControllerRegister.Options",
-                            "ControllerRegister.Patch",
-                            "ControllerRegister.Post",
-                            "ControllerRegister.Put",
-                            "ControllerRegister.ServeHTTP",
-                            "ControllerRegister.URLFor",
-                            "CtrlAny",
-                            "CtrlDelete",
-                            "CtrlGet",
-                            "CtrlHead",
-                            "CtrlOptions",
-                            "CtrlPatch",
-                            "CtrlPost",
-                            "CtrlPut",
-                            "Date",
-                            "DateFormat",
-                            "DateParse",
-                            "Delete",
-                            "Exception",
-                            "ExecuteTemplate",
-                            "ExecuteViewPathTemplate",
-                            "FileSystem.Open",
-                            "FilterRouter.ValidRouter",
-                            "FlashData.Error",
-                            "FlashData.Notice",
-                            "FlashData.Set",
-                            "FlashData.Store",
-                            "FlashData.Success",
-                            "FlashData.Warning",
-                            "Get",
-                            "GetConfig",
-                            "HTML2str",
-                            "Handler",
-                            "Head",
-                            "Htmlquote",
-                            "Htmlunquote",
-                            "HttpServer.Any",
-                            "HttpServer.AutoPrefix",
-                            "HttpServer.AutoRouter",
-                            "HttpServer.CtrlAny",
-                            "HttpServer.CtrlDelete",
-                            "HttpServer.CtrlGet",
-                            "HttpServer.CtrlHead",
-                            "HttpServer.CtrlOptions",
-                            "HttpServer.CtrlPatch",
-                            "HttpServer.CtrlPost",
-                            "HttpServer.CtrlPut",
-                            "HttpServer.Delete",
-                            "HttpServer.Get",
-                            "HttpServer.Handler",
-                            "HttpServer.Head",
-                            "HttpServer.Include",
-                            "HttpServer.InsertFilter",
-                            "HttpServer.LogAccess",
-                            "HttpServer.Options",
-                            "HttpServer.Patch",
-                            "HttpServer.Post",
-                            "HttpServer.PrintTree",
-                            "HttpServer.Put",
-                            "HttpServer.RESTRouter",
-                            "HttpServer.Router",
-                            "HttpServer.RouterWithOpts",
-                            "HttpServer.Run",
-                            "Include",
-                            "InitBeegoBeforeTest",
-                            "InsertFilter",
-                            "LoadAppConfig",
-                            "LogAccess",
-                            "MapGet",
-                            "Namespace.Any",
-                            "Namespace.AutoPrefix",
-                            "Namespace.AutoRouter",
-                            "Namespace.Cond",
-                            "Namespace.CtrlAny",
-                            "Namespace.CtrlDelete",
-                            "Namespace.CtrlGet",
-                            "Namespace.CtrlHead",
-                            "Namespace.CtrlOptions",
-                            "Namespace.CtrlPatch",
-                            "Namespace.CtrlPost",
-                            "Namespace.CtrlPut",
-                            "Namespace.Delete",
-                            "Namespace.Filter",
-                            "Namespace.Get",
-                            "Namespace.Handler",
-                            "Namespace.Head",
-                            "Namespace.Include",
-                            "Namespace.Namespace",
-                            "Namespace.Options",
-                            "Namespace.Patch",
-                            "Namespace.Post",
-                            "Namespace.Put",
-                            "Namespace.Router",
-                            "NewControllerRegister",
-                            "NewControllerRegisterWithCfg",
-                            "NewHttpServerWithCfg",
-                            "NewHttpSever",
-                            "NewNamespace",
-                            "NotNil",
-                            "Options",
-                            "ParseForm",
-                            "Patch",
-                            "Policy",
-                            "Post",
-                            "PrintTree",
-                            "Put",
-                            "RESTRouter",
-                            "ReadFromRequest",
-                            "RenderForm",
-                            "Router",
-                            "RouterWithOpts",
-                            "Run",
-                            "RunWithMiddleWares",
-                            "TestBeegoInit",
-                            "Tree.AddRouter",
-                            "Tree.AddTree",
-                            "Tree.Match",
-                            "URLFor",
-                            "URLMap.GetMap",
-                            "URLMap.GetMapData",
-                            "Walk",
-                            "adminApp.Run",
-                            "adminController.AdminIndex",
-                            "adminController.Healthcheck",
-                            "adminController.ListConf",
-                            "adminController.ProfIndex",
-                            "adminController.PrometheusMetrics",
-                            "adminController.QpsIndex",
-                            "adminController.TaskStatus",
-                            "beegoAppConfig.Bool",
-                            "beegoAppConfig.DefaultBool"
-                        ]
-                    }
-                ]
-            }
-        }
-    ],
-    "references": [
-        {
-            "type": "FIX",
-            "url": "https://github.com/beego/beego/pull/5025"
-        },
-        {
-            "type": "FIX",
-            "url": "https://github.com/beego/beego/pull/5025/commits/ea5ae58d40589d249cf577a053e490509de2bf57"
-        }
-    ],
-    "schema_version": "1.3.1"
-}
\ No newline at end of file
diff --git a/internal/govulncheckshim/govulncheckshim.go b/internal/govulncheckshim/govulncheckshim.go
deleted file mode 100644
index 9f512c3..0000000
--- a/internal/govulncheckshim/govulncheckshim.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package govulncheckshim
-
-import (
-	"context"
-	"fmt"
-	"path/filepath"
-	"strings"
-
-	"golang.org/x/tools/go/packages"
-	"golang.org/x/vuln/exp/govulncheck"
-	"golang.org/x/vuln/vulncheck"
-
-	"github.com/google/osv-scanner/pkg/models"
-)
-
-type packageError struct {
-	Errors []packages.Error
-}
-
-func (e *packageError) Error() string {
-	var b strings.Builder
-	fmt.Fprintln(&b, "Packages contain errors:")
-	for _, e := range e.Errors {
-		fmt.Fprintln(&b, e)
-	}
-
-	return b.String()
-}
-
-// RunGoVulnCheck runs govulncheck with a subset of vulnerabilities identified by osv-scanner
-func RunGoVulnCheck(path string, vulns []models.Vulnerability) (*govulncheck.Result, error) {
-	path, err := filepath.Abs(path)
-	if err != nil {
-		return nil, err
-	}
-	scanPath := filepath.Join(path, "...")
-	client := newClient(vulns)
-
-	cfg := &govulncheck.Config{Client: client}
-	pkgs, err := loadPackages([]string{scanPath}, filepath.Dir(scanPath))
-	if err != nil {
-		return nil, err
-	}
-
-	return govulncheck.Source(context.Background(), cfg, pkgs)
-}
-
-// loadPackages loads the packages matching patterns at dir using build tags
-// provided by tagsFlag. Uses load mode needed for vulncheck analysis. If the
-// packages contain errors, a packageError is returned containing a list of
-// the errors, along with the packages themselves.
-func loadPackages(patterns []string, dir string) ([]*vulncheck.Package, error) {
-	var buildFlags []string
-	// TODO: Enable user configurable tags
-	// if tagsFlag != nil {
-	// 	buildFlags = []string{fmt.Sprintf("-tags=%s", strings.Join(tagsFlag, ","))}
-	// }
-
-	cfg := &packages.Config{Dir: dir, Tests: true}
-	cfg.Mode |= packages.NeedName | packages.NeedImports | packages.NeedTypes |
-		packages.NeedSyntax | packages.NeedTypesInfo | packages.NeedDeps |
-		packages.NeedModule
-	cfg.BuildFlags = buildFlags
-
-	pkgs, err := packages.Load(cfg, patterns...)
-	if err != nil {
-		return nil, err
-	}
-	vpkgs := vulncheck.Convert(pkgs)
-
-	var perrs []packages.Error
-	packages.Visit(pkgs, nil, func(p *packages.Package) {
-		perrs = append(perrs, p.Errors...)
-	})
-	if len(perrs) > 0 {
-		err = &packageError{perrs}
-	}
-
-	return vpkgs, err
-}
diff --git a/internal/sourceanalysis/fixtures/govulncheckinput.json b/internal/sourceanalysis/fixtures/govulncheckinput.json
index e70cca4..80608be 100644
--- a/internal/sourceanalysis/fixtures/govulncheckinput.json
+++ b/internal/sourceanalysis/fixtures/govulncheckinput.json
@@ -1,169 +1,48 @@
 {
-  "GO-2021-0053": {
-    "OSV": {
-      "id": "GO-2021-0053",
-      "published": "2021-04-14T20:04:52Z",
-      "modified": "2023-02-10T16:51:38Z",
-      "aliases": [
-        "CVE-2021-3121",
-        "GHSA-c3h9-896r-86jm"
-      ],
-      "details": "Due to improper bounds checking, maliciously crafted input to generated Unmarshal methods can cause an out-of-bounds panic. If parsing messages from untrusted parties, this may be used as a denial of service vector.",
-      "affected": [
-        {
-          "package": {
-            "name": "github.com/gogo/protobuf",
-            "ecosystem": "Go"
-          },
-          "ranges": [
+   "GO-2021-0053":[
+      {
+         "osv":"GO-2021-0053",
+         "fixed_version":"v1.3.2",
+         "trace":[
             {
-              "type": "SEMVER",
-              "events": [
-                {
-                  "introduced": "0"
-                },
-                {
-                  "fixed": "1.3.2"
-                }
-              ]
+               "module":"github.com/gogo/protobuf",
+               "version":"v1.3.1",
+               "package":"github.com/gogo/protobuf/plugin/unmarshal"
             }
-          ],
-          "database_specific": {
-            "url": "https://pkg.go.dev/vuln/GO-2021-0053"
-          },
-          "ecosystem_specific": {
-            "imports": [
-              {
-                "path": "github.com/gogo/protobuf/plugin/unmarshal",
-                "symbols": [
-                  "unmarshal.Generate",
-                  "unmarshal.field"
-                ]
-              }
-            ]
-          }
-        }
-      ],
-      "references": [
-        {
-          "type": "FIX",
-          "url": "https://github.com/gogo/protobuf/commit/b03c65ea87cdc3521ede29f62fe3ce239267c1bc"
-        }
-      ],
-      "schema_version": "1.3.0"
-    },
-    "Modules": [
-      {
-        "Path": "github.com/gogo/protobuf",
-        "FoundVersion": "v1.3.1",
-        "FixedVersion": "v1.3.2",
-        "Packages": [
-          {
-            "Path": "github.com/gogo/protobuf/plugin/unmarshal",
-            "CallStacks": null
-          }
-        ]
+         ]
       }
-    ]
-  },
-  "GO-2023-1558": {
-    "OSV": {
-      "id": "GO-2023-1558",
-      "published": "2023-02-14T19:41:21Z",
-      "modified": "2023-02-14T19:41:21Z",
-      "aliases": [
-        "CVE-2023-23626",
-        "GHSA-2h6c-j3gf-xp9r"
-      ],
-      "details": "When feeding untrusted user input into the size parameter of `NewBitfield` and FromBytes functions, an attacker can trigger panics.\n\nThis happens when the size is a not a multiple of 8 or is negative.\n\nA workaround is to ensure size%8 == 0 \u0026\u0026 size \u003e= 0 yourself before calling NewBitfield or FromBytes.",
-      "affected": [
-        {
-          "package": {
-            "name": "github.com/ipfs/go-bitfield",
-            "ecosystem": "Go"
-          },
-          "ranges": [
+   ],
+   "GO-2023-1558":[
+      {
+         "osv":"GO-2023-1558",
+         "fixed_version":"v1.1.0",
+         "trace":[
             {
-              "type": "SEMVER",
-              "events": [
-                {
-                  "introduced": "0"
-                },
-                {
-                  "fixed": "1.1.0"
-                }
-              ]
+               "module":"github.com/ipfs/go-bitfield",
+               "version":"v1.0.0",
+               "package":"github.com/ipfs/go-bitfield",
+               "function":"NewBitfield",
+               "receiver":"",
+               "position":{
+                  "filename":"",
+                  "offset":0,
+                  "line":0,
+                  "column":0
+               }
+            },
+            {
+               "module":"github.com/ossf-tests/osv-e2e",
+               "package":"github.com/ossf-tests/osv-e2e",
+               "function":"main",
+               "receiver":"",
+               "position":{
+                  "filename":"/home/rexpan/Documents/Projects/osv-scanner/internal/govulncheckshim/fixtures/test-project/main.go",
+                  "offset":234,
+                  "line":13,
+                  "column":22
+               }
             }
-          ],
-          "database_specific": {
-            "url": "https://pkg.go.dev/vuln/GO-2023-1558"
-          },
-          "ecosystem_specific": {
-            "imports": [
-              {
-                "path": "github.com/ipfs/go-bitfield",
-                "symbols": [
-                  "FromBytes",
-                  "NewBitfield"
-                ]
-              }
-            ]
-          }
-        }
-      ],
-      "references": [
-        {
-          "type": "ADVISORY",
-          "url": "https://github.com/ipfs/go-bitfield/security/advisories/GHSA-2h6c-j3gf-xp9r"
-        },
-        {
-          "type": "FIX",
-          "url": "https://github.com/ipfs/go-bitfield/commit/5e1d256fe043fc4163343ccca83862c69c52e579"
-        }
-      ],
-      "schema_version": "1.3.0"
-    },
-    "Modules": [
-      {
-        "Path": "github.com/ipfs/go-bitfield",
-        "FoundVersion": "v1.0.0",
-        "FixedVersion": "v1.1.0",
-        "Packages": [
-          {
-            "Path": "github.com/ipfs/go-bitfield",
-            "CallStacks": [
-              {
-                "Symbol": "NewBitfield",
-                "Summary": "../../internal/govulncheckshim/fixtures/test-project/main.go:13:22: github.com/ossf-tests/osv-e2e.main calls github.com/ipfs/go-bitfield.NewBitfield",
-                "Frames": [
-                  {
-                    "PkgPath": "github.com/ossf-tests/osv-e2e",
-                    "FuncName": "main",
-                    "RecvType": "",
-                    "Position": {
-                      "Filename": "/home/rexpan/Documents/Projects/osv-scanner/internal/govulncheckshim/fixtures/test-project/main.go",
-                      "Offset": 234,
-                      "Line": 13,
-                      "Column": 22
-                    }
-                  },
-                  {
-                    "PkgPath": "github.com/ipfs/go-bitfield",
-                    "FuncName": "NewBitfield",
-                    "RecvType": "",
-                    "Position": {
-                      "Filename": "",
-                      "Offset": 0,
-                      "Line": 0,
-                      "Column": 0
-                    }
-                  }
-                ]
-              }
-            ]
-          }
-        ]
+         ]
       }
-    ]
-  }
-}
\ No newline at end of file
+   ]
+}
diff --git a/internal/sourceanalysis/go.go b/internal/sourceanalysis/go.go
index 59288a9..979e802 100644
--- a/internal/sourceanalysis/go.go
+++ b/internal/sourceanalysis/go.go
@@ -1,19 +1,23 @@
 package sourceanalysis
 
 import (
+	"bytes"
+	"context"
+	"encoding/json"
 	"fmt"
+	"io"
+	"os"
 	"path/filepath"
 
-	"github.com/google/osv-scanner/internal/govulncheckshim"
+	"github.com/google/osv-scanner/internal/sourceanalysis/govulncheck"
 	"github.com/google/osv-scanner/pkg/models"
 	"github.com/google/osv-scanner/pkg/reporter"
-	"golang.org/x/exp/slices"
-	"golang.org/x/vuln/exp/govulncheck"
+	"golang.org/x/vuln/scan"
 )
 
 func goAnalysis(r reporter.Reporter, pkgs []models.PackageVulns, source models.SourceInfo) {
 	vulns, vulnsByID := vulnsFromAllPkgs(pkgs)
-	res, err := govulncheckshim.RunGoVulnCheck(filepath.Dir(source.Path), vulns)
+	res, err := runGovulncheck(filepath.Dir(source.Path), vulns)
 	if err != nil {
 		// TODO: Better method to identify the type of error and give advice specific to the error
 		r.PrintError(
@@ -22,14 +26,20 @@ func goAnalysis(r reporter.Reporter, pkgs []models.PackageVulns, source models.S
 
 		return
 	}
-	gvcResByVulnID := map[string]*govulncheck.Vuln{}
-	for _, v := range res.Vulns {
-		gvcResByVulnID[v.OSV.ID] = v
-	}
-	matchAnalysisWithPackageVulns(pkgs, gvcResByVulnID, vulnsByID)
+	matchAnalysisWithPackageVulns(pkgs, res, vulnsByID)
 }
 
-func matchAnalysisWithPackageVulns(pkgs []models.PackageVulns, gvcResByVulnID map[string]*govulncheck.Vuln, vulnsByID map[string]models.Vulnerability) {
+func matchAnalysisWithPackageVulns(pkgs []models.PackageVulns, idToFindings map[string][]*govulncheck.Finding, vulnsByID map[string]models.Vulnerability) {
+	idToModuleToCalled := map[string]map[string]bool{}
+	for id, findings := range idToFindings {
+		idToModuleToCalled[id] = map[string]bool{}
+		for _, f := range findings {
+			modulePath := f.Trace[0].Module
+			called := f.Trace[0].Function != ""
+			idToModuleToCalled[f.OSV][modulePath] = called
+		}
+	}
+
 	for _, pv := range pkgs {
 		// Use index to keep reference to original element in slice
 		for groupIdx := range pv.Groups {
@@ -39,26 +49,13 @@ func matchAnalysisWithPackageVulns(pkgs []models.PackageVulns, gvcResByVulnID ma
 					*analysis = make(map[string]models.AnalysisInfo)
 				}
 
-				gvcVuln, ok := gvcResByVulnID[vulnID]
+				moduleToCalled, ok := idToModuleToCalled[vulnID]
 				if !ok { // If vulnerability not found, check if it contain any source information
 					fillNotImportedAnalysisInfo(vulnsByID, vulnID, pv, analysis)
 					continue
 				}
-				// Module list is unlikely to be very big, linear search is fine
-				containsModule := slices.ContainsFunc(gvcVuln.Modules, func(module *govulncheck.Module) bool {
-					return module.Path == pv.Package.Name
-				})
-
-				if !containsModule {
-					// Code does not import module, so definitely not called
-					(*analysis)[vulnID] = models.AnalysisInfo{
-						Called: false,
-					}
-				} else {
-					// Code does import module, check if it's called
-					(*analysis)[vulnID] = models.AnalysisInfo{
-						Called: gvcVuln.IsCalled(),
-					}
+				(*analysis)[vulnID] = models.AnalysisInfo{
+					Called: moduleToCalled[pv.Package.Name],
 				}
 			}
 		}
@@ -83,3 +80,77 @@ func fillNotImportedAnalysisInfo(vulnsByID map[string]models.Vulnerability, vuln
 		}
 	}
 }
+
+func runGovulncheck(moddir string, vulns []models.Vulnerability) (map[string][]*govulncheck.Finding, error) {
+	// Create a temporary directory containing all of the vulnerabilities that
+	// are passed in to check against govulncheck.
+	//
+	// This enables OSV scanner to supply the OSV vulnerabilities to run
+	// against govulncheck and manage the database separately from vuln.go.dev.
+	dbdir, err := os.MkdirTemp("", "")
+	if err != nil {
+		return nil, err
+	}
+	defer func() {
+		rerr := os.RemoveAll(dbdir)
+		if err == nil {
+			err = rerr
+		}
+	}()
+
+	for _, vuln := range vulns {
+		dat, err := json.Marshal(vuln)
+		if err != nil {
+			return nil, err
+		}
+		if err := os.WriteFile(fmt.Sprintf("%s/%s.json", dbdir, vuln.ID), dat, 0600); err != nil {
+			return nil, err
+		}
+	}
+
+	// Run govulncheck on the module at moddir and vulnerability database that
+	// was just created.
+	cmd := scan.Command(context.Background(), "-db", fmt.Sprintf("file://%s", dbdir), "-C", moddir, "-json", "./...")
+	var b bytes.Buffer
+	cmd.Stdout = &b
+	if err := cmd.Start(); err != nil {
+		return nil, err
+	}
+	if err := cmd.Wait(); err != nil {
+		return nil, err
+	}
+
+	// Group the output of govulncheck based on the OSV ID.
+	h := &osvHandler{
+		idToFindings: map[string][]*govulncheck.Finding{},
+	}
+	if err := handleJSON(bytes.NewReader(b.Bytes()), h); err != nil {
+		return nil, err
+	}
+
+	return h.idToFindings, nil
+}
+
+type osvHandler struct {
+	idToFindings map[string][]*govulncheck.Finding
+}
+
+func (h *osvHandler) Finding(f *govulncheck.Finding) {
+	h.idToFindings[f.OSV] = append(h.idToFindings[f.OSV], f)
+}
+
+func handleJSON(from io.Reader, to *osvHandler) error {
+	dec := json.NewDecoder(from)
+	for dec.More() {
+		msg := govulncheck.Message{}
+		// decode the next message in the stream
+		if err := dec.Decode(&msg); err != nil {
+			return err
+		}
+		if msg.Finding != nil {
+			to.Finding(msg.Finding)
+		}
+	}
+
+	return nil
+}
diff --git a/internal/sourceanalysis/govulncheck/result.go b/internal/sourceanalysis/govulncheck/result.go
new file mode 100644
index 0000000..c2102a4
--- /dev/null
+++ b/internal/sourceanalysis/govulncheck/result.go
@@ -0,0 +1,86 @@
+// Copied from
+// https://github.com/golang/vuln/blob/267a472bf377fa105988693c2a597d2b8de36ad8/internal/govulncheck/result.go
+// and modified.
+
+package govulncheck
+
+// Message is an entry in the output stream. It will always have exactly one
+// field filled in.
+type Message struct {
+	Finding *Finding `json:"finding,omitempty"`
+
+	// The Config, Progress, and OSV fields from the JSON output are removed, since they
+	// are not used.
+}
+
+// Finding represents a single finding.
+type Finding struct {
+	// OSV is the id of the detected vulnerability.
+	OSV string `json:"osv,omitempty"`
+
+	// FixedVersion is the module version where the vulnerability was
+	// fixed. This is empty if a fix is not available.
+	//
+	// If there are multiple fixed versions in the OSV report, this will
+	// be the fixed version in the latest range event for the OSV report.
+	//
+	// For example, if the range events are
+	// {introduced: 0, fixed: 1.0.0} and {introduced: 1.1.0}, the fixed version
+	// will be empty.
+	//
+	// For the stdlib, we will show the fixed version closest to the
+	// Go version that is used. For example, if a fix is available in 1.17.5 and
+	// 1.18.5, and the GOVERSION is 1.17.3, 1.17.5 will be returned as the
+	// fixed version.
+	FixedVersion string `json:"fixed_version,omitempty"`
+
+	// Trace contains an entry for each frame in the trace.
+	//
+	// Frames are sorted starting from the imported vulnerable symbol
+	// until the entry point. The first frame in Frames should match
+	// Symbol.
+	//
+	// In binary mode, trace will contain a single-frame with no position
+	// information.
+	//
+	// When a package is imported but no vulnerable symbol is called, the trace
+	// will contain a single-frame with no symbol or position information.
+	Trace []*Frame `json:"trace,omitempty"`
+}
+
+// Frame represents an entry in a finding trace.
+type Frame struct {
+	// Module is the module path of the module containing this symbol.
+	//
+	// Importable packages in the standard library will have the path "stdlib".
+	Module string `json:"module"`
+
+	// Version is the module version from the build graph.
+	Version string `json:"version,omitempty"`
+
+	// Package is the import path.
+	Package string `json:"package,omitempty"`
+
+	// Function is the function name.
+	Function string `json:"function,omitempty"`
+
+	// Receiver is the receiver type if the called symbol is a method.
+	//
+	// The client can create the final symbol name by
+	// prepending Receiver to FuncName.
+	Receiver string `json:"receiver,omitempty"`
+
+	// Position describes an arbitrary source position
+	// including the file, line, and column location.
+	// A Position is valid if the line number is > 0.
+	Position *Position `json:"position,omitempty"`
+}
+
+// Position is a copy of token.Position used to marshal/unmarshal
+// JSON correctly.
+type Position struct {
+	Filename string `json:"filename,omitempty"` // filename, if any
+	Offset   int    `json:"offset"`             // offset, starting at 0
+	Line     int    `json:"line"`               // line number, starting at 1
+	Column   int    `json:"column"`             // column number, starting at 1 (byte count)
+}


Test patch:
diff --git a/internal/govulncheckshim/client_test.go b/internal/govulncheckshim/client_test.go
deleted file mode 100644
index 778973b..0000000
--- a/internal/govulncheckshim/client_test.go
+++ /dev/null
@@ -1,244 +0,0 @@
-package govulncheckshim
-
-import (
-	"context"
-	"encoding/json"
-	"os"
-	"path/filepath"
-	"testing"
-
-	"github.com/google/osv-scanner/pkg/models"
-)
-
-func newTestClient(t *testing.T) *localSource {
-	t.Helper()
-
-	vulns := []models.Vulnerability{}
-	entries, err := os.ReadDir("fixtures/client")
-	if err != nil {
-		t.Fatal(err)
-	}
-	for _, entry := range entries {
-		file, err := os.Open(filepath.Join("fixtures/client", entry.Name()))
-		if err != nil {
-			t.Fatalf("failed to open test fixtures %s", err)
-		}
-		newVuln := models.Vulnerability{}
-		err = json.NewDecoder(file).Decode(&newVuln)
-		if err != nil {
-			t.Fatalf("failed to parse test fixtures %s", err)
-		}
-		vulns = append(vulns, newVuln)
-	}
-
-	return newClient(vulns)
-}
-
-func TestGetByID(t *testing.T) {
-	t.Parallel()
-
-	type IDTestCases struct {
-		ID          string
-		ReturnValue *struct {
-			Published string
-		}
-	}
-
-	testCases := []IDTestCases{
-		{
-			ID: "GO-2021-0098",
-			ReturnValue: &struct{ Published string }{
-				Published: "2021-04-14",
-			},
-		},
-		{
-			ID: "GO-2022-0569",
-			ReturnValue: &struct{ Published string }{
-				Published: "2022-08-23",
-			},
-		},
-		{
-			ID: "GHSA-vc3p-29h2-gpcp",
-			ReturnValue: &struct{ Published string }{
-				Published: "2022-01-02",
-			},
-		},
-		{
-			ID:          "GO-1234-5678",
-			ReturnValue: nil,
-		},
-	}
-
-	client := newTestClient(t)
-	for _, x := range testCases {
-		res, err := client.GetByID(context.Background(), x.ID)
-		if err != nil {
-			t.Error(err)
-		}
-		if (x.ReturnValue == nil) != (res == nil) {
-			t.Errorf("Expected %s, found %s", x.ReturnValue, res)
-		}
-
-		if res == nil {
-			return
-		}
-
-		if res.Published.Format("2006-01-02") != x.ReturnValue.Published {
-			t.Errorf("Expected %s, found %s", x.ReturnValue.Published, res.Published.Format("yyyy-mm-dd"))
-		}
-	}
-}
-
-func TestGetByAlias(t *testing.T) {
-	t.Parallel()
-
-	type AliasTestCases struct {
-		Alias       string
-		ReturnValue []struct {
-			ID string
-		}
-	}
-
-	testCases := []AliasTestCases{
-		{
-			Alias: "CVE-2021-44716",
-			ReturnValue: []struct{ ID string }{
-				{
-					ID: "GHSA-vc3p-29h2-gpcp",
-				},
-			},
-		},
-		{
-			Alias: "CVE-2021-21237",
-			ReturnValue: []struct{ ID string }{
-				// Order doesn't matter
-				{
-					ID: "GHSA-cx3w-xqmc-84g5",
-				},
-				{
-					ID: "GO-2021-0098",
-				},
-			},
-		},
-		{
-			Alias: "GHSA-cx3w-xqmc-84g5",
-			ReturnValue: []struct{ ID string }{
-				// If the alias is the ID, do not return the entry
-				// TODO: Is this correct behavior?
-				// {
-				// 	ID: "GHSA-cx3w-xqmc-84g5",
-				// },
-				{
-					ID: "GO-2021-0098",
-				},
-			},
-		},
-		{
-			Alias:       "GO-1234-5678",
-			ReturnValue: nil,
-		},
-	}
-
-	client := newTestClient(t)
-	for _, x := range testCases {
-		res, err := client.GetByAlias(context.Background(), x.Alias)
-		if err != nil {
-			t.Error(err)
-		}
-		if (x.ReturnValue == nil) != (res == nil) {
-			t.Errorf("Expected %v, found %v", x.ReturnValue, res)
-		}
-
-		if res == nil {
-			return
-		}
-
-		if len(res) != len(x.ReturnValue) {
-			t.Errorf("Expected %v, found %v", x.ReturnValue, res)
-		}
-
-		for i := range res {
-			if res[i].ID != x.ReturnValue[i].ID {
-				t.Errorf("Expected %s, found %s", x.ReturnValue[i].ID, res[i].ID)
-			}
-		}
-	}
-}
-
-func TestGetByModule(t *testing.T) {
-	t.Parallel()
-
-	type ModuleTestCases struct {
-		Module      string
-		ReturnValue []struct {
-			ID string
-		}
-	}
-
-	testCases := []ModuleTestCases{
-		{
-			Module: "github.com/beego/beego",
-			ReturnValue: []struct{ ID string }{
-				{
-					ID: "GO-2022-0569",
-				},
-			},
-		},
-		{
-			Module: "github.com/git-lfs/git-lfs",
-			ReturnValue: []struct{ ID string }{
-				// Order doesn't matter
-				{
-					ID: "GHSA-cx3w-xqmc-84g5",
-				},
-				{
-					ID: "GO-2021-0098",
-				},
-			},
-		},
-		{
-			Module:      "golang.org/x/y/z",
-			ReturnValue: nil,
-		},
-	}
-
-	client := newTestClient(t)
-	for _, x := range testCases {
-		res, err := client.GetByModule(context.Background(), x.Module)
-		if err != nil {
-			t.Error(err)
-		}
-		if (x.ReturnValue == nil) != (res == nil) {
-			t.Errorf("Expected %v, found %v", x.ReturnValue, res)
-		}
-
-		if res == nil {
-			return
-		}
-
-		if len(res) != len(x.ReturnValue) {
-			t.Errorf("Expected %v, found %v", x.ReturnValue, res)
-		}
-
-		for i := range res {
-			if res[i].ID != x.ReturnValue[i].ID {
-				t.Errorf("Expected %s, found %s", x.ReturnValue[i].ID, res[i].ID)
-			}
-		}
-	}
-}
-
-func TestLastModifiedTime(t *testing.T) {
-	t.Parallel()
-
-	client := newTestClient(t)
-	clientLastModTime, err := client.LastModifiedTime(context.Background())
-	if err != nil {
-		t.Error(err)
-	}
-
-	// Last modified time in GHSA-vc3p-29h2-gpcp
-	if clientLastModTime.Format("2006-01-02") != "2023-02-08" {
-		t.Errorf("Expected %s, found %s", "2023-02-08", clientLastModTime.Format("2006-01-02"))
-	}
-}
diff --git a/internal/govulncheckshim/fixtures/snapshots/govulncheckshim_test.json b/internal/govulncheckshim/fixtures/snapshots/govulncheckshim_test.json
deleted file mode 100755
index f4b2bbd..0000000
--- a/internal/govulncheckshim/fixtures/snapshots/govulncheckshim_test.json
+++ /dev/null
@@ -1,175 +0,0 @@
-{
- "Vulns": [
-  {
-   "Modules": [
-    {
-     "FixedVersion": "v1.1.0",
-     "FoundVersion": "v1.0.0",
-     "Packages": [
-      {
-       "CallStacks": [
-        {
-         "Frames": [
-          {
-           "FuncName": "main",
-           "PkgPath": "github.com/ossf-tests/osv-e2e",
-           "Position": {
-            "Column": 22,
-            "Filename": "<Any value>",
-            "Line": 13,
-            "Offset": 234
-           },
-           "RecvType": ""
-          },
-          {
-           "FuncName": "NewBitfield",
-           "PkgPath": "github.com/ipfs/go-bitfield",
-           "Position": {
-            "Column": 0,
-            "Filename": "",
-            "Line": 0,
-            "Offset": 0
-           },
-           "RecvType": ""
-          }
-         ],
-         "Summary": "fixtures/test-project/main.go:13:22: github.com/ossf-tests/osv-e2e.main calls github.com/ipfs/go-bitfield.NewBitfield",
-         "Symbol": "NewBitfield"
-        }
-       ],
-       "Path": "github.com/ipfs/go-bitfield"
-      }
-     ],
-     "Path": "github.com/ipfs/go-bitfield"
-    }
-   ],
-   "OSV": {
-    "affected": [
-     {
-      "database_specific": {
-       "url": "https://pkg.go.dev/vuln/GO-2023-1558"
-      },
-      "ecosystem_specific": {
-       "imports": [
-        {
-         "path": "github.com/ipfs/go-bitfield",
-         "symbols": [
-          "FromBytes",
-          "NewBitfield"
-         ]
-        }
-       ]
-      },
-      "package": {
-       "ecosystem": "Go",
-       "name": "github.com/ipfs/go-bitfield"
-      },
-      "ranges": [
-       {
-        "events": [
-         {
-          "introduced": "0"
-         },
-         {
-          "fixed": "1.1.0"
-         }
-        ],
-        "type": "SEMVER"
-       }
-      ]
-     }
-    ],
-    "aliases": [
-     "CVE-2023-23626",
-     "GHSA-2h6c-j3gf-xp9r"
-    ],
-    "details": "When feeding untrusted user input into the size parameter of `NewBitfield` and FromBytes functions, an attacker can trigger panics.\n\nThis happens when the size is a not a multiple of 8 or is negative.\n\nA workaround is to ensure size%8 == 0 \u0026\u0026 size \u003e= 0 yourself before calling NewBitfield or FromBytes.",
-    "id": "GO-2023-1558",
-    "modified": "2023-02-14T19:41:21Z",
-    "published": "2023-02-14T19:41:21Z",
-    "references": [
-     {
-      "type": "ADVISORY",
-      "url": "https://github.com/ipfs/go-bitfield/security/advisories/GHSA-2h6c-j3gf-xp9r"
-     },
-     {
-      "type": "FIX",
-      "url": "https://github.com/ipfs/go-bitfield/commit/5e1d256fe043fc4163343ccca83862c69c52e579"
-     }
-    ],
-    "credits": [
-        { "name": "Jorropo" }
-    ],
-    "schema_version": "1.3.1"
-   }
-  },
-  {
-   "Modules": [
-    {
-     "FixedVersion": "v1.3.2",
-     "FoundVersion": "v1.3.1",
-     "Packages": [
-      {
-       "CallStacks": null,
-       "Path": "github.com/gogo/protobuf/plugin/unmarshal"
-      }
-     ],
-     "Path": "github.com/gogo/protobuf"
-    }
-   ],
-   "OSV": {
-    "affected": [
-     {
-      "database_specific": {
-       "url": "https://pkg.go.dev/vuln/GO-2021-0053"
-      },
-      "ecosystem_specific": {
-       "imports": [
-        {
-         "path": "github.com/gogo/protobuf/plugin/unmarshal",
-         "symbols": [
-          "unmarshal.Generate",
-          "unmarshal.field"
-         ]
-        }
-       ]
-      },
-      "package": {
-       "ecosystem": "Go",
-       "name": "github.com/gogo/protobuf"
-      },
-      "ranges": [
-       {
-        "events": [
-         {
-          "introduced": "0"
-         },
-         {
-          "fixed": "1.3.2"
-         }
-        ],
-        "type": "SEMVER"
-       }
-      ]
-     }
-    ],
-    "aliases": [
-     "CVE-2021-3121",
-     "GHSA-c3h9-896r-86jm"
-    ],
-    "details": "Due to improper bounds checking, maliciously crafted input to generated Unmarshal methods can cause an out-of-bounds panic. If parsing messages from untrusted parties, this may be used as a denial of service vector.",
-    "id": "GO-2021-0053",
-    "modified": "2023-02-10T16:51:38Z",
-    "published": "2021-04-14T20:04:52Z",
-    "references": [
-     {
-      "type": "FIX",
-      "url": "https://github.com/gogo/protobuf/commit/b03c65ea87cdc3521ede29f62fe3ce239267c1bc"
-     }
-    ],
-    "schema_version": "1.3.1"
-   }
-  }
- ]
-}
-
diff --git a/internal/sourceanalysis/go_test.go b/internal/sourceanalysis/go_test.go
index 6723f19..c9eb638 100644
--- a/internal/sourceanalysis/go_test.go
+++ b/internal/sourceanalysis/go_test.go
@@ -3,16 +3,16 @@ package sourceanalysis
 import (
 	"testing"
 
+	"github.com/google/osv-scanner/internal/sourceanalysis/govulncheck"
 	"github.com/google/osv-scanner/internal/testutility"
 	"github.com/google/osv-scanner/pkg/models"
-	"golang.org/x/vuln/exp/govulncheck"
 )
 
 func Test_matchAnalysisWithPackageVulns(t *testing.T) {
 	t.Parallel()
 
 	pkgs := testutility.LoadJSONFixture[[]models.PackageVulns](t, "fixtures/input.json")
-	gvcResByVulnID := testutility.LoadJSONFixture[map[string]*govulncheck.Vuln](t, "fixtures/govulncheckinput.json")
+	gvcResByVulnID := testutility.LoadJSONFixture[map[string][]*govulncheck.Finding](t, "fixtures/govulncheckinput.json")
 	vulnsByID := testutility.LoadJSONFixture[map[string]models.Vulnerability](t, "fixtures/vulnbyid.json")
 
 	matchAnalysisWithPackageVulns(pkgs, gvcResByVulnID, vulnsByID)
diff --git a/internal/govulncheckshim/.goignore b/internal/sourceanalysis/integration/.goignore
similarity index 100%
rename from internal/govulncheckshim/.goignore
rename to internal/sourceanalysis/integration/.goignore
diff --git a/internal/govulncheckshim/fixtures/GO-2021-0053.json b/internal/sourceanalysis/integration/fixtures/GO-2021-0053.json
similarity index 100%
rename from internal/govulncheckshim/fixtures/GO-2021-0053.json
rename to internal/sourceanalysis/integration/fixtures/GO-2021-0053.json
diff --git a/internal/govulncheckshim/fixtures/GO-2023-1558.json b/internal/sourceanalysis/integration/fixtures/GO-2023-1558.json
similarity index 100%
rename from internal/govulncheckshim/fixtures/GO-2023-1558.json
rename to internal/sourceanalysis/integration/fixtures/GO-2023-1558.json
diff --git a/internal/sourceanalysis/integration/fixtures/snapshots/govulncheckshim_test.json b/internal/sourceanalysis/integration/fixtures/snapshots/govulncheckshim_test.json
new file mode 100755
index 0000000..355e95d
--- /dev/null
+++ b/internal/sourceanalysis/integration/fixtures/snapshots/govulncheckshim_test.json
@@ -0,0 +1,40 @@
+{
+   "GO-2023-1558":[
+      {
+         "osv":"GO-2023-1558",
+         "fixed_version":"v1.1.0",
+         "trace":[
+            {
+               "module":"github.com/ipfs/go-bitfield",
+               "package":"github.com/ipfs/go-bitfield",
+               "version":"v1.0.0",
+               "function":"NewBitfield"
+            },
+            {
+               "module":"github.com/ossf-tests/osv-e2e",
+               "package":"github.com/ossf-tests/osv-e2e",
+               "function":"main",
+               "position":{
+                  "column":22,
+                  "filename":"<Any value>",
+                  "line":13,
+                  "offset":234
+               }
+            }
+         ]
+      }
+   ],
+   "GO-2021-0053":[
+      {
+         "osv":"GO-2021-0053",
+         "fixed_version":"v1.3.2",
+         "trace":[
+            {
+               "module":"github.com/gogo/protobuf",
+               "version":"v1.3.1",
+               "package":"github.com/gogo/protobuf/plugin/unmarshal"
+            }
+         ]
+      }
+   ]
+}
diff --git a/internal/govulncheckshim/fixtures/test-project/go.mod b/internal/sourceanalysis/integration/fixtures/test-project/go.mod
similarity index 100%
rename from internal/govulncheckshim/fixtures/test-project/go.mod
rename to internal/sourceanalysis/integration/fixtures/test-project/go.mod
diff --git a/internal/govulncheckshim/fixtures/test-project/go.sum b/internal/sourceanalysis/integration/fixtures/test-project/go.sum
similarity index 100%
rename from internal/govulncheckshim/fixtures/test-project/go.sum
rename to internal/sourceanalysis/integration/fixtures/test-project/go.sum
diff --git a/internal/govulncheckshim/fixtures/test-project/main.go b/internal/sourceanalysis/integration/fixtures/test-project/main.go
similarity index 100%
rename from internal/govulncheckshim/fixtures/test-project/main.go
rename to internal/sourceanalysis/integration/fixtures/test-project/main.go
diff --git a/internal/govulncheckshim/fixtures/test-project/osv-scanner.toml b/internal/sourceanalysis/integration/fixtures/test-project/osv-scanner.toml
similarity index 100%
rename from internal/govulncheckshim/fixtures/test-project/osv-scanner.toml
rename to internal/sourceanalysis/integration/fixtures/test-project/osv-scanner.toml
diff --git a/internal/govulncheckshim/govulncheckshim_test.go b/internal/sourceanalysis/integration_test.go
similarity index 60%
rename from internal/govulncheckshim/govulncheckshim_test.go
rename to internal/sourceanalysis/integration_test.go
index ef54557..f130b4c 100644
--- a/internal/govulncheckshim/govulncheckshim_test.go
+++ b/internal/sourceanalysis/integration_test.go
@@ -1,4 +1,4 @@
-package govulncheckshim
+package sourceanalysis
 
 import (
 	"encoding/json"
@@ -11,9 +11,11 @@ import (
 	"github.com/google/osv-scanner/pkg/models"
 )
 
+var fixturesDir = "integration/fixtures"
+
 func Test_RunGoVulnCheck(t *testing.T) {
 	t.Parallel()
-	entries, err := os.ReadDir("fixtures")
+	entries, err := os.ReadDir(fixturesDir)
 	if err != nil {
 		t.Errorf("failed to read fixtures dir: %v", err)
 	}
@@ -28,7 +30,8 @@ func Test_RunGoVulnCheck(t *testing.T) {
 			continue
 		}
 
-		file, err := os.Open(filepath.Join("fixtures", de.Name()))
+		fn := filepath.Join(fixturesDir, de.Name())
+		file, err := os.Open(fn)
 		if err != nil {
 			t.Errorf("failed to open fixture vuln files: %v", err)
 		}
@@ -36,16 +39,16 @@ func Test_RunGoVulnCheck(t *testing.T) {
 		newVuln := models.Vulnerability{}
 		err = json.NewDecoder(file).Decode(&newVuln)
 		if err != nil {
-			t.Errorf("failed to decode fixture vuln files: %v", err)
+			t.Errorf("failed to decode fixture vuln file (%q): %v", fn, err)
 		}
 		vulns = append(vulns, newVuln)
 	}
 
-	res, err := RunGoVulnCheck("fixtures/test-project", vulns)
+	res, err := runGovulncheck(filepath.Join(fixturesDir, "test-project"), vulns)
 	if err != nil {
 		t.Errorf("failed to run RunGoVulnCheck: %v", err)
 	}
 
-	res.Vulns[0].Modules[0].Packages[0].CallStacks[0].Frames[0].Position.Filename = "<Any value>"
-	testutility.AssertMatchFixtureJSON(t, "fixtures/snapshots/govulncheckshim_test.json", res)
+	res["GO-2023-1558"][0].Trace[1].Position.Filename = "<Any value>"
+	testutility.AssertMatchFixtureJSON(t, filepath.Join(fixturesDir, "snapshots/govulncheckshim_test.json"), res)
 }