Repository: google/osv-scanner
Pull request #505 (2023-08-25 06:25:16)

Add osv output lockfile + refactor
Introduces the osv-scanner results lockfile format (feel free to suggest a better name for this), 

This also refactors the models folder slightly to move some of the helper functions out to a separate internal crate. This stops the models package from pulling in the lockfile package, causing cyclic imports.

I also added another field to `PackageDetails`, `Source`, a currently optional string to specify the location the dependency is actually specified. The only times it will be different from the lockfile location currently is:

- Python requirements.txt `-r`
- This new osv-scanner format, it stores the lockfile path parsed in the output results.

G-Rath: I think it would be good if you split the refactor out into its own PR, and consider if anything else should be refactored for consistency since removing the receiver from a method is a breaking change so best to do it now than regret it later (you can also always make a method public in future in a non-breaking version too)

Patch:
diff --git a/go.mod b/go.mod
index 909fbe7..0800cda 100644
--- a/go.mod
+++ b/go.mod
@@ -4,12 +4,12 @@ go 1.19
 
 require (
 	github.com/BurntSushi/toml v1.3.2
-	github.com/CycloneDX/cyclonedx-go v0.7.1
+	github.com/CycloneDX/cyclonedx-go v0.7.2
 	github.com/go-git/go-billy/v5 v5.4.1
 	github.com/go-git/go-git/v5 v5.8.1
 	github.com/goark/go-cvss v1.6.6
 	github.com/google/go-cmp v0.5.9
-	github.com/jedib0t/go-pretty/v6 v6.4.6
+	github.com/jedib0t/go-pretty/v6 v6.4.7
 	github.com/kr/pretty v0.3.1
 	github.com/owenrumney/go-sarif/v2 v2.2.0
 	github.com/package-url/packageurl-go v0.1.1
diff --git a/go.sum b/go.sum
index fdaaffe..b2764ad 100644
--- a/go.sum
+++ b/go.sum
@@ -2,8 +2,8 @@ dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
 dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
 github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
 github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
-github.com/CycloneDX/cyclonedx-go v0.7.1 h1:5w1SxjGm9MTMNTuRbEPyw21ObdbaagTWF/KfF0qHTRE=
-github.com/CycloneDX/cyclonedx-go v0.7.1/go.mod h1:N/nrdWQI2SIjaACyyDs/u7+ddCkyl/zkNs8xFsHF2Ps=
+github.com/CycloneDX/cyclonedx-go v0.7.2 h1:kKQ0t1dPOlugSIYVOMiMtFqeXI2wp/f5DBIdfux8gnQ=
+github.com/CycloneDX/cyclonedx-go v0.7.2/go.mod h1:K2bA+324+Og0X84fA8HhN2X066K7Bxz4rpMQ4ZhjtSk=
 github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
 github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
 github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
@@ -52,8 +52,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab h1:BA4a7pe
 github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
-github.com/jedib0t/go-pretty/v6 v6.4.6 h1:v6aG9h6Uby3IusSSEjHaZNXpHFhzqMmjXcPq1Rjl9Jw=
-github.com/jedib0t/go-pretty/v6 v6.4.6/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs=
+github.com/jedib0t/go-pretty/v6 v6.4.7 h1:lwiTJr1DEkAgzljsUsORmWsVn5MQjt1BPJdPCtJ6KXE=
+github.com/jedib0t/go-pretty/v6 v6.4.7/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs=
 github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
 github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -109,12 +109,16 @@ github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
 github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/terminalstatic/go-xsd-validate v0.1.5 h1:RqpJnf6HGE2CB/lZB1A8BYguk8uRtcvYAPLCF15qguo=
 github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs=
 github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
 github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
 github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
 github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
 github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
+github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
 github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
 github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
diff --git a/pkg/lockfile/extractor.go b/pkg/lockfile/extractor.go
index 521dae3..b331b22 100644
--- a/pkg/lockfile/extractor.go
+++ b/pkg/lockfile/extractor.go
@@ -60,6 +60,9 @@ func OpenLocalDepFile(path string) (NestedDepFile, error) {
 		return LocalFile{}, err
 	}
 
+	// Very unlikely to have Abs return an error if the file opens correctly
+	path, _ = filepath.Abs(path)
+
 	return LocalFile{r, path}, nil
 }
 
diff --git a/pkg/lockfile/fixtures/osvscannerresults/empty.json b/pkg/lockfile/fixtures/osvscannerresults/empty.json
new file mode 100644
index 0000000..a9452a2
--- /dev/null
+++ b/pkg/lockfile/fixtures/osvscannerresults/empty.json
@@ -0,0 +1,3 @@
+{
+    "results": []
+}
\ No newline at end of file
diff --git a/pkg/lockfile/fixtures/osvscannerresults/multi-packages-with-vulns.json b/pkg/lockfile/fixtures/osvscannerresults/multi-packages-with-vulns.json
new file mode 100644
index 0000000..c861029
--- /dev/null
+++ b/pkg/lockfile/fixtures/osvscannerresults/multi-packages-with-vulns.json
@@ -0,0 +1,504 @@
+{
+    "results": [
+        {
+            "source": {
+                "path": "/path/to/Cargo.lock",
+                "type": "lockfile"
+            },
+            "packages": [
+                {
+                    "package": {
+                        "name": "crossbeam-utils",
+                        "version": "0.6.6",
+                        "ecosystem": "crates.io"
+                    },
+                    "vulnerabilities": [
+                        {
+                            "modified": "2022-08-11T21:55:33Z",
+                            "published": "2022-02-16T22:36:21Z",
+                            "schema_version": "1.4.0",
+                            "id": "GHSA-qc84-gqf4-9926",
+                            "aliases": [
+                                "CVE-2022-23639"
+                            ],
+                            "summary": "crossbeam-utils Race Condition vulnerability",
+                            "details": "### Impact\n\nThe affected version of this crate incorrectly assumed that the alignment of `{i,u}64` was always the same as `Atomic{I,U}64`. \n\nHowever, the alignment of `{i,u}64` on a 32-bit target can be smaller than `Atomic{I,U}64`.\n\nThis can cause the following problems:\n\n- Unaligned memory accesses\n- Data race\n\nCrates using `fetch_*` methods with `AtomicCell\u003c{i,u}64\u003e` are affected by this issue.\n\n32-bit targets without `Atomic{I,U}64` and 64-bit targets are not affected by this issue.\n32-bit targets with `Atomic{I,U}64` and `{i,u}64` have the same alignment are also not affected by this issue.\n\nThe following is a complete list of the builtin targets that may be affected. (last update: nightly-2022-02-11)\n\n- armv7-apple-ios (tier 3)\n- armv7s-apple-ios (tier 3)\n- i386-apple-ios (tier 3)\n- i586-unknown-linux-gnu\n- i586-unknown-linux-musl\n- i686-apple-darwin (tier 3)\n- i686-linux-android\n- i686-unknown-freebsd\n- i686-unknown-haiku (tier 3)\n- i686-unknown-linux-gnu\n- i686-unknown-linux-musl\n- i686-unknown-netbsd (tier 3)\n- i686-unknown-openbsd (tier 3)\n- i686-wrs-vxworks (tier 3)\n\n([script to get list](https://gist.github.com/taiki-e/3c7891e8c5f5e0cbcb44d7396aabfe10))\n\n### Patches\n\nThis has been fixed in crossbeam-utils 0.8.7.\n\nAffected 0.8.x releases have been yanked.\n\n### References\n\nhttps://github.com/crossbeam-rs/crossbeam/pull/781 \n\n### License\n\nThis advisory is in the public domain.",
+                            "affected": [
+                                {
+                                    "package": {
+                                        "ecosystem": "crates.io",
+                                        "name": "crossbeam-utils",
+                                        "purl": "pkg:cargo/crossbeam-utils"
+                                    },
+                                    "ranges": [
+                                        {
+                                            "type": "SEMVER",
+                                            "events": [
+                                                {
+                                                    "introduced": "0"
+                                                },
+                                                {
+                                                    "fixed": "0.8.7"
+                                                }
+                                            ]
+                                        }
+                                    ],
+                                    "database_specific": {
+                                        "source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2022/02/GHSA-qc84-gqf4-9926/GHSA-qc84-gqf4-9926.json"
+                                    }
+                                }
+                            ],
+                            "severity": [
+                                {
+                                    "type": "CVSS_V3",
+                                    "score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H"
+                                }
+                            ],
+                            "references": [
+                                {
+                                    "type": "WEB",
+                                    "url": "https://github.com/crossbeam-rs/crossbeam/security/advisories/GHSA-qc84-gqf4-9926"
+                                },
+                                {
+                                    "type": "ADVISORY",
+                                    "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-23639"
+                                },
+                                {
+                                    "type": "WEB",
+                                    "url": "https://github.com/crossbeam-rs/crossbeam/pull/781"
+                                },
+                                {
+                                    "type": "PACKAGE",
+                                    "url": "https://github.com/crossbeam-rs/crossbeam"
+                                },
+                                {
+                                    "type": "WEB",
+                                    "url": "https://github.com/crossbeam-rs/crossbeam/releases/tag/crossbeam-utils-0.8.7"
+                                },
+                                {
+                                    "type": "WEB",
+                                    "url": "https://rustsec.org/advisories/RUSTSEC-2022-0041.html"
+                                }
+                            ],
+                            "database_specific": {
+                                "cwe_ids": [
+                                    "CWE-362"
+                                ],
+                                "github_reviewed": true,
+                                "github_reviewed_at": "2022-02-16T22:36:21Z",
+                                "nvd_published_at": "2022-02-15T19:15:00Z",
+                                "severity": "HIGH"
+                            }
+                        },
+                        {
+                            "modified": "2022-08-04T13:56:30Z",
+                            "published": "2022-02-05T12:00:00Z",
+                            "schema_version": "1.4.0",
+                            "id": "RUSTSEC-2022-0041",
+                            "aliases": [
+                                "GHSA-qc84-gqf4-9926",
+                                "CVE-2022-23639"
+                            ],
+                            "summary": "Unsoundness of AtomicCell\u003c*64\u003e arithmetics on 32-bit targets that support Atomic*64",
+                            "details": "## Impact\n\nAffected versions of this crate incorrectly assumed that the alignment of {i,u}64 was always the same as Atomic{I,U}64.\n\nHowever, the alignment of {i,u}64 on a 32-bit target can be smaller than Atomic{I,U}64.\n\nThis can cause the following problems:\n\n- Unaligned memory accesses\n- Data race\n\nCrates using fetch_* methods with AtomicCell\u003c{i,u}64\u003e are affected by this issue.\n\n32-bit targets without Atomic{I,U}64 and 64-bit targets are not affected by this issue.\n\n32-bit targets with Atomic{I,U}64 and {i,u}64 have the same alignment are also not affected by this issue.\n\nThe following is a complete list of the builtin targets that may be affected. (last update: nightly-2022-02-11)\n\n- armv7-apple-ios (tier 3)\n- armv7s-apple-ios (tier 3)\n- i386-apple-ios (tier 3)\n- i586-unknown-linux-gnu\n- i586-unknown-linux-musl\n- i686-apple-darwin (tier 3)\n- i686-linux-android\n- i686-unknown-freebsd\n- i686-unknown-haiku (tier 3)\n- i686-unknown-linux-gnu\n- i686-unknown-linux-musl\n- i686-unknown-netbsd (tier 3)\n- i686-unknown-openbsd (tier 3)\n- i686-wrs-vxworks (tier 3)\n\n([script to get list](https://gist.github.com/taiki-e/3c7891e8c5f5e0cbcb44d7396aabfe10))\n\n## Patches\n\nThis has been fixed in crossbeam-utils 0.8.7.\n\nAffected 0.8.x releases have been yanked.\n\nThanks to @taiki-e",
+                            "affected": [
+                                {
+                                    "package": {
+                                        "ecosystem": "crates.io",
+                                        "name": "crossbeam-utils",
+                                        "purl": "pkg:cargo/crossbeam-utils"
+                                    },
+                                    "ranges": [
+                                        {
+                                            "type": "SEMVER",
+                                            "events": [
+                                                {
+                                                    "introduced": "0.0.0-0"
+                                                },
+                                                {
+                                                    "fixed": "0.8.7"
+                                                }
+                                            ]
+                                        }
+                                    ],
+                                    "database_specific": {
+                                        "categories": [
+                                            "memory-corruption"
+                                        ],
+                                        "cvss": null,
+                                        "informational": "unsound",
+                                        "source": "https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2022-0041.json"
+                                    },
+                                    "ecosystem_specific": {
+                                        "affects": {
+                                            "arch": [],
+                                            "functions": [],
+                                            "os": []
+                                        }
+                                    }
+                                }
+                            ],
+                            "references": [
+                                {
+                                    "type": "PACKAGE",
+                                    "url": "https://crates.io/crates/crossbeam-utils"
+                                },
+                                {
+                                    "type": "ADVISORY",
+                                    "url": "https://rustsec.org/advisories/RUSTSEC-2022-0041.html"
+                                },
+                                {
+                                    "type": "WEB",
+                                    "url": "https://github.com/crossbeam-rs/crossbeam/pull/781"
+                                }
+                            ]
+                        }
+                    ],
+                    "groups": [
+                        {
+                            "ids": [
+                                "GHSA-qc84-gqf4-9926",
+                                "RUSTSEC-2022-0041"
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "package": {
+                        "name": "memoffset",
+                        "version": "0.5.6",
+                        "ecosystem": "crates.io"
+                    },
+                    "vulnerabilities": [
+                        {
+                            "modified": "2023-06-21T22:06:29Z",
+                            "published": "2023-06-21T22:06:29Z",
+                            "schema_version": "1.4.0",
+                            "id": "GHSA-wfg4-322g-9vqv",
+                            "summary": "memoffset allows reading uninitialized memory",
+                            "details": "memoffset allows attempt of reading data from address `0` with arbitrary type. This behavior is an undefined behavior because address `0` to `std::mem::size_of\u003cT\u003e` may not have valid bit-pattern with `T`. Old implementation dereferences uninitialized memory obtained from `std::mem::align_of`. Older implementation prior to it allows using uninitialized data obtained from `std::mem::uninitialized` with arbitrary type then compute offset by taking the address of field-projection. This may also result in an undefined behavior for \"father\" that includes (directly or transitively) type that [does not allow to be uninitialized](https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html).\n\nThis flaw was corrected by using `std::ptr::addr_of` in \u003chttps://github.com/Gilnaa/memoffset/pull/50\u003e.\n",
+                            "affected": [
+                                {
+                                    "package": {
+                                        "ecosystem": "crates.io",
+                                        "name": "memoffset",
+                                        "purl": "pkg:cargo/memoffset"
+                                    },
+                                    "ranges": [
+                                        {
+                                            "type": "SEMVER",
+                                            "events": [
+                                                {
+                                                    "introduced": "0"
+                                                },
+                                                {
+                                                    "fixed": "0.6.2"
+                                                }
+                                            ]
+                                        }
+                                    ],
+                                    "database_specific": {
+                                        "source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2023/06/GHSA-wfg4-322g-9vqv/GHSA-wfg4-322g-9vqv.json"
+                                    }
+                                }
+                            ],
+                            "references": [
+                                {
+                                    "type": "WEB",
+                                    "url": "https://github.com/Gilnaa/memoffset/issues/24"
+                                },
+                                {
+                                    "type": "WEB",
+                                    "url": "https://github.com/Gilnaa/memoffset/pull/50"
+                                },
+                                {
+                                    "type": "PACKAGE",
+                                    "url": "https://github.com/Gilnaa/memoffset"
+                                },
+                                {
+                                    "type": "WEB",
+                                    "url": "https://rustsec.org/advisories/RUSTSEC-2023-0045.html"
+                                }
+                            ],
+                            "database_specific": {
+                                "cwe_ids": [],
+                                "github_reviewed": true,
+                                "github_reviewed_at": "2023-06-21T22:06:29Z",
+                                "nvd_published_at": null,
+                                "severity": "MODERATE"
+                            }
+                        },
+                        {
+                            "modified": "2023-07-08T12:30:19Z",
+                            "published": "2023-06-21T12:00:00Z",
+                            "schema_version": "1.4.0",
+                            "id": "RUSTSEC-2023-0045",
+                            "aliases": [
+                                "GHSA-wfg4-322g-9vqv"
+                            ],
+                            "summary": "memoffset allows reading uninitialized memory",
+                            "details": "memoffset allows attempt of reading data from address `0` with arbitrary type. This behavior is an undefined behavior because address `0` to `std::mem::size_of\u003cT\u003e` may not have valid bit-pattern with `T`. Old implementation dereferences uninitialized memory obtained from `std::mem::align_of`. Older implementation prior to it allows using uninitialized data obtained from `std::mem::uninitialized` with arbitrary type then compute offset by taking the address of field-projection. This may also result in an undefined behavior for \"father\" that includes (directly or transitively) type that [does not allow to be uninitialized](https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html).\n\nThis flaw was corrected by using `std::ptr::addr_of` in \u003chttps://github.com/Gilnaa/memoffset/pull/50\u003e.",
+                            "affected": [
+                                {
+                                    "package": {
+                                        "ecosystem": "crates.io",
+                                        "name": "memoffset",
+                                        "purl": "pkg:cargo/memoffset"
+                                    },
+                                    "ranges": [
+                                        {
+                                            "type": "SEMVER",
+                                            "events": [
+                                                {
+                                                    "introduced": "0.0.0-0"
+                                                },
+                                                {
+                                                    "fixed": "0.6.2"
+                                                }
+                                            ]
+                                        }
+                                    ],
+                                    "database_specific": {
+                                        "categories": [
+                                            "memory-corruption"
+                                        ],
+                                        "cvss": null,
+                                        "informational": "unsound",
+                                        "source": "https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2023-0045.json"
+                                    },
+                                    "ecosystem_specific": {
+                                        "affects": {
+                                            "arch": [],
+                                            "functions": [
+                                                "memoffset::offset_of"
+                                            ],
+                                            "os": []
+                                        }
+                                    }
+                                }
+                            ],
+                            "references": [
+                                {
+                                    "type": "PACKAGE",
+                                    "url": "https://crates.io/crates/memoffset"
+                                },
+                                {
+                                    "type": "ADVISORY",
+                                    "url": "https://rustsec.org/advisories/RUSTSEC-2023-0045.html"
+                                },
+                                {
+                                    "type": "REPORT",
+                                    "url": "https://github.com/Gilnaa/memoffset/issues/24"
+                                }
+                            ]
+                        }
+                    ],
+                    "groups": [
+                        {
+                            "ids": [
+                                "GHSA-wfg4-322g-9vqv",
+                                "RUSTSEC-2023-0045"
+                            ]
+                        }
+                    ]
+                },
+                {
+                    "package": {
+                        "name": "smallvec",
+                        "version": "1.6.0",
+                        "ecosystem": "crates.io"
+                    },
+                    "vulnerabilities": [
+                        {
+                            "modified": "2023-06-13T20:51:42Z",
+                            "published": "2022-05-24T17:40:21Z",
+                            "schema_version": "1.4.0",
+                            "id": "GHSA-43w2-9j62-hq99",
+                            "aliases": [
+                                "CVE-2021-25900"
+                            ],
+                            "summary": "Buffer overflow in SmallVec::insert_many",
+                            "details": "A bug in the SmallVec::insert_many method caused it to allocate a buffer that was smaller than needed. It then wrote past the end of the buffer, causing a buffer overflow and memory corruption on the heap. This bug was only triggered if the iterator passed to insert_many yielded more items than the lower bound returned from its size_hint method.\n\nThe flaw was corrected in smallvec 0.6.14 and 1.6.1, by ensuring that additional space is always reserved for each item inserted. The fix also simplified the implementation of insert_many to use less unsafe code, so it is easier to verify its correctness.",
+                            "affected": [
+                                {
+                                    "package": {
+                                        "ecosystem": "crates.io",
+                                        "name": "smallvec",
+                                        "purl": "pkg:cargo/smallvec"
+                                    },
+                                    "ranges": [
+                                        {
+                                            "type": "SEMVER",
+                                            "events": [
+                                                {
+                                                    "introduced": "0.6.3"
+                                                },
+                                                {
+                                                    "fixed": "0.6.14"
+                                                }
+                                            ]
+                                        }
+                                    ],
+                                    "database_specific": {
+                                        "source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2022/05/GHSA-43w2-9j62-hq99/GHSA-43w2-9j62-hq99.json"
+                                    },
+                                    "ecosystem_specific": {
+                                        "affected_functions": [
+                                            "smallvec::SmallVec::insert_many"
+                                        ]
+                                    }
+                                },
+                                {
+                                    "package": {
+                                        "ecosystem": "crates.io",
+                                        "name": "smallvec",
+                                        "purl": "pkg:cargo/smallvec"
+                                    },
+                                    "ranges": [
+                                        {
+                                            "type": "SEMVER",
+                                            "events": [
+                                                {
+                                                    "introduced": "1.0.0"
+                                                },
+                                                {
+                                                    "fixed": "1.6.1"
+                                                }
+                                            ]
+                                        }
+                                    ],
+                                    "database_specific": {
+                                        "source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2022/05/GHSA-43w2-9j62-hq99/GHSA-43w2-9j62-hq99.json"
+                                    },
+                                    "ecosystem_specific": {
+                                        "affected_functions": [
+                                            "smallvec::SmallVec::insert_many"
+                                        ]
+                                    }
+                                }
+                            ],
+                            "severity": [
+                                {
+                                    "type": "CVSS_V3",
+                                    "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
+                                }
+                            ],
+                            "references": [
+                                {
+                                    "type": "ADVISORY",
+                                    "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-25900"
+                                },
+                                {
+                                    "type": "WEB",
+                                    "url": "https://github.com/servo/rust-smallvec/issues/252"
+                                },
+                                {
+                                    "type": "PACKAGE",
+                                    "url": "https://github.com/servo/rust-smallvec"
+                                },
+                                {
+                                    "type": "WEB",
+                                    "url": "https://rustsec.org/advisories/RUSTSEC-2021-0003.html"
+                                }
+                            ],
+                            "database_specific": {
+                                "cwe_ids": [
+                                    "CWE-787"
+                                ],
+                                "github_reviewed": true,
+                                "github_reviewed_at": "2022-06-17T00:20:48Z",
+                                "nvd_published_at": "2021-01-26T18:16:00Z",
+                                "severity": "CRITICAL"
+                            }
+                        },
+                        {
+                            "modified": "2023-06-13T13:10:24Z",
+                            "published": "2021-01-08T12:00:00Z",
+                            "schema_version": "1.4.0",
+                            "id": "RUSTSEC-2021-0003",
+                            "aliases": [
+                                "CVE-2021-25900",
+                                "GHSA-43w2-9j62-hq99"
+                            ],
+                            "summary": "Buffer overflow in SmallVec::insert_many",
+                            "details": "A bug in the `SmallVec::insert_many` method caused it to allocate a buffer that was smaller than needed.  It then wrote past the end of the buffer, causing a buffer overflow and memory corruption on the heap.\n\nThis bug was only triggered if the iterator passed to `insert_many` yielded more items than the lower bound returned from its `size_hint` method.\n \nThe flaw was corrected in smallvec 0.6.14 and 1.6.1, by ensuring that additional space is always reserved for each item inserted.  The fix also simplified the implementation of `insert_many` to use less unsafe code, so it is easier to verify its correctness.\n\nThank you to Yechan Bae (@Qwaz) and the Rust group at Georgia Tech’s SSLab for finding and reporting this bug.",
+                            "affected": [
+                                {
+                                    "package": {
+                                        "ecosystem": "crates.io",
+                                        "name": "smallvec",
+                                        "purl": "pkg:cargo/smallvec"
+                                    },
+                                    "ranges": [
+                                        {
+                                            "type": "SEMVER",
+                                            "events": [
+                                                {
+                                                    "introduced": "0.6.3"
+                                                },
+                                                {
+                                                    "fixed": "0.6.14"
+                                                },
+                                                {
+                                                    "introduced": "1.0.0"
+                                                },
+                                                {
+                                                    "fixed": "1.6.1"
+                                                }
+                                            ]
+                                        }
+                                    ],
+                                    "database_specific": {
+                                        "categories": [
+                                            "memory-corruption"
+                                        ],
+                                        "cvss": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
+                                        "informational": null,
+                                        "source": "https://github.com/rustsec/advisory-db/blob/osv/crates/RUSTSEC-2021-0003.json"
+                                    },
+                                    "ecosystem_specific": {
+                                        "affects": {
+                                            "arch": [],
+                                            "functions": [
+                                                "smallvec::SmallVec::insert_many"
+                                            ],
+                                            "os": []
+                                        }
+                                    }
+                                }
+                            ],
+                            "severity": [
+                                {
+                                    "type": "CVSS_V3",
+                                    "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
+                                }
+                            ],
+                            "references": [
+                                {
+                                    "type": "PACKAGE",
+                                    "url": "https://crates.io/crates/smallvec"
+                                },
+                                {
+                                    "type": "ADVISORY",
+                                    "url": "https://rustsec.org/advisories/RUSTSEC-2021-0003.html"
+                                },
+                                {
+                                    "type": "REPORT",
+                                    "url": "https://github.com/servo/rust-smallvec/issues/252"
+                                }
+                            ]
+                        }
+                    ],
+                    "groups": [
+                        {
+                            "ids": [
+                                "GHSA-43w2-9j62-hq99",
+                                "RUSTSEC-2021-0003"
+                            ]
+                        }
+                    ]
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/pkg/lockfile/fixtures/osvscannerresults/not-json.txt b/pkg/lockfile/fixtures/osvscannerresults/not-json.txt
new file mode 100644
index 0000000..319318e
--- /dev/null
+++ b/pkg/lockfile/fixtures/osvscannerresults/not-json.txt
@@ -0,0 +1,1 @@
+this is not valid json! (I think)
diff --git a/pkg/lockfile/fixtures/osvscannerresults/one-package.json b/pkg/lockfile/fixtures/osvscannerresults/one-package.json
new file mode 100644
index 0000000..ceeca26
--- /dev/null
+++ b/pkg/lockfile/fixtures/osvscannerresults/one-package.json
@@ -0,0 +1,21 @@
+{
+  "results": [
+    {
+      "source": {
+        "path": "/path/to/Gemfile.lock",
+        "type": "lockfile"
+      },
+      "packages": [
+        {
+          "package": {
+            "name": "activesupport",
+            "version": "7.0.7",
+            "ecosystem": "RubyGems"
+          },
+          "vulnerabilities": [],
+          "groups": []
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/pkg/lockfile/osv-vuln-results.go b/pkg/lockfile/osv-vuln-results.go
new file mode 100644
index 0000000..8931fab
--- /dev/null
+++ b/pkg/lockfile/osv-vuln-results.go
@@ -0,0 +1,55 @@
+package lockfile
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"github.com/google/osv-scanner/pkg/models"
+)
+
+func ParseOSVScannerResults(pathToLockfile string) ([]PackageDetails, error) {
+	return extractFromFile(pathToLockfile, OSVScannerResultsExtractor{})
+}
+
+type OSVScannerResultsExtractor struct{}
+
+func (e OSVScannerResultsExtractor) ShouldExtract(path string) bool {
+	// The output will always be a custom json file, so don't return a default should extract
+	return false
+}
+
+func (e OSVScannerResultsExtractor) Extract(f DepFile) ([]PackageDetails, error) {
+	parsedResults := models.VulnerabilityResults{}
+	err := json.NewDecoder(f).Decode(&parsedResults)
+
+	if err != nil {
+		return nil, fmt.Errorf("could not extract from %s: %w", f.Path(), err)
+	}
+
+	packages := []PackageDetails{}
+	for _, res := range parsedResults.Results {
+		for _, pkg := range res.Packages {
+			packages = append(packages, PackageDetails{
+				Name:      pkg.Package.Name,
+				Ecosystem: Ecosystem(pkg.Package.Ecosystem),
+				Version:   pkg.Package.Version,
+				CompareAs: Ecosystem(pkg.Package.Ecosystem),
+			})
+		}
+	}
+
+	return packages, nil
+}
+
+var _ Extractor = OSVScannerResultsExtractor{}
+
+// FromOSVScannerResults attempts to extract packages stored in the OSVScannerResults format
+func FromOSVScannerResults(pathToInstalled string) (Lockfile, error) {
+	packages, err := extractFromFile(pathToInstalled, OSVScannerResultsExtractor{})
+
+	return Lockfile{
+		FilePath: pathToInstalled,
+		ParsedAs: "osv-scanner-results",
+		Packages: packages,
+	}, err
+}
diff --git a/pkg/lockfile/parse-requirements-txt.go b/pkg/lockfile/parse-requirements-txt.go
index 90c8057..038df33 100644
--- a/pkg/lockfile/parse-requirements-txt.go
+++ b/pkg/lockfile/parse-requirements-txt.go
@@ -167,6 +167,7 @@ func parseRequirementsTxt(f DepFile, requiredAlready map[string]struct{}) ([]Pac
 		}
 
 		detail := parseLine(line)
+
 		packages[detail.Name+"@"+detail.Version] = detail
 	}
 
diff --git a/renovate.json b/renovate.json
index 9918ff6..238fe59 100644
--- a/renovate.json
+++ b/renovate.json
@@ -20,7 +20,7 @@
       "groupName": "osv-scanner minor"
     },
     {
-      "matchPaths": [".github/"],
+      "matchFileNames": [".github/"],
       "groupName": "workflows"
     }
   ],


Test patch:
diff --git a/pkg/lockfile/helpers_test.go b/pkg/lockfile/helpers_test.go
index 8e5c4e5..c32f9f8 100644
--- a/pkg/lockfile/helpers_test.go
+++ b/pkg/lockfile/helpers_test.go
@@ -31,7 +31,9 @@ func packageToString(pkg lockfile.PackageDetails) string {
 	return fmt.Sprintf("%s@%s (%s, %s)", pkg.Name, pkg.Version, pkg.Ecosystem, commit)
 }
 
-func hasPackage(packages []lockfile.PackageDetails, pkg lockfile.PackageDetails) bool {
+func hasPackage(t *testing.T, packages []lockfile.PackageDetails, pkg lockfile.PackageDetails) bool {
+	t.Helper()
+
 	for _, details := range packages {
 		if details == pkg {
 			return true
@@ -44,7 +46,7 @@ func hasPackage(packages []lockfile.PackageDetails, pkg lockfile.PackageDetails)
 func expectPackage(t *testing.T, packages []lockfile.PackageDetails, pkg lockfile.PackageDetails) {
 	t.Helper()
 
-	if !hasPackage(packages, pkg) {
+	if !hasPackage(t, packages, pkg) {
 		t.Errorf(
 			"Expected packages to include %s@%s (%s, %s), but it did not",
 			pkg.Name,
@@ -55,11 +57,12 @@ func expectPackage(t *testing.T, packages []lockfile.PackageDetails, pkg lockfil
 	}
 }
 
-func findMissingPackages(actualPackages []lockfile.PackageDetails, expectedPackages []lockfile.PackageDetails) []lockfile.PackageDetails {
+func findMissingPackages(t *testing.T, actualPackages []lockfile.PackageDetails, expectedPackages []lockfile.PackageDetails) []lockfile.PackageDetails {
+	t.Helper()
 	var missingPackages []lockfile.PackageDetails
 
 	for _, pkg := range actualPackages {
-		if !hasPackage(expectedPackages, pkg) {
+		if !hasPackage(t, expectedPackages, pkg) {
 			missingPackages = append(missingPackages, pkg)
 		}
 	}
@@ -79,8 +82,8 @@ func expectPackages(t *testing.T, actualPackages []lockfile.PackageDetails, expe
 		)
 	}
 
-	missingActualPackages := findMissingPackages(actualPackages, expectedPackages)
-	missingExpectedPackages := findMissingPackages(expectedPackages, actualPackages)
+	missingActualPackages := findMissingPackages(t, actualPackages, expectedPackages)
+	missingExpectedPackages := findMissingPackages(t, expectedPackages, actualPackages)
 
 	if len(missingActualPackages) != 0 {
 		for _, unexpectedPackage := range missingActualPackages {
diff --git a/pkg/lockfile/osv-vuln-result_test.go b/pkg/lockfile/osv-vuln-result_test.go
new file mode 100644
index 0000000..1317af8
--- /dev/null
+++ b/pkg/lockfile/osv-vuln-result_test.go
@@ -0,0 +1,87 @@
+package lockfile_test
+
+import (
+	"testing"
+
+	"github.com/google/osv-scanner/pkg/lockfile"
+)
+
+func TestParseOSVScannerResults_FileDoesNotExist(t *testing.T) {
+	t.Parallel()
+
+	packages, err := lockfile.ParseOSVScannerResults("fixtures/osvscannerresults/does-not-exist")
+
+	expectErrContaining(t, err, "no such file or directory")
+	expectPackages(t, packages, []lockfile.PackageDetails{})
+}
+
+func TestParseOSVScannerResults_InvalidJSON(t *testing.T) {
+	t.Parallel()
+
+	packages, err := lockfile.ParseOSVScannerResults("fixtures/osvscannerresults/not-json.txt")
+
+	expectErrContaining(t, err, "could not extract from")
+	expectPackages(t, packages, []lockfile.PackageDetails{})
+}
+
+func TestParseOSVScannerResults_NoPackages(t *testing.T) {
+	t.Parallel()
+
+	packages, err := lockfile.ParseOSVScannerResults("fixtures/osvscannerresults/empty.json")
+
+	if err != nil {
+		t.Errorf("Got unexpected error: %v", err)
+	}
+
+	expectPackages(t, packages, []lockfile.PackageDetails{})
+}
+
+func TestParseOSVScannerResults_OnePackage(t *testing.T) {
+	t.Parallel()
+
+	packages, err := lockfile.ParseOSVScannerResults("fixtures/osvscannerresults/one-package.json")
+
+	if err != nil {
+		t.Errorf("Got unexpected error: %v", err)
+	}
+
+	expectPackages(t, packages, []lockfile.PackageDetails{
+		{
+			Name:      "activesupport",
+			Version:   "7.0.7",
+			Ecosystem: lockfile.BundlerEcosystem,
+			CompareAs: lockfile.BundlerEcosystem,
+		},
+	})
+}
+
+func TestParseOSVScannerResults_MultiPackages(t *testing.T) {
+	t.Parallel()
+
+	packages, err := lockfile.ParseOSVScannerResults("fixtures/osvscannerresults/multi-packages-with-vulns.json")
+
+	if err != nil {
+		t.Errorf("Got unexpected error: %v", err)
+	}
+
+	expectPackages(t, packages, []lockfile.PackageDetails{
+		{
+			Name:      "crossbeam-utils",
+			Version:   "0.6.6",
+			Ecosystem: lockfile.CargoEcosystem,
+			CompareAs: lockfile.CargoEcosystem,
+		},
+		{
+			Name:      "memoffset",
+			Version:   "0.5.6",
+			Ecosystem: lockfile.CargoEcosystem,
+			CompareAs: lockfile.CargoEcosystem,
+		},
+		{
+			Name:      "smallvec",
+			Version:   "1.6.0",
+			Ecosystem: lockfile.CargoEcosystem,
+			CompareAs: lockfile.CargoEcosystem,
+		},
+	})
+}