blob: b9b19e3db5d5f78c40c79745c2db695d8500d603 [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 sinon = require('sinon');
import vscode = require('vscode');
import { VulncheckTerminal } from '../../src/goVulncheck';
import { ExecuteCommandParams, ExecuteCommandRequest } from 'vscode-languageserver-protocol';
import { Env, FakeOutputChannel } from './goplsTestEnv.utils';
import { URI } from 'vscode-uri';
import { getGoConfig } from '../../src/config';
suite('writeVulns', function () {
this.timeout(30000);
const sandbox = sinon.createSandbox(); // for suite
const env = new Env();
// This test suite will start an editor that opens a go workspace in test/testdata/vuln
// that includes mod1 (that has some vulnerabilities) and mod2 (that has 0 dependency).
// By reusing the editor session, we reduce the test time by 1.5~2 seconds for each test.
const fixtureDir = path.join(__dirname, '..', '..', '..', 'test', 'testdata', 'vuln');
// Tests will run govulncheck and see if expected output is accumulated in fakeTerminal.
const fakeTerminal = new FakeOutputChannel();
suiteSetup(async () => {
const config = require('../../src/config');
const goConfig = Object.create(getGoConfig(), {
// User the GOVULNDB that contains two OSV entries on golang.org/x/text and stdlib modules.
toolsEnvVars: { value: { GOVULNDB: URI.file(path.join(fixtureDir, 'vulndb')).toString() } }
}) as vscode.WorkspaceConfiguration;
sandbox.stub(config, 'getGoConfig').returns(goConfig);
await env.startGopls(undefined, goConfig, fixtureDir);
sandbox.stub(VulncheckTerminal, 'Open').returns({
appendLine: fakeTerminal.appendLine,
show: () => {},
exit: () => {}
});
});
this.afterEach(async function () {
if (this.currentTest?.state === 'failed') {
console.log('=== Gopls Trace ===');
env.flushTrace(true);
console.log('=== Vulncheck Terminal Output ===');
console.log(fakeTerminal.toString());
}
env.flushTrace(false);
fakeTerminal.clear();
});
suiteTeardown(async () => {
await env.teardown();
sandbox.restore();
});
test('govulncheck finds vulnerabilities', async () => {
const workspaceDir = path.join(fixtureDir, 'mod1');
const output = await testRunGovulncheck(workspaceDir);
const sections = output.toString().split(' Informational ');
assert(sections.length >= 2, `got ${JSON.stringify(sections)}`);
assert(sections[0].includes('GO-1970-TEXT'));
assert(sections[1].includes('GO-1970-FMT'));
assert(sections[1].includes('vulnerabilities found'));
});
test('govulncheck finds no vulnerabilities', async () => {
const workspaceDir = path.join(fixtureDir, 'mod2');
const output = await testRunGovulncheck(workspaceDir);
assert(output.toString().includes('No vulnerabilities found'));
});
async function testRunGovulncheck(workspaceDir: string) {
const languageClient = env.languageClient!;
const document = await vscode.workspace.openTextDocument(vscode.Uri.file(path.join(workspaceDir, 'go.mod')));
const uri = languageClient.code2ProtocolConverter.asTextDocumentIdentifier(document).uri;
languageClient.middleware!.executeCommand!('gopls.run_govulncheck', [{ URI: uri }], async (cmd, args) => {
const params: ExecuteCommandParams = {
command: cmd,
arguments: args
};
return await languageClient?.sendRequest(ExecuteCommandRequest.type, params);
});
const msg = 'Share feedback';
const timeoutMS = 10000;
await new Promise<void>((resolve, reject) => {
const timeout = setTimeout(() => {
reject(`Timed out while waiting for '${msg}'`);
}, timeoutMS);
fakeTerminal.onPattern(msg, () => {
clearTimeout(timeout);
resolve();
});
});
return fakeTerminal;
}
});