When using codescanning config call run queries a single time

When the codescanning config is being used by the CLI, there is a
single query suite that is generated that contains all queries to be
run by the analysis. This is different from the traditional way, where
there are potentially three query suites: builtin, custom, and packs.

We need to ensure that when the codescanning config is being used,
only a single call to run queries is used, and this call uses the
single generated query suite.

Also, this commit changes the cutoff version for codescanning config to
2.10.1. Earlier versions work, but there were some bugs that are only
fixed in 2.10.1 and later.
This commit is contained in:
Andrew Eisenberg 2022-06-29 12:50:24 -07:00
parent 6fabde2be8
commit 8688a09e14
7 changed files with 199 additions and 146 deletions

View file

@ -227,6 +227,7 @@ export async function runQueries(
);
}
const codeql = await getCodeQL(config.codeQLCmd);
for (const language of config.languages) {
const queries = config.queries[language];
const packsWithVersion = config.packs[language] || [];
@ -241,89 +242,117 @@ export async function runQueries(
);
}
const codeql = await getCodeQL(config.codeQLCmd);
try {
if (
hasPackWithCustomQueries &&
!(await util.useCodeScanningConfigInCli(codeql))
) {
logger.info("Performing analysis with custom CodeQL Packs.");
logger.startGroup(`Downloading custom packs for ${language}`);
const results = await codeql.packDownload(packsWithVersion);
logger.info(
`Downloaded packs: ${results.packs
.map((r) => `${r.name}@${r.version || "latest"}`)
.join(", ")}`
);
logger.endGroup();
}
logger.startGroup(`Running queries for ${language}`);
const querySuitePaths: string[] = [];
if (queries["builtin"].length > 0) {
if (await util.useCodeScanningConfigInCli(codeql)) {
// If we are using the codescanning config in the CLI,
// much of the work needed to generate the query suites
// is done in the CLI. We just need to make a single
// call to run all the queries for each language and
// another to interpret the results.
logger.startGroup(`Running queries for ${language}`);
const startTimeBuiltIn = new Date().getTime();
querySuitePaths.push(
await runQueryGroup(
language,
"builtin",
createQuerySuiteContents(queries["builtin"]),
undefined
)
);
await runQueryGroup(language, "all", undefined, undefined);
// TODO should not be using `builtin` here. We should be using `all` instead.
// The status report does not support `all` yet.
statusReport[`analyze_builtin_queries_${language}_duration_ms`] =
new Date().getTime() - startTimeBuiltIn;
}
const startTimeCustom = new Date().getTime();
let ranCustom = false;
for (let i = 0; i < queries["custom"].length; ++i) {
if (queries["custom"][i].queries.length > 0) {
logger.startGroup(`Interpreting results for ${language}`);
const startTimeInterpretResults = new Date().getTime();
const sarifFile = path.join(sarifFolder, `${language}.sarif`);
const analysisSummary = await runInterpretResults(
language,
undefined,
sarifFile
);
statusReport[`interpret_results_${language}_duration_ms`] =
new Date().getTime() - startTimeInterpretResults;
logger.endGroup();
logger.info(analysisSummary);
} else {
if (hasPackWithCustomQueries) {
logger.info("Performing analysis with custom CodeQL Packs.");
logger.startGroup(`Downloading custom packs for ${language}`);
const results = await codeql.packDownload(packsWithVersion);
logger.info(
`Downloaded packs: ${results.packs
.map((r) => `${r.name}@${r.version || "latest"}`)
.join(", ")}`
);
logger.endGroup();
}
logger.startGroup(`Running queries for ${language}`);
const querySuitePaths: string[] = [];
if (queries["builtin"].length > 0) {
const startTimeBuiltIn = new Date().getTime();
querySuitePaths.push(
await runQueryGroup(
(await runQueryGroup(
language,
`custom-${i}`,
createQuerySuiteContents(queries["custom"][i].queries),
queries["custom"][i].searchPath
)
"builtin",
createQuerySuiteContents(queries["builtin"]),
undefined
)) as string
);
statusReport[`analyze_builtin_queries_${language}_duration_ms`] =
new Date().getTime() - startTimeBuiltIn;
}
const startTimeCustom = new Date().getTime();
let ranCustom = false;
for (let i = 0; i < queries["custom"].length; ++i) {
if (queries["custom"][i].queries.length > 0) {
querySuitePaths.push(
(await runQueryGroup(
language,
`custom-${i}`,
createQuerySuiteContents(queries["custom"][i].queries),
queries["custom"][i].searchPath
)) as string
);
ranCustom = true;
}
}
if (packsWithVersion.length > 0) {
querySuitePaths.push(
...(await runQueryPacks(
language,
"packs",
packsWithVersion,
undefined
))
);
ranCustom = true;
}
}
if (packsWithVersion.length > 0) {
querySuitePaths.push(
...(await runQueryPacks(
language,
"packs",
packsWithVersion,
undefined
))
if (ranCustom) {
statusReport[`analyze_custom_queries_${language}_duration_ms`] =
new Date().getTime() - startTimeCustom;
}
logger.endGroup();
logger.startGroup(`Interpreting results for ${language}`);
const startTimeInterpretResults = new Date().getTime();
const sarifFile = path.join(sarifFolder, `${language}.sarif`);
const analysisSummary = await runInterpretResults(
language,
querySuitePaths,
sarifFile
);
ranCustom = true;
if (!cliCanCountBaseline) {
await injectLinesOfCode(sarifFile, language, locPromise);
}
statusReport[`interpret_results_${language}_duration_ms`] =
new Date().getTime() - startTimeInterpretResults;
logger.endGroup();
logger.info(analysisSummary);
}
if (ranCustom) {
statusReport[`analyze_custom_queries_${language}_duration_ms`] =
new Date().getTime() - startTimeCustom;
}
logger.endGroup();
logger.startGroup(`Interpreting results for ${language}`);
const startTimeInterpretResults = new Date().getTime();
const sarifFile = path.join(sarifFolder, `${language}.sarif`);
const analysisSummary = await runInterpretResults(
language,
querySuitePaths,
sarifFile
);
if (!cliCanCountBaseline)
await injectLinesOfCode(sarifFile, language, locPromise);
statusReport[`interpret_results_${language}_duration_ms`] =
new Date().getTime() - startTimeInterpretResults;
logger.endGroup();
logger.info(analysisSummary);
if (!cliCanCountBaseline || debugMode)
if (!cliCanCountBaseline || debugMode) {
printLinesOfCodeSummary(logger, language, await locPromise);
if (cliCanCountBaseline) logger.info(await runPrintLinesOfCode(language));
}
if (cliCanCountBaseline) {
logger.info(await runPrintLinesOfCode(language));
}
} catch (e) {
logger.info(String(e));
if (e instanceof Error) {
@ -341,11 +370,10 @@ export async function runQueries(
async function runInterpretResults(
language: Language,
queries: string[],
queries: string[] | undefined,
sarifFile: string
): Promise<string> {
const databasePath = util.getCodeQLDatabasePath(config, language);
const codeql = await getCodeQL(config.codeQLCmd);
return await codeql.databaseInterpretResults(
databasePath,
queries,
@ -365,26 +393,27 @@ export async function runQueries(
async function runPrintLinesOfCode(language: Language): Promise<string> {
const databasePath = util.getCodeQLDatabasePath(config, language);
const codeql = await getCodeQL(config.codeQLCmd);
return await codeql.databasePrintBaseline(databasePath);
}
async function runQueryGroup(
language: Language,
type: string,
querySuiteContents: string,
querySuiteContents: string | undefined,
searchPath: string | undefined
): Promise<string> {
): Promise<string | undefined> {
const databasePath = util.getCodeQLDatabasePath(config, language);
// Pass the queries to codeql using a file instead of using the command
// line to avoid command line length restrictions, particularly on windows.
const querySuitePath = `${databasePath}-queries-${type}.qls`;
fs.writeFileSync(querySuitePath, querySuiteContents);
logger.debug(
`Query suite file for ${language}-${type}...\n${querySuiteContents}`
);
const codeql = await getCodeQL(config.codeQLCmd);
const querySuitePath = querySuiteContents
? `${databasePath}-queries-${type}.qls`
: undefined;
if (querySuiteContents && querySuitePath) {
fs.writeFileSync(querySuitePath, querySuiteContents);
logger.debug(
`Query suite file for ${language}-${type}...\n${querySuiteContents}`
);
}
await codeql.databaseRunQueries(
databasePath,
searchPath,
@ -409,7 +438,6 @@ export async function runQueries(
for (const pack of packs) {
logger.debug(`Running query pack for ${language}-${type}: ${pack}`);
const codeql = await getCodeQL(config.codeQLCmd);
await codeql.databaseRunQueries(
databasePath,
searchPath,

View file

@ -144,7 +144,7 @@ export interface CodeQL {
databaseRunQueries(
databasePath: string,
extraSearchPath: string | undefined,
querySuitePath: string,
querySuitePath: string | undefined,
memoryFlag: string,
threadsFlag: string
): Promise<void>;
@ -153,7 +153,7 @@ export interface CodeQL {
*/
databaseInterpretResults(
databasePath: string,
querySuitePaths: string[],
querySuitePaths: string[] | undefined,
sarifFile: string,
addSnippetsFlag: string,
threadsFlag: string,
@ -226,9 +226,9 @@ const CODEQL_VERSION_GROUP_RULES = "2.5.5";
const CODEQL_VERSION_SARIF_GROUP = "2.5.3";
export const CODEQL_VERSION_COUNTS_LINES = "2.6.2";
const CODEQL_VERSION_CUSTOM_QUERY_HELP = "2.7.1";
export const CODEQL_VERSION_CONFIG_FILES = "2.8.2"; // Versions before 2.8.2 weren't tolerant to unknown properties
export const CODEQL_VERSION_ML_POWERED_QUERIES = "2.7.5";
const CODEQL_VERSION_LUA_TRACER_CONFIG = "2.10.0";
export const CODEQL_VERSION_CONFIG_FILES = "2.10.1";
/**
* This variable controls using the new style of tracing from the CodeQL
@ -924,7 +924,7 @@ async function getCodeQLForCmd(
async databaseRunQueries(
databasePath: string,
extraSearchPath: string | undefined,
querySuitePath: string,
querySuitePath: string | undefined,
memoryFlag: string,
threadsFlag: string
): Promise<void> {
@ -941,14 +941,14 @@ async function getCodeQLForCmd(
if (extraSearchPath !== undefined) {
codeqlArgs.push("--additional-packs", extraSearchPath);
}
if (!(await util.useCodeScanningConfigInCli(this))) {
if (querySuitePath) {
codeqlArgs.push(querySuitePath);
}
await runTool(cmd, codeqlArgs);
},
async databaseInterpretResults(
databasePath: string,
querySuitePaths: string[],
querySuitePaths: string[] | undefined,
sarifFile: string,
addSnippetsFlag: string,
threadsFlag: string,
@ -979,7 +979,7 @@ async function getCodeQLForCmd(
codeqlArgs.push("--sarif-category", automationDetailsId);
}
codeqlArgs.push(databasePath);
if (!(await util.useCodeScanningConfigInCli(this))) {
if (querySuitePaths) {
codeqlArgs.push(...querySuitePaths);
}
// capture stdout, which contains analysis summaries