split up builtin and custom queries
This commit is contained in:
parent
75af0bf309
commit
0539269665
12 changed files with 322 additions and 117 deletions
48
lib/analyze.js
generated
48
lib/analyze.js
generated
|
|
@ -39,35 +39,45 @@ async function finalizeDatabaseCreation(config, logger) {
|
|||
}
|
||||
// Runs queries and creates sarif files in the given folder
|
||||
async function runQueries(sarifFolder, memoryFlag, threadsFlag, config, logger) {
|
||||
const codeql = codeql_1.getCodeQL(config.codeQLCmd);
|
||||
const statusReport = {};
|
||||
for (let language of config.languages) {
|
||||
logger.startGroup('Analyzing ' + language);
|
||||
const queries = config.queries[language] || [];
|
||||
if (queries.length === 0) {
|
||||
const queries = config.queries[language];
|
||||
if (queries.builtin.length === 0 && queries.custom.length === 0) {
|
||||
throw new Error('Unable to analyse ' + language + ' as no queries were selected for this language');
|
||||
}
|
||||
try {
|
||||
const databasePath = util.getCodeQLDatabasePath(config.tempDir, 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 querySuite = databasePath + '-queries.qls';
|
||||
const querySuiteContents = queries.map(q => '- query: ' + q).join('\n');
|
||||
fs.writeFileSync(querySuite, querySuiteContents);
|
||||
logger.debug('Query suite file for ' + language + '...\n' + querySuiteContents);
|
||||
const sarifFile = path.join(sarifFolder, language + '.sarif');
|
||||
await codeql.databaseAnalyze(databasePath, sarifFile, querySuite, memoryFlag, threadsFlag);
|
||||
logger.debug('SARIF results for database ' + language + ' created at "' + sarifFile + '"');
|
||||
logger.endGroup();
|
||||
for (const type of ['builtin', 'custom']) {
|
||||
if (queries[type].length > 0) {
|
||||
const startTime = new Date().getTime();
|
||||
const databasePath = util.getCodeQLDatabasePath(config.tempDir, 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`;
|
||||
const querySuiteContents = queries[type].map((q) => '- query: ' + q).join('\n');
|
||||
fs.writeFileSync(querySuitePath, querySuiteContents);
|
||||
logger.debug('Query suite file for ' + language + '...\n' + querySuiteContents);
|
||||
const sarifFile = path.join(sarifFolder, `${language}-${type}.sarif`);
|
||||
const codeql = codeql_1.getCodeQL(config.codeQLCmd);
|
||||
await codeql.databaseAnalyze(databasePath, sarifFile, querySuitePath, memoryFlag, threadsFlag);
|
||||
logger.debug('SARIF results for database ' + language + ' created at "' + sarifFile + '"');
|
||||
logger.endGroup();
|
||||
// Record the performance
|
||||
const endTime = new Date().getTime();
|
||||
statusReport[`analyze_${type}_queries_${language}_duration_ms`] = endTime - startTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
// For now the fields about query performance are not populated
|
||||
return {
|
||||
analyze_failure_language: language,
|
||||
};
|
||||
logger.error(`Error running analysis for ${language}: ${e}`);
|
||||
logger.info(e);
|
||||
statusReport.analyze_failure_language = language;
|
||||
return statusReport;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
return statusReport;
|
||||
}
|
||||
exports.runQueries = runQueries;
|
||||
async function runAnalyze(repositoryNwo, commitOid, ref, analysisKey, analysisName, workflowRunID, checkoutPath, environment, githubAuth, githubUrl, doUpload, mode, outputDir, memoryFlag, threadsFlag, config, logger) {
|
||||
// Delete the tracer config env var to avoid tracing ourselves
|
||||
delete process.env[sharedEnv.ODASA_TRACER_CONFIGURATION];
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../src/analyze.ts"],"names":[],"mappings":"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"}
|
||||
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../src/analyze.ts"],"names":[],"mappings":"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"}
|
||||
60
lib/analyze.test.js
generated
Normal file
60
lib/analyze.test.js
generated
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||
result["default"] = mod;
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const ava_1 = __importDefault(require("ava"));
|
||||
const fs = __importStar(require("fs"));
|
||||
const analyze_1 = require("./analyze");
|
||||
const codeql_1 = require("./codeql");
|
||||
const languages_1 = require("./languages");
|
||||
const logging_1 = require("./logging");
|
||||
const testing_utils_1 = require("./testing-utils");
|
||||
const util = __importStar(require("./util"));
|
||||
testing_utils_1.setupTests(ava_1.default);
|
||||
// Checks that the duration fields are populated for the correct language
|
||||
// and correct case of builtin or custom.
|
||||
ava_1.default('status report fields', async (t) => {
|
||||
return await util.withTmpDir(async (tmpDir) => {
|
||||
codeql_1.setCodeQL({
|
||||
databaseAnalyze: async () => undefined
|
||||
});
|
||||
const memoryFlag = '';
|
||||
const threadsFlag = '';
|
||||
for (const language of Object.values(languages_1.Language)) {
|
||||
const config = {
|
||||
languages: [language],
|
||||
queries: {},
|
||||
pathsIgnore: [],
|
||||
paths: [],
|
||||
originalUserInput: {},
|
||||
tempDir: tmpDir,
|
||||
toolCacheDir: tmpDir,
|
||||
codeQLCmd: '',
|
||||
};
|
||||
fs.mkdirSync(util.getCodeQLDatabasePath(config.tempDir, language), { recursive: true });
|
||||
config.queries[language] = {
|
||||
builtin: ['foo.ql'],
|
||||
custom: [],
|
||||
};
|
||||
const builtinStatusReport = await analyze_1.runQueries(tmpDir, memoryFlag, threadsFlag, config, logging_1.getRunnerLogger(true));
|
||||
t.deepEqual(Object.keys(builtinStatusReport).length, 1);
|
||||
t.true(`analyze_builtin_queries_${language}_duration_ms` in builtinStatusReport);
|
||||
config.queries[language] = {
|
||||
builtin: [],
|
||||
custom: ['foo.ql'],
|
||||
};
|
||||
const customStatusReport = await analyze_1.runQueries(tmpDir, memoryFlag, threadsFlag, config, logging_1.getRunnerLogger(true));
|
||||
t.deepEqual(Object.keys(customStatusReport).length, 1);
|
||||
t.true(`analyze_custom_queries_${language}_duration_ms` in customStatusReport);
|
||||
}
|
||||
});
|
||||
});
|
||||
//# sourceMappingURL=analyze.test.js.map
|
||||
1
lib/analyze.test.js.map
Normal file
1
lib/analyze.test.js.map
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"analyze.test.js","sourceRoot":"","sources":["../src/analyze.test.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,8CAAuB;AACvB,uCAAyB;AAEzB,uCAAuC;AACvC,qCAAqC;AAErC,2CAAuC;AACvC,uCAA4C;AAC5C,mDAA6C;AAC7C,6CAA+B;AAE/B,0BAAU,CAAC,aAAI,CAAC,CAAC;AAEjB,yEAAyE;AACzE,yCAAyC;AACzC,aAAI,CAAC,sBAAsB,EAAE,KAAK,EAAC,CAAC,EAAC,EAAE;IACrC,OAAO,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,EAAC,MAAM,EAAC,EAAE;QAC1C,kBAAS,CAAC;YACR,eAAe,EAAE,KAAK,IAAI,EAAE,CAAC,SAAS;SACvC,CAAC,CAAC;QAEH,MAAM,UAAU,GAAG,EAAE,CAAC;QACtB,MAAM,WAAW,GAAG,EAAE,CAAC;QAEvB,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,oBAAQ,CAAC,EAAE;YAC9C,MAAM,MAAM,GAAW;gBACrB,SAAS,EAAE,CAAC,QAAQ,CAAC;gBACrB,OAAO,EAAE,EAAE;gBACX,WAAW,EAAE,EAAE;gBACf,KAAK,EAAE,EAAE;gBACT,iBAAiB,EAAE,EAAE;gBACrB,OAAO,EAAE,MAAM;gBACf,YAAY,EAAE,MAAM;gBACpB,SAAS,EAAE,EAAE;aACd,CAAC;YACF,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAExF,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG;gBACzB,OAAO,EAAE,CAAC,QAAQ,CAAC;gBACnB,MAAM,EAAE,EAAE;aACX,CAAC;YACF,MAAM,mBAAmB,GAAG,MAAM,oBAAU,CAC1C,MAAM,EACN,UAAU,EACV,WAAW,EACX,MAAM,EACN,yBAAe,CAAC,IAAI,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACxD,CAAC,CAAC,IAAI,CAAC,2BAA2B,QAAQ,cAAc,IAAI,mBAAmB,CAAC,CAAC;YAEjF,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG;gBACzB,OAAO,EAAE,EAAE;gBACX,MAAM,EAAE,CAAC,QAAQ,CAAC;aACnB,CAAC;YACF,MAAM,kBAAkB,GAAG,MAAM,oBAAU,CACzC,MAAM,EACN,UAAU,EACV,WAAW,EACX,MAAM,EACN,yBAAe,CAAC,IAAI,CAAC,CAAC,CAAC;YACzB,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACvD,CAAC,CAAC,IAAI,CAAC,0BAA0B,QAAQ,cAAc,IAAI,kBAAkB,CAAC,CAAC;SAChF;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
||||
41
lib/config-utils.js
generated
41
lib/config-utils.js
generated
|
|
@ -61,25 +61,39 @@ function validateQueries(resolvedQueries) {
|
|||
}
|
||||
/**
|
||||
* Run 'codeql resolve queries' and add the results to resultMap
|
||||
*
|
||||
* If a checkout path is given then the queries are assumed to be custom queries
|
||||
* and an error will be thrown if there is anything invalid about the queries.
|
||||
* If a checkout path is not given then the queries are assumed to be builtin
|
||||
* queries, and error checking will be suppressed.
|
||||
*/
|
||||
async function runResolveQueries(codeQL, resultMap, toResolve, extraSearchPath, errorOnInvalidQueries) {
|
||||
async function runResolveQueries(codeQL, resultMap, toResolve, extraSearchPath) {
|
||||
const resolvedQueries = await codeQL.resolveQueries(toResolve, extraSearchPath);
|
||||
for (const [language, queries] of Object.entries(resolvedQueries.byLanguage)) {
|
||||
if (resultMap[language] === undefined) {
|
||||
resultMap[language] = [];
|
||||
}
|
||||
resultMap[language].push(...Object.keys(queries).filter(q => !queryIsDisabled(language, q)));
|
||||
}
|
||||
if (errorOnInvalidQueries) {
|
||||
if (extraSearchPath !== undefined) {
|
||||
validateQueries(resolvedQueries);
|
||||
}
|
||||
for (const [language, queryPaths] of Object.entries(resolvedQueries.byLanguage)) {
|
||||
if (resultMap[language] === undefined) {
|
||||
resultMap[language] = {
|
||||
builtin: [],
|
||||
custom: [],
|
||||
};
|
||||
}
|
||||
const queries = Object.keys(queryPaths).filter(q => !queryIsDisabled(language, q));
|
||||
if (extraSearchPath !== undefined) {
|
||||
resultMap[language].custom.push(...queries);
|
||||
}
|
||||
else {
|
||||
resultMap[language].builtin.push(...queries);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get the set of queries included by default.
|
||||
*/
|
||||
async function addDefaultQueries(codeQL, languages, resultMap) {
|
||||
const suites = languages.map(l => l + '-code-scanning.qls');
|
||||
await runResolveQueries(codeQL, resultMap, suites, undefined, false);
|
||||
await runResolveQueries(codeQL, resultMap, suites, undefined);
|
||||
}
|
||||
// The set of acceptable values for built-in suites from the codeql bundle
|
||||
const builtinSuites = ['security-extended', 'security-and-quality'];
|
||||
|
|
@ -93,7 +107,7 @@ async function addBuiltinSuiteQueries(languages, codeQL, resultMap, suiteName, c
|
|||
throw new Error(getQueryUsesInvalid(configFile, suiteName));
|
||||
}
|
||||
const suites = languages.map(l => l + '-' + suiteName + '.qls');
|
||||
await runResolveQueries(codeQL, resultMap, suites, undefined, false);
|
||||
await runResolveQueries(codeQL, resultMap, suites, undefined);
|
||||
}
|
||||
/**
|
||||
* Retrieve the set of queries at localQueryPath and add them to resultMap.
|
||||
|
|
@ -112,7 +126,7 @@ async function addLocalQueries(codeQL, resultMap, localQueryPath, checkoutPath,
|
|||
if (!(absoluteQueryPath + path.sep).startsWith(fs.realpathSync(checkoutPath) + path.sep)) {
|
||||
throw new Error(getLocalPathOutsideOfRepository(configFile, localQueryPath));
|
||||
}
|
||||
await runResolveQueries(codeQL, resultMap, [absoluteQueryPath], checkoutPath, true);
|
||||
await runResolveQueries(codeQL, resultMap, [absoluteQueryPath], checkoutPath);
|
||||
}
|
||||
/**
|
||||
* Retrieve the set of queries at the referenced remote repo and add them to resultMap.
|
||||
|
|
@ -140,7 +154,7 @@ async function addRemoteQueries(codeQL, resultMap, queryUses, tempDir, githubUrl
|
|||
const queryPath = tok.length > 2
|
||||
? path.join(checkoutPath, tok.slice(2).join('/'))
|
||||
: checkoutPath;
|
||||
await runResolveQueries(codeQL, resultMap, [queryPath], checkoutPath, true);
|
||||
await runResolveQueries(codeQL, resultMap, [queryPath], checkoutPath);
|
||||
}
|
||||
/**
|
||||
* Parse a query 'uses' field to a discrete set of query files and update resultMap.
|
||||
|
|
@ -476,7 +490,8 @@ async function loadConfig(languagesInput, queriesInput, configFile, repository,
|
|||
// The list of queries should not be empty for any language. If it is then
|
||||
// it is a user configuration error.
|
||||
for (const language of languages) {
|
||||
if (queries[language] === undefined || queries[language].length === 0) {
|
||||
if (queries[language] === undefined ||
|
||||
(queries[language].builtin.length === 0 && queries[language].custom.length === 0)) {
|
||||
throw new Error(`Did not detect any queries to run for ${language}. ` +
|
||||
"Please make sure that the default queries are enabled, or you are specifying queries to run.");
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
44
lib/config-utils.test.js
generated
44
lib/config-utils.test.js
generated
|
|
@ -161,7 +161,10 @@ ava_1.default("load non-empty input", async (t) => {
|
|||
// And the config we expect it to parse to
|
||||
const expectedConfig = {
|
||||
languages: [languages_1.Language.javascript],
|
||||
queries: { 'javascript': ['/foo/a.ql', '/bar/b.ql'] },
|
||||
queries: { 'javascript': {
|
||||
builtin: [],
|
||||
custom: ['/foo/a.ql', '/bar/b.ql']
|
||||
} },
|
||||
pathsIgnore: ['a', 'b'],
|
||||
paths: ['c/d'],
|
||||
originalUserInput: {
|
||||
|
|
@ -260,9 +263,10 @@ ava_1.default("Queries can be specified in config file", async (t) => {
|
|||
t.deepEqual(resolveQueriesArgs[1].queries.length, 1);
|
||||
t.regex(resolveQueriesArgs[1].queries[0], /.*\/foo$/);
|
||||
// Now check that the end result contains the default queries and the query from config
|
||||
t.deepEqual(config.queries['javascript'].length, 2);
|
||||
t.regex(config.queries['javascript'][0], /javascript-code-scanning.qls$/);
|
||||
t.regex(config.queries['javascript'][1], /.*\/foo$/);
|
||||
t.deepEqual(config.queries['javascript'].builtin.length, 1);
|
||||
t.deepEqual(config.queries['javascript'].custom.length, 1);
|
||||
t.regex(config.queries['javascript'].builtin[0], /javascript-code-scanning.qls$/);
|
||||
t.regex(config.queries['javascript'].custom[0], /.*\/foo$/);
|
||||
});
|
||||
});
|
||||
ava_1.default("Queries from config file can be overridden in workflow file", async (t) => {
|
||||
|
|
@ -292,9 +296,10 @@ ava_1.default("Queries from config file can be overridden in workflow file", asy
|
|||
t.deepEqual(resolveQueriesArgs[1].queries.length, 1);
|
||||
t.regex(resolveQueriesArgs[1].queries[0], /.*\/override$/);
|
||||
// Now check that the end result contains only the default queries and the override query
|
||||
t.deepEqual(config.queries['javascript'].length, 2);
|
||||
t.regex(config.queries['javascript'][0], /javascript-code-scanning.qls$/);
|
||||
t.regex(config.queries['javascript'][1], /.*\/override$/);
|
||||
t.deepEqual(config.queries['javascript'].builtin.length, 1);
|
||||
t.deepEqual(config.queries['javascript'].custom.length, 1);
|
||||
t.regex(config.queries['javascript'].builtin[0], /javascript-code-scanning.qls$/);
|
||||
t.regex(config.queries['javascript'].custom[0], /.*\/override$/);
|
||||
});
|
||||
});
|
||||
ava_1.default("Queries in workflow file can be used in tandem with the 'disable default queries' option", async (t) => {
|
||||
|
|
@ -323,8 +328,9 @@ ava_1.default("Queries in workflow file can be used in tandem with the 'disable
|
|||
t.deepEqual(resolveQueriesArgs[0].queries.length, 1);
|
||||
t.regex(resolveQueriesArgs[0].queries[0], /.*\/workflow-query$/);
|
||||
// Now check that the end result contains only the workflow query, and not the default one
|
||||
t.deepEqual(config.queries['javascript'].length, 1);
|
||||
t.regex(config.queries['javascript'][0], /.*\/workflow-query$/);
|
||||
t.deepEqual(config.queries['javascript'].builtin.length, 0);
|
||||
t.deepEqual(config.queries['javascript'].custom.length, 1);
|
||||
t.regex(config.queries['javascript'].custom[0], /.*\/workflow-query$/);
|
||||
});
|
||||
});
|
||||
ava_1.default("Multiple queries can be specified in workflow file, no config file required", async (t) => {
|
||||
|
|
@ -350,10 +356,11 @@ ava_1.default("Multiple queries can be specified in workflow file, no config fil
|
|||
t.regex(resolveQueriesArgs[1].queries[0], /.*\/override1$/);
|
||||
t.regex(resolveQueriesArgs[2].queries[0], /.*\/override2$/);
|
||||
// Now check that the end result contains both the queries from the workflow, as well as the defaults
|
||||
t.deepEqual(config.queries['javascript'].length, 3);
|
||||
t.regex(config.queries['javascript'][0], /javascript-code-scanning.qls$/);
|
||||
t.regex(config.queries['javascript'][1], /.*\/override1$/);
|
||||
t.regex(config.queries['javascript'][2], /.*\/override2$/);
|
||||
t.deepEqual(config.queries['javascript'].builtin.length, 1);
|
||||
t.deepEqual(config.queries['javascript'].custom.length, 2);
|
||||
t.regex(config.queries['javascript'].builtin[0], /javascript-code-scanning.qls$/);
|
||||
t.regex(config.queries['javascript'].custom[0], /.*\/override1$/);
|
||||
t.regex(config.queries['javascript'].custom[1], /.*\/override2$/);
|
||||
});
|
||||
});
|
||||
ava_1.default("Queries in workflow file can be added to the set of queries without overriding config file", async (t) => {
|
||||
|
|
@ -391,11 +398,12 @@ ava_1.default("Queries in workflow file can be added to the set of queries witho
|
|||
t.deepEqual(resolveQueriesArgs[3].queries.length, 1);
|
||||
t.regex(resolveQueriesArgs[3].queries[0], /.*\/foo$/);
|
||||
// Now check that the end result contains all the queries
|
||||
t.deepEqual(config.queries['javascript'].length, 4);
|
||||
t.regex(config.queries['javascript'][0], /javascript-code-scanning.qls$/);
|
||||
t.regex(config.queries['javascript'][1], /.*\/additional1$/);
|
||||
t.regex(config.queries['javascript'][2], /.*\/additional2$/);
|
||||
t.regex(config.queries['javascript'][3], /.*\/foo$/);
|
||||
t.deepEqual(config.queries['javascript'].builtin.length, 1);
|
||||
t.deepEqual(config.queries['javascript'].custom.length, 3);
|
||||
t.regex(config.queries['javascript'].builtin[0], /javascript-code-scanning.qls$/);
|
||||
t.regex(config.queries['javascript'].custom[0], /.*\/additional1$/);
|
||||
t.regex(config.queries['javascript'].custom[1], /.*\/additional2$/);
|
||||
t.regex(config.queries['javascript'].custom[2], /.*\/foo$/);
|
||||
});
|
||||
});
|
||||
ava_1.default("Invalid queries in workflow file handled correctly", async (t) => {
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
65
src/analyze.test.ts
Normal file
65
src/analyze.test.ts
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import test from 'ava';
|
||||
import * as fs from 'fs';
|
||||
|
||||
import { runQueries } from './analyze';
|
||||
import { setCodeQL } from './codeql';
|
||||
import { Config } from './config-utils';
|
||||
import { Language } from './languages';
|
||||
import { getRunnerLogger } from './logging';
|
||||
import { setupTests } from './testing-utils';
|
||||
import * as util from './util';
|
||||
|
||||
setupTests(test);
|
||||
|
||||
// Checks that the duration fields are populated for the correct language
|
||||
// and correct case of builtin or custom.
|
||||
test('status report fields', async t => {
|
||||
return await util.withTmpDir(async tmpDir => {
|
||||
setCodeQL({
|
||||
databaseAnalyze: async () => undefined
|
||||
});
|
||||
|
||||
const memoryFlag = '';
|
||||
const threadsFlag = '';
|
||||
|
||||
for (const language of Object.values(Language)) {
|
||||
const config: Config = {
|
||||
languages: [language],
|
||||
queries: {},
|
||||
pathsIgnore: [],
|
||||
paths: [],
|
||||
originalUserInput: {},
|
||||
tempDir: tmpDir,
|
||||
toolCacheDir: tmpDir,
|
||||
codeQLCmd: '',
|
||||
};
|
||||
fs.mkdirSync(util.getCodeQLDatabasePath(config.tempDir, language), { recursive: true });
|
||||
|
||||
config.queries[language] = {
|
||||
builtin: ['foo.ql'],
|
||||
custom: [],
|
||||
};
|
||||
const builtinStatusReport = await runQueries(
|
||||
tmpDir,
|
||||
memoryFlag,
|
||||
threadsFlag,
|
||||
config,
|
||||
getRunnerLogger(true));
|
||||
t.deepEqual(Object.keys(builtinStatusReport).length, 1);
|
||||
t.true(`analyze_builtin_queries_${language}_duration_ms` in builtinStatusReport);
|
||||
|
||||
config.queries[language] = {
|
||||
builtin: [],
|
||||
custom: ['foo.ql'],
|
||||
};
|
||||
const customStatusReport = await runQueries(
|
||||
tmpDir,
|
||||
memoryFlag,
|
||||
threadsFlag,
|
||||
config,
|
||||
getRunnerLogger(true));
|
||||
t.deepEqual(Object.keys(customStatusReport).length, 1);
|
||||
t.true(`analyze_custom_queries_${language}_duration_ms` in customStatusReport);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -75,47 +75,58 @@ async function finalizeDatabaseCreation(
|
|||
}
|
||||
|
||||
// Runs queries and creates sarif files in the given folder
|
||||
async function runQueries(
|
||||
export async function runQueries(
|
||||
sarifFolder: string,
|
||||
memoryFlag: string,
|
||||
threadsFlag: string,
|
||||
config: configUtils.Config,
|
||||
logger: Logger): Promise<QueriesStatusReport> {
|
||||
|
||||
const codeql = getCodeQL(config.codeQLCmd);
|
||||
const statusReport: QueriesStatusReport = {};
|
||||
|
||||
for (let language of config.languages) {
|
||||
logger.startGroup('Analyzing ' + language);
|
||||
|
||||
const queries = config.queries[language] || [];
|
||||
if (queries.length === 0) {
|
||||
const queries = config.queries[language];
|
||||
if (queries.builtin.length === 0 && queries.custom.length === 0) {
|
||||
throw new Error('Unable to analyse ' + language + ' as no queries were selected for this language');
|
||||
}
|
||||
|
||||
try {
|
||||
const databasePath = util.getCodeQLDatabasePath(config.tempDir, 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 querySuite = databasePath + '-queries.qls';
|
||||
const querySuiteContents = queries.map(q => '- query: ' + q).join('\n');
|
||||
fs.writeFileSync(querySuite, querySuiteContents);
|
||||
logger.debug('Query suite file for ' + language + '...\n' + querySuiteContents);
|
||||
for (const type of ['builtin', 'custom']) {
|
||||
if (queries[type].length > 0) {
|
||||
const startTime = new Date().getTime();
|
||||
|
||||
const sarifFile = path.join(sarifFolder, language + '.sarif');
|
||||
const databasePath = util.getCodeQLDatabasePath(config.tempDir, 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`;
|
||||
const querySuiteContents = queries[type].map((q: string) => '- query: ' + q).join('\n');
|
||||
fs.writeFileSync(querySuitePath, querySuiteContents);
|
||||
logger.debug('Query suite file for ' + language + '...\n' + querySuiteContents);
|
||||
|
||||
await codeql.databaseAnalyze(databasePath, sarifFile, querySuite, memoryFlag, threadsFlag);
|
||||
const sarifFile = path.join(sarifFolder, `${language}-${type}.sarif`);
|
||||
|
||||
logger.debug('SARIF results for database ' + language + ' created at "' + sarifFile + '"');
|
||||
logger.endGroup();
|
||||
const codeql = getCodeQL(config.codeQLCmd);
|
||||
await codeql.databaseAnalyze(databasePath, sarifFile, querySuitePath, memoryFlag, threadsFlag);
|
||||
|
||||
logger.debug('SARIF results for database ' + language + ' created at "' + sarifFile + '"');
|
||||
logger.endGroup();
|
||||
|
||||
// Record the performance
|
||||
const endTime = new Date().getTime();
|
||||
statusReport[`analyze_${type}_queries_${language}_duration_ms`] = endTime - startTime;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// For now the fields about query performance are not populated
|
||||
return {
|
||||
analyze_failure_language: language,
|
||||
};
|
||||
logger.error(`Error running analysis for ${language}: ${e}`);
|
||||
logger.info(e);
|
||||
statusReport.analyze_failure_language = language;
|
||||
return statusReport;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
return statusReport;
|
||||
}
|
||||
|
||||
export async function runAnalyze(
|
||||
|
|
|
|||
|
|
@ -239,7 +239,10 @@ test("load non-empty input", async t => {
|
|||
// And the config we expect it to parse to
|
||||
const expectedConfig: configUtils.Config = {
|
||||
languages: [Language.javascript],
|
||||
queries: {'javascript': ['/foo/a.ql', '/bar/b.ql']},
|
||||
queries: {'javascript': {
|
||||
builtin: [],
|
||||
custom: ['/foo/a.ql', '/bar/b.ql']
|
||||
}},
|
||||
pathsIgnore: ['a', 'b'],
|
||||
paths: ['c/d'],
|
||||
originalUserInput: {
|
||||
|
|
@ -390,9 +393,10 @@ test("Queries can be specified in config file", async t => {
|
|||
t.regex(resolveQueriesArgs[1].queries[0], /.*\/foo$/);
|
||||
|
||||
// Now check that the end result contains the default queries and the query from config
|
||||
t.deepEqual(config.queries['javascript'].length, 2);
|
||||
t.regex(config.queries['javascript'][0], /javascript-code-scanning.qls$/);
|
||||
t.regex(config.queries['javascript'][1], /.*\/foo$/);
|
||||
t.deepEqual(config.queries['javascript'].builtin.length, 1);
|
||||
t.deepEqual(config.queries['javascript'].custom.length, 1);
|
||||
t.regex(config.queries['javascript'].builtin[0], /javascript-code-scanning.qls$/);
|
||||
t.regex(config.queries['javascript'].custom[0], /.*\/foo$/);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -442,9 +446,10 @@ test("Queries from config file can be overridden in workflow file", async t => {
|
|||
t.regex(resolveQueriesArgs[1].queries[0], /.*\/override$/);
|
||||
|
||||
// Now check that the end result contains only the default queries and the override query
|
||||
t.deepEqual(config.queries['javascript'].length, 2);
|
||||
t.regex(config.queries['javascript'][0], /javascript-code-scanning.qls$/);
|
||||
t.regex(config.queries['javascript'][1], /.*\/override$/);
|
||||
t.deepEqual(config.queries['javascript'].builtin.length, 1);
|
||||
t.deepEqual(config.queries['javascript'].custom.length, 1);
|
||||
t.regex(config.queries['javascript'].builtin[0], /javascript-code-scanning.qls$/);
|
||||
t.regex(config.queries['javascript'].custom[0], /.*\/override$/);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -492,8 +497,9 @@ test("Queries in workflow file can be used in tandem with the 'disable default q
|
|||
t.regex(resolveQueriesArgs[0].queries[0], /.*\/workflow-query$/);
|
||||
|
||||
// Now check that the end result contains only the workflow query, and not the default one
|
||||
t.deepEqual(config.queries['javascript'].length, 1);
|
||||
t.regex(config.queries['javascript'][0], /.*\/workflow-query$/);
|
||||
t.deepEqual(config.queries['javascript'].builtin.length, 0);
|
||||
t.deepEqual(config.queries['javascript'].custom.length, 1);
|
||||
t.regex(config.queries['javascript'].custom[0], /.*\/workflow-query$/);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -537,10 +543,11 @@ test("Multiple queries can be specified in workflow file, no config file require
|
|||
t.regex(resolveQueriesArgs[2].queries[0], /.*\/override2$/);
|
||||
|
||||
// Now check that the end result contains both the queries from the workflow, as well as the defaults
|
||||
t.deepEqual(config.queries['javascript'].length, 3);
|
||||
t.regex(config.queries['javascript'][0], /javascript-code-scanning.qls$/);
|
||||
t.regex(config.queries['javascript'][1], /.*\/override1$/);
|
||||
t.regex(config.queries['javascript'][2], /.*\/override2$/);
|
||||
t.deepEqual(config.queries['javascript'].builtin.length, 1);
|
||||
t.deepEqual(config.queries['javascript'].custom.length, 2);
|
||||
t.regex(config.queries['javascript'].builtin[0], /javascript-code-scanning.qls$/);
|
||||
t.regex(config.queries['javascript'].custom[0], /.*\/override1$/);
|
||||
t.regex(config.queries['javascript'].custom[1], /.*\/override2$/);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -598,11 +605,12 @@ test("Queries in workflow file can be added to the set of queries without overri
|
|||
t.regex(resolveQueriesArgs[3].queries[0], /.*\/foo$/);
|
||||
|
||||
// Now check that the end result contains all the queries
|
||||
t.deepEqual(config.queries['javascript'].length, 4);
|
||||
t.regex(config.queries['javascript'][0], /javascript-code-scanning.qls$/);
|
||||
t.regex(config.queries['javascript'][1], /.*\/additional1$/);
|
||||
t.regex(config.queries['javascript'][2], /.*\/additional2$/);
|
||||
t.regex(config.queries['javascript'][3], /.*\/foo$/);
|
||||
t.deepEqual(config.queries['javascript'].builtin.length, 1);
|
||||
t.deepEqual(config.queries['javascript'].custom.length, 3);
|
||||
t.regex(config.queries['javascript'].builtin[0], /javascript-code-scanning.qls$/);
|
||||
t.regex(config.queries['javascript'].custom[0], /.*\/additional1$/);
|
||||
t.regex(config.queries['javascript'].custom[1], /.*\/additional2$/);
|
||||
t.regex(config.queries['javascript'].custom[2], /.*\/foo$/);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,22 @@ export interface UserConfig {
|
|||
paths?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists of query files for each language.
|
||||
* Will only contain .ql files and not other kinds of files,
|
||||
* and all file paths will be absolute.
|
||||
*
|
||||
* The queries are split between ones from a builtin suite
|
||||
* and custom queries from unknown locations. This allows us to treat
|
||||
* them separately if we want to, for example to measure performance.
|
||||
*/
|
||||
type Queries = { [language: string]: {
|
||||
/** Queries from one of the builtin suites */
|
||||
builtin: string[];
|
||||
/** Custom queries, from a non-standard location */
|
||||
custom: string[];
|
||||
}};
|
||||
|
||||
/**
|
||||
* Format of the parsed config file.
|
||||
*/
|
||||
|
|
@ -41,10 +57,8 @@ export interface Config {
|
|||
languages: Language[];
|
||||
/**
|
||||
* Map from language to query files.
|
||||
* Will only contain .ql files and not other kinds of files,
|
||||
* and all file paths will be absolute.
|
||||
*/
|
||||
queries: { [language: string]: string[] };
|
||||
queries: Queries;
|
||||
/**
|
||||
* List of paths to ignore from analysis.
|
||||
*/
|
||||
|
|
@ -122,34 +136,46 @@ function validateQueries(resolvedQueries: ResolveQueriesOutput) {
|
|||
|
||||
/**
|
||||
* Run 'codeql resolve queries' and add the results to resultMap
|
||||
*
|
||||
* If a checkout path is given then the queries are assumed to be custom queries
|
||||
* and an error will be thrown if there is anything invalid about the queries.
|
||||
* If a checkout path is not given then the queries are assumed to be builtin
|
||||
* queries, and error checking will be suppressed.
|
||||
*/
|
||||
async function runResolveQueries(
|
||||
codeQL: CodeQL,
|
||||
resultMap: { [language: string]: string[] },
|
||||
resultMap: Queries,
|
||||
toResolve: string[],
|
||||
extraSearchPath: string | undefined,
|
||||
errorOnInvalidQueries: boolean) {
|
||||
extraSearchPath: string | undefined) {
|
||||
|
||||
const resolvedQueries = await codeQL.resolveQueries(toResolve, extraSearchPath);
|
||||
|
||||
for (const [language, queries] of Object.entries(resolvedQueries.byLanguage)) {
|
||||
if (resultMap[language] === undefined) {
|
||||
resultMap[language] = [];
|
||||
}
|
||||
resultMap[language].push(...Object.keys(queries).filter(q => !queryIsDisabled(language, q)));
|
||||
if (extraSearchPath !== undefined) {
|
||||
validateQueries(resolvedQueries);
|
||||
}
|
||||
|
||||
if (errorOnInvalidQueries) {
|
||||
validateQueries(resolvedQueries);
|
||||
for (const [language, queryPaths] of Object.entries(resolvedQueries.byLanguage)) {
|
||||
if (resultMap[language] === undefined) {
|
||||
resultMap[language] = {
|
||||
builtin: [],
|
||||
custom: [],
|
||||
};
|
||||
}
|
||||
const queries = Object.keys(queryPaths).filter(q => !queryIsDisabled(language, q));
|
||||
if (extraSearchPath !== undefined) {
|
||||
resultMap[language].custom.push(...queries);
|
||||
} else {
|
||||
resultMap[language].builtin.push(...queries);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the set of queries included by default.
|
||||
*/
|
||||
async function addDefaultQueries(codeQL: CodeQL, languages: string[], resultMap: { [language: string]: string[] }) {
|
||||
async function addDefaultQueries(codeQL: CodeQL, languages: string[], resultMap: Queries) {
|
||||
const suites = languages.map(l => l + '-code-scanning.qls');
|
||||
await runResolveQueries(codeQL, resultMap, suites, undefined, false);
|
||||
await runResolveQueries(codeQL, resultMap, suites, undefined);
|
||||
}
|
||||
|
||||
// The set of acceptable values for built-in suites from the codeql bundle
|
||||
|
|
@ -162,7 +188,7 @@ const builtinSuites = ['security-extended', 'security-and-quality'] as const;
|
|||
async function addBuiltinSuiteQueries(
|
||||
languages: string[],
|
||||
codeQL: CodeQL,
|
||||
resultMap: { [language: string]: string[] },
|
||||
resultMap: Queries,
|
||||
suiteName: string,
|
||||
configFile?: string) {
|
||||
|
||||
|
|
@ -172,7 +198,7 @@ async function addBuiltinSuiteQueries(
|
|||
}
|
||||
|
||||
const suites = languages.map(l => l + '-' + suiteName + '.qls');
|
||||
await runResolveQueries(codeQL, resultMap, suites, undefined, false);
|
||||
await runResolveQueries(codeQL, resultMap, suites, undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -180,7 +206,7 @@ async function addBuiltinSuiteQueries(
|
|||
*/
|
||||
async function addLocalQueries(
|
||||
codeQL: CodeQL,
|
||||
resultMap: { [language: string]: string[] },
|
||||
resultMap: Queries,
|
||||
localQueryPath: string,
|
||||
checkoutPath: string,
|
||||
configFile?: string) {
|
||||
|
|
@ -202,7 +228,7 @@ async function addLocalQueries(
|
|||
throw new Error(getLocalPathOutsideOfRepository(configFile, localQueryPath));
|
||||
}
|
||||
|
||||
await runResolveQueries(codeQL, resultMap, [absoluteQueryPath], checkoutPath, true);
|
||||
await runResolveQueries(codeQL, resultMap, [absoluteQueryPath], checkoutPath);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -210,7 +236,7 @@ async function addLocalQueries(
|
|||
*/
|
||||
async function addRemoteQueries(
|
||||
codeQL: CodeQL,
|
||||
resultMap: { [language: string]: string[] },
|
||||
resultMap: Queries,
|
||||
queryUses: string,
|
||||
tempDir: string,
|
||||
githubUrl: string,
|
||||
|
|
@ -249,7 +275,7 @@ async function addRemoteQueries(
|
|||
? path.join(checkoutPath, tok.slice(2).join('/'))
|
||||
: checkoutPath;
|
||||
|
||||
await runResolveQueries(codeQL, resultMap, [queryPath], checkoutPath, true);
|
||||
await runResolveQueries(codeQL, resultMap, [queryPath], checkoutPath);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -263,7 +289,7 @@ async function addRemoteQueries(
|
|||
async function parseQueryUses(
|
||||
languages: string[],
|
||||
codeQL: CodeQL,
|
||||
resultMap: { [language: string]: string[] },
|
||||
resultMap: Queries,
|
||||
queryUses: string,
|
||||
tempDir: string,
|
||||
checkoutPath: string,
|
||||
|
|
@ -543,7 +569,7 @@ async function addQueriesFromWorkflow(
|
|||
codeQL: CodeQL,
|
||||
queriesInput: string,
|
||||
languages: string[],
|
||||
resultMap: { [language: string]: string[] },
|
||||
resultMap: Queries,
|
||||
tempDir: string,
|
||||
checkoutPath: string,
|
||||
githubUrl: string,
|
||||
|
|
@ -599,7 +625,7 @@ export async function getDefaultConfig(
|
|||
githubAuth,
|
||||
githubUrl,
|
||||
logger);
|
||||
const queries = {};
|
||||
const queries: Queries = {};
|
||||
await addDefaultQueries(codeQL, languages, queries);
|
||||
if (queriesInput) {
|
||||
await addQueriesFromWorkflow(
|
||||
|
|
@ -672,7 +698,7 @@ async function loadConfig(
|
|||
githubUrl,
|
||||
logger);
|
||||
|
||||
const queries = {};
|
||||
const queries: Queries = {};
|
||||
const pathsIgnore: string[] = [];
|
||||
const paths: string[] = [];
|
||||
|
||||
|
|
@ -750,7 +776,8 @@ async function loadConfig(
|
|||
// The list of queries should not be empty for any language. If it is then
|
||||
// it is a user configuration error.
|
||||
for (const language of languages) {
|
||||
if (queries[language] === undefined || queries[language].length === 0) {
|
||||
if (queries[language] === undefined ||
|
||||
(queries[language].builtin.length === 0 && queries[language].custom.length === 0)) {
|
||||
throw new Error(`Did not detect any queries to run for ${language}. ` +
|
||||
"Please make sure that the default queries are enabled, or you are specifying queries to run.");
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue