Skip to content

Commit 6a6fd4b

Browse files
authored
Merge pull request #64 from sonukapoor/codex/issue-63-osv-advisory-source-tests
test: add OSV advisory source tests
2 parents 4845de9 + 7fe7d50 commit 6a6fd4b

1 file changed

Lines changed: 144 additions & 0 deletions

File tree

tests/osv-advisory-source.test.ts

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import { jest } from "@jest/globals";
2+
import type { PackageRef } from "../src/types.js";
3+
import { OsvAdvisorySource } from "../src/advisory/osv-advisory-source.js";
4+
5+
const fetchMock = jest.fn();
6+
global.fetch = fetchMock as unknown as typeof fetch;
7+
8+
function createPackages(): PackageRef[] {
9+
return [
10+
{
11+
name: "lodash",
12+
version: "4.17.20",
13+
ecosystem: "npm",
14+
},
15+
{
16+
name: "@scope/pkg",
17+
version: "1.2.3",
18+
ecosystem: "npm",
19+
},
20+
];
21+
}
22+
23+
describe("OsvAdvisorySource", () => {
24+
beforeEach(() => {
25+
fetchMock.mockReset();
26+
});
27+
28+
it("queries the OSV batch endpoint with the expected request body and maps results", async () => {
29+
const packages = createPackages();
30+
fetchMock.mockResolvedValue({
31+
ok: true,
32+
json: async () => ({
33+
results: [
34+
{ vulns: [{ id: "OSV-123" }] },
35+
{},
36+
],
37+
}),
38+
});
39+
40+
const source = new OsvAdvisorySource("https://example.test");
41+
const results = await source.queryBatch(packages);
42+
43+
expect(fetchMock).toHaveBeenCalledWith("https://example.test/v1/querybatch", {
44+
method: "POST",
45+
headers: {
46+
"Content-Type": "application/json",
47+
},
48+
body: JSON.stringify({
49+
queries: [
50+
{
51+
package: { ecosystem: "npm", name: "lodash" },
52+
version: "4.17.20",
53+
},
54+
{
55+
package: { ecosystem: "npm", name: "@scope/pkg" },
56+
version: "1.2.3",
57+
},
58+
],
59+
}),
60+
});
61+
62+
expect(results).toEqual([
63+
{
64+
package: "lodash",
65+
version: "4.17.20",
66+
vulnerabilities: [{ id: "OSV-123" }],
67+
},
68+
{
69+
package: "@scope/pkg",
70+
version: "1.2.3",
71+
vulnerabilities: [],
72+
},
73+
]);
74+
});
75+
76+
it("wraps non-ok batch responses with the configured base URL", async () => {
77+
fetchMock.mockResolvedValue({
78+
ok: false,
79+
status: 502,
80+
statusText: "Bad Gateway",
81+
});
82+
83+
const source = new OsvAdvisorySource("https://mirror.test");
84+
85+
await expect(source.queryBatch(createPackages())).rejects.toThrow(
86+
"OSV batch query failed for https://mirror.test: OSV batch query failed: 502 Bad Gateway",
87+
);
88+
});
89+
90+
it("wraps thrown batch fetch errors", async () => {
91+
fetchMock.mockRejectedValue(new Error("socket hang up"));
92+
93+
const source = new OsvAdvisorySource("https://mirror.test");
94+
95+
await expect(source.queryBatch(createPackages())).rejects.toThrow(
96+
"OSV batch query failed for https://mirror.test: socket hang up",
97+
);
98+
});
99+
100+
it("fetches a single vulnerability by encoded id", async () => {
101+
fetchMock.mockResolvedValue({
102+
ok: true,
103+
json: async () => ({
104+
id: "GHSA-abcd/1234",
105+
aliases: ["CVE-2026-0001"],
106+
}),
107+
});
108+
109+
const source = new OsvAdvisorySource("https://example.test");
110+
const vuln = await source.getVuln("GHSA-abcd/1234");
111+
112+
expect(fetchMock).toHaveBeenCalledWith(
113+
"https://example.test/v1/vulns/GHSA-abcd%2F1234",
114+
);
115+
expect(vuln).toMatchObject({
116+
id: "GHSA-abcd/1234",
117+
aliases: ["CVE-2026-0001"],
118+
});
119+
});
120+
121+
it("wraps non-ok vulnerability fetch responses", async () => {
122+
fetchMock.mockResolvedValue({
123+
ok: false,
124+
status: 404,
125+
statusText: "Not Found",
126+
});
127+
128+
const source = new OsvAdvisorySource("https://example.test");
129+
130+
await expect(source.getVuln("OSV-404")).rejects.toThrow(
131+
"OSV vuln fetch failed for OSV-404 via https://example.test: OSV vuln fetch failed for OSV-404: 404 Not Found",
132+
);
133+
});
134+
135+
it("wraps thrown vulnerability fetch errors", async () => {
136+
fetchMock.mockRejectedValue(new Error("network unavailable"));
137+
138+
const source = new OsvAdvisorySource("https://example.test");
139+
140+
await expect(source.getVuln("OSV-500")).rejects.toThrow(
141+
"OSV vuln fetch failed for OSV-500 via https://example.test: network unavailable",
142+
);
143+
});
144+
});

0 commit comments

Comments
 (0)