Add packs and queries from input

This commit adds the packs and queries from the actions input to the
config file used by the CodeQL CLI.

When the `+` is used, the actions input value is combined with the
config value and when it is not used, the input value overrides the
config value.

This commit also adds a bunch of integration tests for this feature.
In order to avoid adding too many new jobs, all of the tests are
run sequentially in a single job (matrixed across relevant operating
systems and OSes).
This commit is contained in:
Andrew Eisenberg
2022-06-19 16:44:24 -07:00
parent 237260b693
commit 6fabde2be8
53 changed files with 2072 additions and 219 deletions

View File

@@ -763,26 +763,12 @@ async function getCodeQLForCmd(
}
}
}
if (await util.codeQlVersionAbove(codeql, CODEQL_VERSION_CONFIG_FILES)) {
const configLocation = path.resolve(config.tempDir, "user-config.yaml");
const augmentedConfig = config.originalUserInput;
if (config.injectedMlQueries) {
// We need to inject the ML queries into the original user input before
// we pass this on to the CLI, to make sure these get run.
const packString = await util.getMlPoweredJsQueriesPack(codeql);
if (augmentedConfig.packs === undefined) augmentedConfig.packs = [];
if (Array.isArray(augmentedConfig.packs)) {
augmentedConfig.packs.push(packString);
} else {
if (!augmentedConfig.packs.javascript)
augmentedConfig.packs["javascript"] = [];
augmentedConfig.packs["javascript"].push(packString);
}
}
fs.writeFileSync(configLocation, yaml.dump(augmentedConfig));
const configLocation = await generateCodescanningConfig(codeql, config);
if (configLocation) {
extraArgs.push(`--codescanning-config=${configLocation}`);
}
await runTool(cmd, [
"database",
"init",
@@ -955,7 +941,7 @@ async function getCodeQLForCmd(
if (extraSearchPath !== undefined) {
codeqlArgs.push("--additional-packs", extraSearchPath);
}
if (!(await util.codeQlVersionAbove(this, CODEQL_VERSION_CONFIG_FILES))) {
if (!(await util.useCodeScanningConfigInCli(this))) {
codeqlArgs.push(querySuitePath);
}
await runTool(cmd, codeqlArgs);
@@ -993,7 +979,7 @@ async function getCodeQLForCmd(
codeqlArgs.push("--sarif-category", automationDetailsId);
}
codeqlArgs.push(databasePath);
if (!(await util.codeQlVersionAbove(this, CODEQL_VERSION_CONFIG_FILES))) {
if (!(await util.useCodeScanningConfigInCli(this))) {
codeqlArgs.push(...querySuitePaths);
}
// capture stdout, which contains analysis summaries
@@ -1187,3 +1173,77 @@ async function runTool(cmd: string, args: string[] = []) {
throw new CommandInvocationError(cmd, args, exitCode, error);
return output;
}
/**
* If appropriate, generates a code scanning configuration that is to be used for a scan.
* If the configuration is not to be generated, returns undefined.
*
* @param codeql The CodeQL object to use.
* @param config The configuration to use.
* @returns the path to the generated user configuration file.
*/
async function generateCodescanningConfig(codeql: CodeQL, config: Config) {
if (!(await util.useCodeScanningConfigInCli(codeql))) {
return;
}
const configLocation = path.resolve(config.tempDir, "user-config.yaml");
// make a copy so we can modify it
const augmentedConfig = JSON.parse(JSON.stringify(config.originalUserInput));
// Inject the queries from the input
if (config.augmentationProperties.queriesInput) {
if (config.augmentationProperties.queriesInputCombines) {
augmentedConfig.queries = (augmentedConfig.queries || []).concat(
config.augmentationProperties.queriesInput
);
} else {
augmentedConfig.queries = config.augmentationProperties.queriesInput;
}
}
if (augmentedConfig.queries?.length === 0) {
delete augmentedConfig.queries;
}
// Inject the packs from the input
if (config.augmentationProperties.packsInput) {
if (config.augmentationProperties.packsInputCombines) {
// At this point, we already know that this is a single-language analysis
if (Array.isArray(augmentedConfig.packs)) {
augmentedConfig.packs = (augmentedConfig.packs || []).concat(
config.augmentationProperties.packsInput
);
} else if (!augmentedConfig.packs) {
augmentedConfig.packs = config.augmentationProperties.packsInput;
} else {
// At this point, we know there is only one language.
// If there were more than one language, an error would already have been thrown.
const language = Object.keys(augmentedConfig.packs)[0];
augmentedConfig.packs[language] = augmentedConfig.packs[
language
].concat(config.augmentationProperties.packsInput);
}
} else {
augmentedConfig.packs = config.augmentationProperties.packsInput;
}
}
if (Array.isArray(augmentedConfig.packs) && !augmentedConfig.packs.length) {
delete augmentedConfig.packs;
}
if (config.augmentationProperties.injectedMlQueries) {
// We need to inject the ML queries into the original user input before
// we pass this on to the CLI, to make sure these get run.
const packString = await util.getMlPoweredJsQueriesPack(codeql);
if (augmentedConfig.packs === undefined) augmentedConfig.packs = [];
if (Array.isArray(augmentedConfig.packs)) {
augmentedConfig.packs.push(packString);
} else {
if (!augmentedConfig.packs.javascript)
augmentedConfig.packs["javascript"] = [];
augmentedConfig.packs["javascript"].push(packString);
}
}
fs.writeFileSync(configLocation, yaml.dump(augmentedConfig));
return configLocation;
}