Merge branch 'main' into upload-database

This commit is contained in:
Robert 2021-06-18 09:50:05 +01:00
commit 33ac512514
30 changed files with 1177 additions and 158 deletions

View file

@ -13,6 +13,7 @@ import { v4 as uuidV4 } from "uuid";
import { isRunningLocalAction, getRelativeScriptPath } from "./actions-util";
import * as api from "./api-client";
import { PackWithVersion } from "./config-utils";
import * as defaults from "./defaults.json"; // Referenced from codeql-action-sync-tool!
import { errorMatchers } from "./error-matcher";
import { Language } from "./languages";
@ -88,6 +89,12 @@ export interface CodeQL {
queries: string[],
extraSearchPath: string | undefined
): Promise<ResolveQueriesOutput>;
/**
* Run 'codeql pack download'.
*/
packDownload(packs: PackWithVersion[]): Promise<PackDownloadOutput>;
/**
* Run 'codeql database cleanup'.
*/
@ -137,6 +144,17 @@ export interface ResolveQueriesOutput {
};
}
export interface PackDownloadOutput {
packs: PackDownloadItem[];
}
interface PackDownloadItem {
name: string;
version: string;
packDir: string;
installResult: string;
}
/**
* Stores the CodeQL object, and is populated by `setupCodeQL` or `getCodeQL`.
* Can be overridden in tests using `setCodeQL`.
@ -496,6 +514,7 @@ export function setCodeQL(partialCodeql: Partial<CodeQL>): CodeQL {
finalizeDatabase: resolveFunction(partialCodeql, "finalizeDatabase"),
resolveLanguages: resolveFunction(partialCodeql, "resolveLanguages"),
resolveQueries: resolveFunction(partialCodeql, "resolveQueries"),
packDownload: resolveFunction(partialCodeql, "packDownload"),
databaseCleanup: resolveFunction(partialCodeql, "databaseCleanup"),
databaseBundle: resolveFunction(partialCodeql, "databaseBundle"),
databaseRunQueries: resolveFunction(partialCodeql, "databaseRunQueries"),
@ -527,7 +546,7 @@ function getCodeQLForCmd(cmd: string): CodeQL {
return cmd;
},
async printVersion() {
await new toolrunner.ToolRunner(cmd, ["version", "--format=json"]).exec();
await runTool(cmd, ["version", "--format=json"]);
},
async getTracerEnv(databasePath: string) {
// Write tracer-env.js to a temp location.
@ -568,7 +587,7 @@ function getCodeQLForCmd(cmd: string): CodeQL {
// _and_ is present in the latest supported CLI release.)
const envFile = path.resolve(databasePath, "working", "env.tmp");
await new toolrunner.ToolRunner(cmd, [
await runTool(cmd, [
"database",
"trace-command",
databasePath,
@ -576,7 +595,7 @@ function getCodeQLForCmd(cmd: string): CodeQL {
process.execPath,
tracerEnvJs,
envFile,
]).exec();
]);
return JSON.parse(fs.readFileSync(envFile, "utf-8"));
},
async databaseInit(
@ -584,14 +603,14 @@ function getCodeQLForCmd(cmd: string): CodeQL {
language: Language,
sourceRoot: string
) {
await new toolrunner.ToolRunner(cmd, [
await runTool(cmd, [
"database",
"init",
databasePath,
`--language=${language}`,
`--source-root=${sourceRoot}`,
...getExtraOptionsFromEnv(["database", "init"]),
]).exec();
]);
},
async runAutobuild(language: Language) {
const cmdName =
@ -615,7 +634,7 @@ function getCodeQLForCmd(cmd: string): CodeQL {
"-Dmaven.wagon.http.pool=false",
].join(" ");
await new toolrunner.ToolRunner(autobuildCmd).exec();
await runTool(autobuildCmd);
},
async extractScannedLanguage(databasePath: string, language: Language) {
// Get extractor location
@ -680,14 +699,7 @@ function getCodeQLForCmd(cmd: string): CodeQL {
},
async resolveLanguages() {
const codeqlArgs = ["resolve", "languages", "--format=json"];
let output = "";
await new toolrunner.ToolRunner(cmd, codeqlArgs, {
listeners: {
stdout: (data: Buffer) => {
output += data.toString();
},
},
}).exec();
const output = await runTool(cmd, codeqlArgs);
try {
return JSON.parse(output);
@ -711,14 +723,7 @@ function getCodeQLForCmd(cmd: string): CodeQL {
if (extraSearchPath !== undefined) {
codeqlArgs.push("--additional-packs", extraSearchPath);
}
let output = "";
await new toolrunner.ToolRunner(cmd, codeqlArgs, {
listeners: {
stdout: (data: Buffer) => {
output += data.toString();
},
},
}).exec();
const output = await runTool(cmd, codeqlArgs);
try {
return JSON.parse(output);
@ -733,7 +738,7 @@ function getCodeQLForCmd(cmd: string): CodeQL {
memoryFlag: string,
threadsFlag: string
): Promise<void> {
const args = [
const codeqlArgs = [
"database",
"run-queries",
memoryFlag,
@ -744,10 +749,10 @@ function getCodeQLForCmd(cmd: string): CodeQL {
...getExtraOptionsFromEnv(["database", "run-queries"]),
];
if (extraSearchPath !== undefined) {
args.push("--additional-packs", extraSearchPath);
codeqlArgs.push("--additional-packs", extraSearchPath);
}
args.push(querySuitePath);
await new toolrunner.ToolRunner(cmd, args).exec();
codeqlArgs.push(querySuitePath);
await runTool(cmd, codeqlArgs);
},
async databaseInterpretResults(
databasePath: string,
@ -757,7 +762,7 @@ function getCodeQLForCmd(cmd: string): CodeQL {
threadsFlag: string,
automationDetailsId: string | undefined
): Promise<string> {
const args = [
const codeqlArgs = [
"database",
"interpret-results",
threadsFlag,
@ -770,31 +775,64 @@ function getCodeQLForCmd(cmd: string): CodeQL {
...getExtraOptionsFromEnv(["database", "interpret-results"]),
];
if (automationDetailsId !== undefined) {
args.push("--sarif-category", automationDetailsId);
codeqlArgs.push("--sarif-category", automationDetailsId);
}
args.push(databasePath, ...querySuitePaths);
codeqlArgs.push(databasePath, ...querySuitePaths);
// capture stdout, which contains analysis summaries
let output = "";
await new toolrunner.ToolRunner(cmd, args, {
listeners: {
stdout: (data: Buffer) => {
output += data.toString("utf8");
},
},
}).exec();
return output;
return await runTool(cmd, codeqlArgs);
},
/**
* Download specified packs into the package cache. If the specified
* package and version already exists (e.g., from a previous analysis run),
* then it is not downloaded again (unless the extra option `--force` is
* specified).
*
* If no version is specified, then the latest version is
* downloaded. The check to determine what the latest version is is done
* each time this package is requested.
*/
async packDownload(packs: PackWithVersion[]): Promise<PackDownloadOutput> {
const codeqlArgs = [
"pack",
"download",
"--format=json",
...getExtraOptionsFromEnv(["pack", "download"]),
...packs.map(packWithVersionToString),
];
const output = await runTool(cmd, codeqlArgs);
try {
const parsedOutput: PackDownloadOutput = JSON.parse(output);
if (
Array.isArray(parsedOutput.packs) &&
// TODO PackDownloadOutput will not include the version if it is not specified
// in the input. The version is always the latest version available.
// It should be added to the output, but this requires a CLI change
parsedOutput.packs.every((p) => p.name /* && p.version */)
) {
return parsedOutput;
} else {
throw new Error("Unexpected output from pack download");
}
} catch (e) {
throw new Error(
`Attempted to download specified packs but got an error:\n${output}\n${e}`
);
}
},
async databaseCleanup(
databasePath: string,
cleanupLevel: string
): Promise<void> {
const args = [
const codeqlArgs = [
"database",
"cleanup",
databasePath,
`--mode=${cleanupLevel}`,
];
await new toolrunner.ToolRunner(cmd, args).exec();
await runTool(cmd, codeqlArgs);
},
async databaseBundle(
databasePath: string,
@ -811,6 +849,9 @@ function getCodeQLForCmd(cmd: string): CodeQL {
};
}
function packWithVersionToString(pack: PackWithVersion): string {
return pack.version ? `${pack.packName}@${pack.version}` : pack.packName;
}
/**
* Gets the options for `path` of `options` as an array of extra option strings.
*/
@ -870,3 +911,15 @@ export function getExtraOptions(
);
return all.concat(specific);
}
async function runTool(cmd: string, args: string[] = []) {
let output = "";
await new toolrunner.ToolRunner(cmd, args, {
listeners: {
stdout: (data: Buffer) => {
output += data.toString();
},
},
}).exec();
return output;
}