blob: b37711b65f581bd4fb4737f60c73ffb6c30979dd [file] [log] [blame]
/*---------------------------------------------------------
* Copyright 2022 The Go Authors. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------*/
import assert from 'assert';
import path = require('path');
import vscode = require('vscode');
import { VulncheckOutputLinkProvider, VulncheckReport, writeVulns } from '../../src/goVulncheck';
import fs = require('fs');
import { CancellationTokenSource } from 'vscode-languageserver-protocol';
suite('writeVulns', () => {
const fixtureDir = path.join(__dirname, '..', '..', '..', 'test', 'testdata', 'vuln');
function testWriteVulns(res: VulncheckReport | undefined | null, expected: string | RegExp[]) {
const b = [] as string[];
writeVulns(res, { appendLine: (str) => b.push(str + '\n') });
const actual = b.join();
if ('string' === typeof expected) {
assert(actual.search(expected), `actual:\n${actual}\nwant:\n${expected}`);
} else {
// RegExp[]
expected.forEach((want) => assert(actual.match(want), `actual:\n${actual}\nwanted:${want}`));
}
}
function readData(fname: string) {
const data = fs.readFileSync(fname);
return JSON.parse(data.toString());
}
test('No vulnerability', () => testWriteVulns({}, 'No vulnerability found.\n'));
test('Undefined result', () => testWriteVulns(undefined, 'Error - invalid vulncheck result.\n'));
test('Nil result', () => testWriteVulns(null, 'Error - invalid vulncheck result.\n'));
test('Vulns is undefined', () => testWriteVulns({ Vulns: undefined }, 'No vulnerability found.\n'));
test('Vulns is empty', () => testWriteVulns({ Vulns: [] }, 'No vulnerability found.\n'));
test('Modules is empty', () =>
testWriteVulns({ Vulns: [{ OSV: { id: 'foo' }, Modules: [] }] }, 'No vulnerability found.\n'));
test('Nonaffecting', () => {
const vulns = readData(path.join(fixtureDir, 'vulncheck-result-unaffecting.json'));
testWriteVulns(vulns, [
/No vulnerability found\./s,
/# The vulnerabilities below are in packages that you import,/s,
/Found 1 unused vulnerability\./s,
/GO-2022-1059 \(https:\/\/[^)]+\)/s,
/Found Version: golang\.org\/x\/text@v0\.3\.7/s,
/Fixed Version: golang\.org\/x\/text@v0\.3\.8/s,
/Package: golang\.org\/x\/text\/language/s
]);
});
test('Afffecting&Nonaffecting', () => {
const vulns = readData(path.join(fixtureDir, 'vulncheck-result-affecting.json'));
testWriteVulns(vulns, [
/Found 1 affecting vulnerability\./s,
/This is used/s, // details
/Found Version: golang\.org\/x\/text@v0\.3\.5/,
/Fixed Version: golang\.org\/x\/text@v0\.3\.7/,
/- main\.go:15:29: module2\.main calls/,
/\tmodule2.main\n/,
/\t\t\(.*\/main.go:15\)\n/,
/# The vulnerabilities below are in packages that you import,/s,
/Found 1 unused vulnerability\./s,
/GO-2022-1059 \(https:\/\/[^)]+\)/s,
/Found Version: golang\.org\/x\/text@v0\.3\.5/s,
/Fixed Version: golang\.org\/x\/text@v0\.3\.8/s,
/Package: golang\.org\/x\/text\/language/s
]);
});
});
const vulncheckOutput = `
govulncheck ./... for file:///Users/foo/module3/go.mod
08:10:27 Loading packages...
08:10:28 Loaded 2 packages and their dependencies
08:10:30 Found 1 affecting vulns and 0 unaffecting vulns in imported packages
Found 1 affecting vulnerability.
--------------------------------------------------------------------------------
⚠ GO-2020-0040 (https://pkg.go.dev/vuln/GO-2020-0040)
Due to unchecked type assertions, maliciously crafted messages can cause panics, which may be used as a denial of service vector. (CVE-2020-36562)
Found Version: github.com/shiyanhui/dht@v0.0.0-20201219151056-5a20f3199263
Fixed Version: N/A
- lib/lib.go:28:21: module3/lib.Run$2 calls github.com/shiyanhui/dht.DHT.GetPeers
module3/lib.Run
(/home/user/module3/lib/lib.go:25)
module3/lib.Run$2
(/home/user/module3/lib/lib.go:28)`;
suite.only('VulncheckOutputLinkProvider', () => {
let doc: vscode.TextDocument;
let links: vscode.DocumentLink[] | undefined | null;
suiteSetup(async () => {
doc = await vscode.workspace.openTextDocument({ content: vulncheckOutput, language: 'govulncheck' });
const p = new VulncheckOutputLinkProvider();
const tokenSrc = new CancellationTokenSource();
links = await p.provideDocumentLinks(doc, tokenSrc.token);
tokenSrc.dispose();
});
function checkExist(word: string, targetPattern: RegExp, tooltip?: string) {
assert(
links?.some((link) => {
const words = doc.getText(link.range);
return (
words.includes(word) &&
// TODO(hyangah): test the full URI matching. Currently, we do partial checking
// since behavior on windows needs more inspection.
link.target?.toString().search(targetPattern) &&
(!tooltip || link.tooltip === tooltip)
);
}),
`failed to find ${word} ${targetPattern} ${tooltip || ''}\n${JSON.stringify(links)}`
);
}
function checkNotExist(word: string) {
assert(
!links?.some((link) => {
const words = doc.getText(link.range);
return words === word;
}),
`got ${word} that shouldn't exist.\n${JSON.stringify(links)}`
);
}
test('provides links', () => {
assert(links, 'links are empty');
});
test('linkify relative file link', () => {
checkExist('lib/lib.go:28:21', /module3.*lib.go#L28,21/);
});
test('linkify Found Version', () => {
checkExist(
'github.com/shiyanhui/dht@v0.0.0-20201219151056-5a20f3199263',
/pkg\.go\.dev\/github\.com\//,
'https://pkg.go.dev/github.com/shiyanhui/dht@v0.0.0-20201219151056-5a20f3199263'
);
});
test('linkify Fixed Version', () => {
checkNotExist('N/A');
});
test('linkify absolute paths', () => {
checkExist('/home/user/module3/lib/lib.go', /lib.go#L28/);
});
});