Compare commits

...

1 Commits

Author SHA1 Message Date
Andrew Eisenberg
f3f429af7c WIP 2021-08-09 11:37:06 -07:00
12 changed files with 145 additions and 32 deletions

7
lib/analyze.js generated
View File

@@ -119,9 +119,9 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
logger.info("*************"); logger.info("*************");
logger.startGroup(`Downloading custom packs for ${language}`); logger.startGroup(`Downloading custom packs for ${language}`);
const codeql = codeql_1.getCodeQL(config.codeQLCmd); const codeql = codeql_1.getCodeQL(config.codeQLCmd);
const results = await codeql.packDownload(packsWithVersion); const results = await codeql.packDownload(packsWithVersion.map(packWithVersionToString));
logger.info(`Downloaded packs: ${results.packs logger.info(`Downloaded packs: ${results.packs
.map((r) => `${r.name}@${r.version || "latest"}`) .map((r) => `${r.name}@${r.version}`)
.join(", ")}`); .join(", ")}`);
logger.endGroup(); logger.endGroup();
} }
@@ -245,4 +245,7 @@ function printLinesOfCodeSummary(logger, language, lineCounts) {
logger.info(`Counted a baseline of ${lineCounts[language]} lines of code for ${language}.`); logger.info(`Counted a baseline of ${lineCounts[language]} lines of code for ${language}.`);
} }
} }
function packWithVersionToString(pack) {
return pack.version ? `${pack.packName}@${pack.version}` : pack.packName;
}
//# sourceMappingURL=analyze.js.map //# sourceMappingURL=analyze.js.map

File diff suppressed because one or more lines are too long

44
lib/codeql.js generated
View File

@@ -273,6 +273,7 @@ function resolveFunction(partialCodeql, methodName, defaultImplementation) {
*/ */
function setCodeQL(partialCodeql) { function setCodeQL(partialCodeql) {
cachedCodeQL = { cachedCodeQL = {
getVersion: resolveFunction(partialCodeql, "getVersion", () => Promise.resolve("0.0.0")),
getPath: resolveFunction(partialCodeql, "getPath", () => "/tmp/dummy-path"), getPath: resolveFunction(partialCodeql, "getPath", () => "/tmp/dummy-path"),
printVersion: resolveFunction(partialCodeql, "printVersion"), printVersion: resolveFunction(partialCodeql, "printVersion"),
getTracerEnv: resolveFunction(partialCodeql, "getTracerEnv"), getTracerEnv: resolveFunction(partialCodeql, "getTracerEnv"),
@@ -306,12 +307,28 @@ function getCachedCodeQL() {
} }
exports.getCachedCodeQL = getCachedCodeQL; exports.getCachedCodeQL = getCachedCodeQL;
function getCodeQLForCmd(cmd) { function getCodeQLForCmd(cmd) {
let version;
return { return {
async getVersion() {
if (!version) {
await this.printVersion();
}
return version;
},
getPath() { getPath() {
return cmd; return cmd;
}, },
async printVersion() { async printVersion() {
await runTool(cmd, ["version", "--format=json"]); const output = await runTool(cmd, ["version", "--format=json"]);
try {
version = JSON.parse(output).version;
if (!version) {
throw new Error("Missing version");
}
}
catch (e) {
throw new Error(`Unexpected output from codeql version: ${e}`);
}
}, },
async getTracerEnv(databasePath) { async getTracerEnv(databasePath) {
// Write tracer-env.js to a temp location. // Write tracer-env.js to a temp location.
@@ -498,22 +515,22 @@ function getCodeQLForCmd(cmd) {
* downloaded. The check to determine what the latest version is is done * downloaded. The check to determine what the latest version is is done
* each time this package is requested. * each time this package is requested.
*/ */
async packDownload(packs) { async packDownload(packsOrSuites, extraSearchPath) {
const codeqlArgs = [ const codeqlArgs = [
"pack", "pack",
"download", "download",
"--format=json", "--format=json",
...getExtraOptionsFromEnv(["pack", "download"]), ...getExtraOptionsFromEnv(["pack", "download"]),
...packs.map(packWithVersionToString), ...packsOrSuites,
]; ];
if (extraSearchPath) {
codeqlArgs.push("--additional-packs", extraSearchPath);
}
const output = await runTool(cmd, codeqlArgs); const output = await runTool(cmd, codeqlArgs);
try { try {
const parsedOutput = JSON.parse(output); const parsedOutput = JSON.parse(output);
if (Array.isArray(parsedOutput.packs) && if (Array.isArray(parsedOutput.packs) &&
// TODO PackDownloadOutput will not include the version if it is not specified parsedOutput.packs.every((p) => p.name && p.version)) {
// 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; return parsedOutput;
} }
else { else {
@@ -544,9 +561,6 @@ function getCodeQLForCmd(cmd) {
}, },
}; };
} }
function packWithVersionToString(pack) {
return pack.version ? `${pack.packName}@${pack.version}` : pack.packName;
}
/** /**
* Gets the options for `path` of `options` as an array of extra option strings. * Gets the options for `path` of `options` as an array of extra option strings.
*/ */
@@ -593,6 +607,16 @@ function getExtraOptions(options, paths, pathInfo) {
return all.concat(specific); return all.concat(specific);
} }
exports.getExtraOptions = getExtraOptions; exports.getExtraOptions = getExtraOptions;
// TODO verify that this is the correct version.
const CODEQL_MIN_VERSION_DOWNLOAD_PACKS_FROM_SUITES = ">=2.6.0";
/**
* Determines if this codeql supports introspecting query suites to look for packages
* to download.
*/
async function supportsDownloadPacksFromSuites(codeQL) {
return semver.satisfies(await codeQL.getVersion(), CODEQL_MIN_VERSION_DOWNLOAD_PACKS_FROM_SUITES);
}
exports.supportsDownloadPacksFromSuites = supportsDownloadPacksFromSuites;
/* /*
* A constant defining the maximum number of characters we will keep from * A constant defining the maximum number of characters we will keep from
* the programs stderr for logging. This serves two purposes: * the programs stderr for logging. This serves two purposes:

File diff suppressed because one or more lines are too long

12
lib/codeql.test.js generated
View File

@@ -205,4 +205,16 @@ ava_1.default("getCodeQLActionRepository", (t) => {
const repoEnv = codeql.getCodeQLActionRepository(logger); const repoEnv = codeql.getCodeQLActionRepository(logger);
t.deepEqual(repoEnv, "xxx/yyy"); t.deepEqual(repoEnv, "xxx/yyy");
}); });
ava_1.default("supportsDownloadPacksFromSuites", async (t) => {
const mockCodeQL = (mockVersion) => {
return {
async getVersion() {
return mockVersion;
},
};
};
t.true(await codeql.supportsDownloadPacksFromSuites(mockCodeQL("2.6.0")));
t.true(await codeql.supportsDownloadPacksFromSuites(mockCodeQL("2.6.1")));
t.false(await codeql.supportsDownloadPacksFromSuites(mockCodeQL("2.5.999")));
});
//# sourceMappingURL=codeql.test.js.map //# sourceMappingURL=codeql.test.js.map

File diff suppressed because one or more lines are too long

5
lib/config-utils.js generated
View File

@@ -12,6 +12,7 @@ const path = __importStar(require("path"));
const yaml = __importStar(require("js-yaml")); const yaml = __importStar(require("js-yaml"));
const semver = __importStar(require("semver")); const semver = __importStar(require("semver"));
const api = __importStar(require("./api-client")); const api = __importStar(require("./api-client"));
const codeql_1 = require("./codeql");
const externalQueries = __importStar(require("./external-queries")); const externalQueries = __importStar(require("./external-queries"));
const languages_1 = require("./languages"); const languages_1 = require("./languages");
// Property names from the user-supplied config file. // Property names from the user-supplied config file.
@@ -67,6 +68,10 @@ function validateQueries(resolvedQueries) {
* queries, and error checking will be suppressed. * queries, and error checking will be suppressed.
*/ */
async function runResolveQueries(codeQL, resultMap, toResolve, extraSearchPath) { async function runResolveQueries(codeQL, resultMap, toResolve, extraSearchPath) {
// before running resolve queries, must run download packs, if the CLI is new enough
if (await codeql_1.supportsDownloadPacksFromSuites(codeQL)) {
await codeQL.packDownload(toResolve, extraSearchPath);
}
const resolvedQueries = await codeQL.resolveQueries(toResolve, extraSearchPath); const resolvedQueries = await codeQL.resolveQueries(toResolve, extraSearchPath);
if (extraSearchPath !== undefined) { if (extraSearchPath !== undefined) {
validateQueries(resolvedQueries); validateQueries(resolvedQueries);

File diff suppressed because one or more lines are too long

View File

@@ -229,10 +229,12 @@ export async function runQueries(
logger.startGroup(`Downloading custom packs for ${language}`); logger.startGroup(`Downloading custom packs for ${language}`);
const codeql = getCodeQL(config.codeQLCmd); const codeql = getCodeQL(config.codeQLCmd);
const results = await codeql.packDownload(packsWithVersion); const results = await codeql.packDownload(
packsWithVersion.map(packWithVersionToString)
);
logger.info( logger.info(
`Downloaded packs: ${results.packs `Downloaded packs: ${results.packs
.map((r) => `${r.name}@${r.version || "latest"}`) .map((r) => `${r.name}@${r.version}`)
.join(", ")}` .join(", ")}`
); );
@@ -445,3 +447,7 @@ function printLinesOfCodeSummary(
); );
} }
} }
function packWithVersionToString(pack: configUtils.PackWithVersion): string {
return pack.version ? `${pack.packName}@${pack.version}` : pack.packName;
}

View File

@@ -390,3 +390,17 @@ test("getCodeQLActionRepository", (t) => {
const repoEnv = codeql.getCodeQLActionRepository(logger); const repoEnv = codeql.getCodeQLActionRepository(logger);
t.deepEqual(repoEnv, "xxx/yyy"); t.deepEqual(repoEnv, "xxx/yyy");
}); });
test("supportsDownloadPacksFromSuites", async (t) => {
const mockCodeQL = (mockVersion: string) => {
return {
async getVersion() {
return mockVersion;
},
} as codeql.CodeQL;
};
t.true(await codeql.supportsDownloadPacksFromSuites(mockCodeQL("2.6.0")));
t.true(await codeql.supportsDownloadPacksFromSuites(mockCodeQL("2.6.1")));
t.false(await codeql.supportsDownloadPacksFromSuites(mockCodeQL("2.5.999")));
});

View File

@@ -9,7 +9,6 @@ import * as semver from "semver";
import { isRunningLocalAction, getRelativeScriptPath } from "./actions-util"; import { isRunningLocalAction, getRelativeScriptPath } from "./actions-util";
import * as api from "./api-client"; import * as api from "./api-client";
import { PackWithVersion } from "./config-utils";
import * as defaults from "./defaults.json"; // Referenced from codeql-action-sync-tool! import * as defaults from "./defaults.json"; // Referenced from codeql-action-sync-tool!
import { errorMatchers } from "./error-matcher"; import { errorMatchers } from "./error-matcher";
import { Language } from "./languages"; import { Language } from "./languages";
@@ -50,6 +49,11 @@ export class CommandInvocationError extends Error {
} }
export interface CodeQL { export interface CodeQL {
/**
* Gets the version of the CodeQL CLI.
*/
getVersion(): Promise<string>;
/** /**
* Get the path of the CodeQL executable. * Get the path of the CodeQL executable.
*/ */
@@ -99,7 +103,10 @@ export interface CodeQL {
/** /**
* Run 'codeql pack download'. * Run 'codeql pack download'.
*/ */
packDownload(packs: PackWithVersion[]): Promise<PackDownloadOutput>; packDownload(
packsOrSuites: string[],
extraSearchPath?: string
): Promise<PackDownloadOutput>;
/** /**
* Run 'codeql database cleanup'. * Run 'codeql database cleanup'.
@@ -489,6 +496,9 @@ function resolveFunction<T>(
*/ */
export function setCodeQL(partialCodeql: Partial<CodeQL>): CodeQL { export function setCodeQL(partialCodeql: Partial<CodeQL>): CodeQL {
cachedCodeQL = { cachedCodeQL = {
getVersion: resolveFunction(partialCodeql, "getVersion", () =>
Promise.resolve("0.0.0")
),
getPath: resolveFunction(partialCodeql, "getPath", () => "/tmp/dummy-path"), getPath: resolveFunction(partialCodeql, "getPath", () => "/tmp/dummy-path"),
printVersion: resolveFunction(partialCodeql, "printVersion"), printVersion: resolveFunction(partialCodeql, "printVersion"),
getTracerEnv: resolveFunction(partialCodeql, "getTracerEnv"), getTracerEnv: resolveFunction(partialCodeql, "getTracerEnv"),
@@ -528,12 +538,27 @@ export function getCachedCodeQL(): CodeQL {
} }
function getCodeQLForCmd(cmd: string): CodeQL { function getCodeQLForCmd(cmd: string): CodeQL {
let version: string;
return { return {
async getVersion() {
if (!version) {
await this.printVersion();
}
return version;
},
getPath() { getPath() {
return cmd; return cmd;
}, },
async printVersion() { async printVersion() {
await runTool(cmd, ["version", "--format=json"]); const output = await runTool(cmd, ["version", "--format=json"]);
try {
version = JSON.parse(output).version;
if (!version) {
throw new Error("Missing version");
}
} catch (e) {
throw new Error(`Unexpected output from codeql version: ${e}`);
}
}, },
async getTracerEnv(databasePath: string) { async getTracerEnv(databasePath: string) {
// Write tracer-env.js to a temp location. // Write tracer-env.js to a temp location.
@@ -779,25 +804,29 @@ function getCodeQLForCmd(cmd: string): CodeQL {
* downloaded. The check to determine what the latest version is is done * downloaded. The check to determine what the latest version is is done
* each time this package is requested. * each time this package is requested.
*/ */
async packDownload(packs: PackWithVersion[]): Promise<PackDownloadOutput> { async packDownload(
packsOrSuites: string[],
extraSearchPath?: string
): Promise<PackDownloadOutput> {
const codeqlArgs = [ const codeqlArgs = [
"pack", "pack",
"download", "download",
"--format=json", "--format=json",
...getExtraOptionsFromEnv(["pack", "download"]), ...getExtraOptionsFromEnv(["pack", "download"]),
...packs.map(packWithVersionToString), ...packsOrSuites,
]; ];
if (extraSearchPath) {
codeqlArgs.push("--additional-packs", extraSearchPath);
}
const output = await runTool(cmd, codeqlArgs); const output = await runTool(cmd, codeqlArgs);
try { try {
const parsedOutput: PackDownloadOutput = JSON.parse(output); const parsedOutput: PackDownloadOutput = JSON.parse(output);
if ( if (
Array.isArray(parsedOutput.packs) && Array.isArray(parsedOutput.packs) &&
// TODO PackDownloadOutput will not include the version if it is not specified parsedOutput.packs.every((p) => p.name && p.version)
// 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; return parsedOutput;
} else { } else {
@@ -835,10 +864,6 @@ 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. * Gets the options for `path` of `options` as an array of extra option strings.
*/ */
@@ -899,6 +924,22 @@ export function getExtraOptions(
return all.concat(specific); return all.concat(specific);
} }
// TODO verify that this is the correct version.
const CODEQL_MIN_VERSION_DOWNLOAD_PACKS_FROM_SUITES = ">=2.6.0";
/**
* Determines if this codeql supports introspecting query suites to look for packages
* to download.
*/
export async function supportsDownloadPacksFromSuites(
codeQL: CodeQL
): Promise<boolean> {
return semver.satisfies(
await codeQL.getVersion(),
CODEQL_MIN_VERSION_DOWNLOAD_PACKS_FROM_SUITES
);
}
/* /*
* A constant defining the maximum number of characters we will keep from * A constant defining the maximum number of characters we will keep from
* the programs stderr for logging. This serves two purposes: * the programs stderr for logging. This serves two purposes:

View File

@@ -5,7 +5,11 @@ import * as yaml from "js-yaml";
import * as semver from "semver"; import * as semver from "semver";
import * as api from "./api-client"; import * as api from "./api-client";
import { CodeQL, ResolveQueriesOutput } from "./codeql"; import {
CodeQL,
ResolveQueriesOutput,
supportsDownloadPacksFromSuites,
} from "./codeql";
import * as externalQueries from "./external-queries"; import * as externalQueries from "./external-queries";
import { Language, parseLanguage } from "./languages"; import { Language, parseLanguage } from "./languages";
import { Logger } from "./logging"; import { Logger } from "./logging";
@@ -202,6 +206,10 @@ async function runResolveQueries(
toResolve: string[], toResolve: string[],
extraSearchPath: string | undefined extraSearchPath: string | undefined
) { ) {
// before running resolve queries, must run download packs, if the CLI is new enough
if (await supportsDownloadPacksFromSuites(codeQL)) {
await codeQL.packDownload(toResolve, extraSearchPath);
}
const resolvedQueries = await codeQL.resolveQueries( const resolvedQueries = await codeQL.resolveQueries(
toResolve, toResolve,
extraSearchPath extraSearchPath