Merge pull request #907 from github/henrymercer/report-ml-powered-query-enablement

Report ML-powered query enablement in the `init` status report
This commit is contained in:
Henry Mercer 2022-02-07 17:16:25 +00:00 committed by GitHub
commit 4eb03fb6f3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 398 additions and 119 deletions

13
lib/config-utils.js generated
View file

@ -120,24 +120,23 @@ const builtinSuites = ["security-extended", "security-and-quality"];
* Throws an error if suiteName is not a valid builtin suite. * Throws an error if suiteName is not a valid builtin suite.
*/ */
async function addBuiltinSuiteQueries(languages, codeQL, resultMap, packs, suiteName, featureFlags, configFile) { async function addBuiltinSuiteQueries(languages, codeQL, resultMap, packs, suiteName, featureFlags, configFile) {
var _a;
const found = builtinSuites.find((suite) => suite === suiteName); const found = builtinSuites.find((suite) => suite === suiteName);
if (!found) { if (!found) {
throw new Error(getQueryUsesInvalid(configFile, suiteName)); throw new Error(getQueryUsesInvalid(configFile, suiteName));
} }
// If we're running the JavaScript security-extended analysis (or a superset of it) and the repo // If we're running the JavaScript security-extended analysis (or a superset of it), the repo is
// is opted into the ML-powered queries beta, then add the ML-powered query pack so that we run // opted into the ML-powered queries beta, and a user hasn't already added the ML-powered query
// the ML-powered queries. // pack, then add the ML-powered query pack so that we run ML-powered queries.
if (languages.includes("javascript") && if (languages.includes("javascript") &&
(found === "security-extended" || found === "security-and-quality") && (found === "security-extended" || found === "security-and-quality") &&
!((_a = packs.javascript) === null || _a === void 0 ? void 0 : _a.some((pack) => pack.packName === util_1.ML_POWERED_JS_QUERIES_PACK.packName)) &&
(await featureFlags.getValue(feature_flags_1.FeatureFlag.MlPoweredQueriesEnabled)) && (await featureFlags.getValue(feature_flags_1.FeatureFlag.MlPoweredQueriesEnabled)) &&
(await (0, util_1.codeQlVersionAbove)(codeQL, codeql_1.CODEQL_VERSION_ML_POWERED_QUERIES))) { (await (0, util_1.codeQlVersionAbove)(codeQL, codeql_1.CODEQL_VERSION_ML_POWERED_QUERIES))) {
if (!packs.javascript) { if (!packs.javascript) {
packs.javascript = []; packs.javascript = [];
} }
packs.javascript.push({ packs.javascript.push(util_1.ML_POWERED_JS_QUERIES_PACK);
packName: "codeql/javascript-experimental-atm-queries",
version: "~0.0.2",
});
} }
const suites = languages.map((l) => `${l}-${suiteName}.qls`); const suites = languages.map((l) => `${l}-${suiteName}.qls`);
await runResolveQueries(codeQL, resultMap, suites, undefined); await runResolveQueries(codeQL, resultMap, suites, undefined);

File diff suppressed because one or more lines are too long

View file

@ -872,7 +872,7 @@ parseInputAndConfigErrorMacro.title = (providedTitle) => `Parse Packs input and
(0, ava_1.default)("input with + only", parseInputAndConfigErrorMacro, {}, " + ", [languages_1.Language.cpp], /remove the '\+'/); (0, ava_1.default)("input with + only", parseInputAndConfigErrorMacro, {}, " + ", [languages_1.Language.cpp], /remove the '\+'/);
(0, ava_1.default)("input with invalid pack name", parseInputAndConfigErrorMacro, {}, " xxx", [languages_1.Language.cpp], /"xxx" is not a valid pack/); (0, ava_1.default)("input with invalid pack name", parseInputAndConfigErrorMacro, {}, " xxx", [languages_1.Language.cpp], /"xxx" is not a valid pack/);
const mlPoweredQueriesMacro = ava_1.default.macro({ const mlPoweredQueriesMacro = ava_1.default.macro({
exec: async (t, codeQLVersion, isMlPoweredQueriesFlagEnabled, queriesInput, shouldRunMlPoweredQueries) => { exec: async (t, codeQLVersion, isMlPoweredQueriesFlagEnabled, packsInput, queriesInput, expectedVersionString) => {
return await util.withTmpDir(async (tmpDir) => { return await util.withTmpDir(async (tmpDir) => {
const codeQL = (0, codeql_1.setCodeQL)({ const codeQL = (0, codeql_1.setCodeQL)({
async getVersion() { async getVersion() {
@ -888,15 +888,15 @@ const mlPoweredQueriesMacro = ava_1.default.macro({
}; };
}, },
}); });
const { packs } = await configUtils.initConfig("javascript", queriesInput, undefined, undefined, undefined, false, "", "", { owner: "github", repo: "example " }, tmpDir, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, feature_flags_1.createFeatureFlags)(isMlPoweredQueriesFlagEnabled const { packs } = await configUtils.initConfig("javascript", queriesInput, packsInput, undefined, undefined, false, "", "", { owner: "github", repo: "example " }, tmpDir, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, feature_flags_1.createFeatureFlags)(isMlPoweredQueriesFlagEnabled
? [feature_flags_1.FeatureFlag.MlPoweredQueriesEnabled] ? [feature_flags_1.FeatureFlag.MlPoweredQueriesEnabled]
: []), (0, logging_1.getRunnerLogger)(true)); : []), (0, logging_1.getRunnerLogger)(true));
if (shouldRunMlPoweredQueries) { if (expectedVersionString !== undefined) {
t.deepEqual(packs, { t.deepEqual(packs, {
[languages_1.Language.javascript]: [ [languages_1.Language.javascript]: [
{ {
packName: "codeql/javascript-experimental-atm-queries", packName: "codeql/javascript-experimental-atm-queries",
version: "~0.0.2", version: expectedVersionString,
}, },
], ],
}); });
@ -906,17 +906,15 @@ const mlPoweredQueriesMacro = ava_1.default.macro({
} }
}); });
}, },
title: (_providedTitle, codeQLVersion, isMlPoweredQueriesFlagEnabled, queriesInput, shouldRunMlPoweredQueries) => { title: (_providedTitle, codeQLVersion, isMlPoweredQueriesFlagEnabled, packsInput, queriesInput, expectedVersionString) => `ML-powered queries ${expectedVersionString !== undefined
const queriesInputDescription = queriesInput ? `${expectedVersionString} are`
? `'queries: ${queriesInput}'` : "aren't"} loaded for packs: ${packsInput}, queries: ${queriesInput} using CLI v${codeQLVersion} when feature flag is ${isMlPoweredQueriesFlagEnabled ? "enabled" : "disabled"}`,
: "default config";
return `ML-powered queries ${shouldRunMlPoweredQueries ? "are" : "aren't"} loaded for ${queriesInputDescription} using CLI v${codeQLVersion} when feature flag is ${isMlPoweredQueriesFlagEnabled ? "enabled" : "disabled"}`;
},
}); });
// macro, isMlPoweredQueriesFlagEnabled, queriesInput, shouldRunMlPoweredQueries // macro, isMlPoweredQueriesFlagEnabled, packsInput, queriesInput, versionString
(0, ava_1.default)(mlPoweredQueriesMacro, "2.7.4", true, "security-extended", false); (0, ava_1.default)(mlPoweredQueriesMacro, "2.7.4", true, undefined, "security-extended", undefined);
(0, ava_1.default)(mlPoweredQueriesMacro, "2.7.5", false, "security-extended", false); (0, ava_1.default)(mlPoweredQueriesMacro, "2.7.5", false, undefined, "security-extended", undefined);
(0, ava_1.default)(mlPoweredQueriesMacro, "2.7.5", true, undefined, false); (0, ava_1.default)(mlPoweredQueriesMacro, "2.7.5", true, undefined, undefined, undefined);
(0, ava_1.default)(mlPoweredQueriesMacro, "2.7.5", true, "security-extended", true); (0, ava_1.default)(mlPoweredQueriesMacro, "2.7.5", true, undefined, "security-extended", "~0.0.2");
(0, ava_1.default)(mlPoweredQueriesMacro, "2.7.5", true, "security-and-quality", true); (0, ava_1.default)(mlPoweredQueriesMacro, "2.7.5", true, undefined, "security-and-quality", "~0.0.2");
(0, ava_1.default)(mlPoweredQueriesMacro, "2.7.5", true, "codeql/javascript-experimental-atm-queries@0.0.1", "security-and-quality", "0.0.1");
//# sourceMappingURL=config-utils.test.js.map //# sourceMappingURL=config-utils.test.js.map

File diff suppressed because one or more lines are too long

5
lib/init-action.js generated
View file

@ -54,14 +54,15 @@ async function sendSuccessStatusReport(startedAt, config, toolsVersion) {
} }
const statusReport = { const statusReport = {
...statusReportBase, ...statusReportBase,
disable_default_queries: disableDefaultQueries,
languages, languages,
workflow_languages: workflowLanguages || "", ml_powered_js_queries: (0, util_1.getMlPoweredJsQueriesStatus)(config),
paths, paths,
paths_ignore: pathsIgnore, paths_ignore: pathsIgnore,
disable_default_queries: disableDefaultQueries,
queries: queries.join(","), queries: queries.join(","),
tools_input: (0, actions_util_1.getOptionalInput)("tools") || "", tools_input: (0, actions_util_1.getOptionalInput)("tools") || "",
tools_resolved_version: toolsVersion, tools_resolved_version: toolsVersion,
workflow_languages: workflowLanguages || "",
}; };
await (0, actions_util_1.sendStatusReport)(statusReport); await (0, actions_util_1.sendStatusReport)(statusReport);
} }

File diff suppressed because one or more lines are too long

55
lib/util.js generated
View file

@ -22,7 +22,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.checkNotWindows11 = exports.isGoodVersion = exports.delay = exports.bundleDb = exports.codeQlVersionAbove = exports.isHTTPError = exports.HTTPError = exports.getRequiredEnvParam = exports.isActions = exports.getMode = exports.enrichEnvironment = exports.initializeEnvironment = exports.Mode = exports.assertNever = exports.getGitHubAuth = exports.apiVersionInRange = exports.DisallowedAPIVersionReason = exports.checkGitHubVersionInRange = exports.getGitHubVersion = exports.GitHubVariant = exports.parseGitHubUrl = exports.getCodeQLDatabasePath = exports.getThreadsFlag = exports.getThreadsFlagValue = exports.getAddSnippetsFlag = exports.getMemoryFlag = exports.getMemoryFlagValue = exports.withTmpDir = exports.getToolNames = exports.getExtraOptionsEnvParam = exports.DEFAULT_DEBUG_DATABASE_NAME = exports.DEFAULT_DEBUG_ARTIFACT_NAME = exports.GITHUB_DOTCOM_URL = void 0; exports.getMlPoweredJsQueriesStatus = exports.ML_POWERED_JS_QUERIES_PACK = exports.checkNotWindows11 = exports.isGoodVersion = exports.delay = exports.bundleDb = exports.codeQlVersionAbove = exports.isHTTPError = exports.HTTPError = exports.getRequiredEnvParam = exports.isActions = exports.getMode = exports.enrichEnvironment = exports.initializeEnvironment = exports.Mode = exports.assertNever = exports.getGitHubAuth = exports.apiVersionInRange = exports.DisallowedAPIVersionReason = exports.checkGitHubVersionInRange = exports.getGitHubVersion = exports.GitHubVariant = exports.parseGitHubUrl = exports.getCodeQLDatabasePath = exports.getThreadsFlag = exports.getThreadsFlagValue = exports.getAddSnippetsFlag = exports.getMemoryFlag = exports.getMemoryFlagValue = exports.withTmpDir = exports.getToolNames = exports.getExtraOptionsEnvParam = exports.DEFAULT_DEBUG_DATABASE_NAME = exports.DEFAULT_DEBUG_ARTIFACT_NAME = exports.GITHUB_DOTCOM_URL = void 0;
const fs = __importStar(require("fs")); const fs = __importStar(require("fs"));
const os = __importStar(require("os")); const os = __importStar(require("os"));
const path = __importStar(require("path")); const path = __importStar(require("path"));
@ -524,4 +524,57 @@ function checkNotWindows11() {
} }
} }
exports.checkNotWindows11 = checkNotWindows11; exports.checkNotWindows11 = checkNotWindows11;
/**
* The ML-powered JS query pack to add to the analysis if a repo is opted into the ML-powered
* queries beta.
*/
exports.ML_POWERED_JS_QUERIES_PACK = {
packName: "codeql/javascript-experimental-atm-queries",
version: "~0.0.2",
};
/**
* Get information about ML-powered JS queries to populate status reports with.
*
* This will be:
*
* - The version string if the analysis is using the ML-powered query pack that will be added to the
* analysis if the repo is opted into the ML-powered queries beta, i.e.
* {@link ML_POWERED_JS_QUERIES_PACK.version}. If the version string
* {@link ML_POWERED_JS_QUERIES_PACK.version} is undefined, then the status report string will be
* "latest", however this shouldn't occur in practice (see comment below).
* - "false" if the analysis won't run any ML-powered JS queries.
* - "other" in all other cases.
*
* Our goal of the status report here is to allow us to compare the occurrence of timeouts and other
* errors with ML-powered queries turned on and off. We also want to be able to compare minor
* version bumps caused by us bumping the version range of `ML_POWERED_JS_QUERIES_PACK` in a new
* version of the CodeQL Action. For instance, we might want to compare the `~0.1.0` and `~0.0.2`
* version strings.
*
* We restrict the set of strings we report here by excluding other version strings and combinations
* of version strings. We do this to limit the cardinality of the ML-powered JS queries status
* report field, since some platforms that ingest this status report bill based on the cardinality
* of its fields.
*
* This function lives here rather than in `init-action.ts` so it's easier to test, since tests for
* `init-action.ts` would each need to live in their own file. See `analyze-action-env.ts` for an
* explanation as to why this is.
*/
function getMlPoweredJsQueriesStatus(config) {
const mlPoweredJsQueryPacks = (config.packs.javascript || []).filter((pack) => pack.packName === exports.ML_POWERED_JS_QUERIES_PACK.packName);
if (mlPoweredJsQueryPacks.length === 0) {
return "false";
}
const firstVersionString = mlPoweredJsQueryPacks[0].version;
if (mlPoweredJsQueryPacks.length === 1 &&
exports.ML_POWERED_JS_QUERIES_PACK.version === firstVersionString) {
// We should always specify an explicit version string in `ML_POWERED_JS_QUERIES_PACK`,
// otherwise we won't be able to make changes to the pack unless those changes are compatible
// with each version of the CodeQL Action. Therefore in practice, we should never hit the
// `latest` case here.
return exports.ML_POWERED_JS_QUERIES_PACK.version || "latest";
}
return "other";
}
exports.getMlPoweredJsQueriesStatus = getMlPoweredJsQueriesStatus;
//# sourceMappingURL=util.js.map //# sourceMappingURL=util.js.map

File diff suppressed because one or more lines are too long

58
lib/util.test.js generated
View file

@ -204,4 +204,62 @@ async function mockStdInForAuthExpectError(t, mockLogger, ...text) {
const stdin = stream.Readable.from(text); const stdin = stream.Readable.from(text);
await t.throwsAsync(async () => util.getGitHubAuth(mockLogger, undefined, true, stdin)); await t.throwsAsync(async () => util.getGitHubAuth(mockLogger, undefined, true, stdin));
} }
const ML_POWERED_JS_STATUS_TESTS = [
[[], "false"],
[[{ packName: "someOtherPack" }], "false"],
[
[{ packName: "someOtherPack" }, util.ML_POWERED_JS_QUERIES_PACK],
util.ML_POWERED_JS_QUERIES_PACK.version,
],
[[util.ML_POWERED_JS_QUERIES_PACK], util.ML_POWERED_JS_QUERIES_PACK.version],
[[{ packName: util.ML_POWERED_JS_QUERIES_PACK.packName }], "other"],
[
[{ packName: util.ML_POWERED_JS_QUERIES_PACK.packName, version: "~0.0.1" }],
"other",
],
[
[
{ packName: util.ML_POWERED_JS_QUERIES_PACK.packName, version: "0.0.1" },
{ packName: util.ML_POWERED_JS_QUERIES_PACK.packName, version: "0.0.2" },
],
"other",
],
[
[
{ packName: "someOtherPack" },
{ packName: util.ML_POWERED_JS_QUERIES_PACK.packName },
],
"other",
],
];
for (const [packs, expectedStatus] of ML_POWERED_JS_STATUS_TESTS) {
const packDescriptions = `[${packs
.map((pack) => JSON.stringify(pack))
.join(", ")}]`;
(0, ava_1.default)(`ML-powered JS queries status report is "${expectedStatus}" for packs = ${packDescriptions}`, (t) => {
return util.withTmpDir(async (tmpDir) => {
const config = {
languages: [],
queries: {},
paths: [],
pathsIgnore: [],
originalUserInput: {},
tempDir: tmpDir,
toolCacheDir: tmpDir,
codeQLCmd: "",
gitHubVersion: {
type: util.GitHubVariant.DOTCOM,
},
dbLocation: "",
packs: {
javascript: packs,
},
debugMode: false,
debugArtifactName: util.DEFAULT_DEBUG_ARTIFACT_NAME,
debugDatabaseName: util.DEFAULT_DEBUG_DATABASE_NAME,
};
t.is(util.getMlPoweredJsQueriesStatus(config), expectedStatus);
});
});
}
//# sourceMappingURL=util.test.js.map //# sourceMappingURL=util.test.js.map

File diff suppressed because one or more lines are too long

View file

@ -548,37 +548,37 @@ type ActionName = "init" | "autobuild" | "finish" | "upload-sarif";
type ActionStatus = "starting" | "aborted" | "success" | "failure"; type ActionStatus = "starting" | "aborted" | "success" | "failure";
export interface StatusReportBase { export interface StatusReportBase {
// ID of the workflow run containing the action run /** ID of the workflow run containing the action run. */
workflow_run_id: number; workflow_run_id: number;
// Workflow name. Converted to analysis_name further down the pipeline. /** Workflow name. Converted to analysis_name further down the pipeline.. */
workflow_name: string; workflow_name: string;
// Job name from the workflow /** Job name from the workflow. */
job_name: string; job_name: string;
// Analysis key, normally composed from the workflow path and job name /** Analysis key, normally composed from the workflow path and job name. */
analysis_key: string; analysis_key: string;
// Value of the matrix for this instantiation of the job /** Value of the matrix for this instantiation of the job. */
matrix_vars?: string; matrix_vars?: string;
// Commit oid that the workflow was triggered on /** Commit oid that the workflow was triggered on. */
commit_oid: string; commit_oid: string;
// Ref that the workflow was triggered on /** Ref that the workflow was triggered on. */
ref: string; ref: string;
// Name of the action being executed /** Name of the action being executed. */
action_name: ActionName; action_name: ActionName;
// Version of the action being executed, as a ref /** Version of the action being executed, as a ref. */
action_ref?: string; action_ref?: string;
// Version of the action being executed, as a commit oid /** Version of the action being executed, as a commit oid. */
action_oid: string; action_oid: string;
// Time the first action started. Normally the init action /** Time the first action started. Normally the init action. */
started_at: string; started_at: string;
// Time this action started /** Time this action started. */
action_started_at: string; action_started_at: string;
// Time this action completed, or undefined if not yet completed /** Time this action completed, or undefined if not yet completed. */
completed_at?: string; completed_at?: string;
// State this action is currently in /** State this action is currently in. */
status: ActionStatus; status: ActionStatus;
// Cause of the failure (or undefined if status is not failure) /** Cause of the failure (or undefined if status is not failure). */
cause?: string; cause?: string;
// Stack trace of the failure (or undefined if status is not failure) /** Stack trace of the failure (or undefined if status is not failure). */
exception?: string; exception?: string;
} }

View file

@ -25,49 +25,49 @@ export class CodeQLAnalysisError extends Error {
} }
export interface QueriesStatusReport { export interface QueriesStatusReport {
// Time taken in ms to run builtin queries for cpp (or undefined if this language was not analyzed) /** Time taken in ms to run builtin queries for cpp (or undefined if this language was not analyzed). */
analyze_builtin_queries_cpp_duration_ms?: number; analyze_builtin_queries_cpp_duration_ms?: number;
// Time taken in ms to run builtin queries for csharp (or undefined if this language was not analyzed) /** Time taken in ms to run builtin queries for csharp (or undefined if this language was not analyzed). */
analyze_builtin_queries_csharp_duration_ms?: number; analyze_builtin_queries_csharp_duration_ms?: number;
// Time taken in ms to run builtin queries for go (or undefined if this language was not analyzed) /** Time taken in ms to run builtin queries for go (or undefined if this language was not analyzed). */
analyze_builtin_queries_go_duration_ms?: number; analyze_builtin_queries_go_duration_ms?: number;
// Time taken in ms to run builtin queries for java (or undefined if this language was not analyzed) /** Time taken in ms to run builtin queries for java (or undefined if this language was not analyzed). */
analyze_builtin_queries_java_duration_ms?: number; analyze_builtin_queries_java_duration_ms?: number;
// Time taken in ms to run builtin queries for javascript (or undefined if this language was not analyzed) /** Time taken in ms to run builtin queries for javascript (or undefined if this language was not analyzed). */
analyze_builtin_queries_javascript_duration_ms?: number; analyze_builtin_queries_javascript_duration_ms?: number;
// Time taken in ms to run builtin queries for python (or undefined if this language was not analyzed) /** Time taken in ms to run builtin queries for python (or undefined if this language was not analyzed). */
analyze_builtin_queries_python_duration_ms?: number; analyze_builtin_queries_python_duration_ms?: number;
// Time taken in ms to run builtin queries for ruby (or undefined if this language was not analyzed) /** Time taken in ms to run builtin queries for ruby (or undefined if this language was not analyzed). */
analyze_builtin_queries_ruby_duration_ms?: number; analyze_builtin_queries_ruby_duration_ms?: number;
// Time taken in ms to run custom queries for cpp (or undefined if this language was not analyzed) /** Time taken in ms to run custom queries for cpp (or undefined if this language was not analyzed). */
analyze_custom_queries_cpp_duration_ms?: number; analyze_custom_queries_cpp_duration_ms?: number;
// Time taken in ms to run custom queries for csharp (or undefined if this language was not analyzed) /** Time taken in ms to run custom queries for csharp (or undefined if this language was not analyzed). */
analyze_custom_queries_csharp_duration_ms?: number; analyze_custom_queries_csharp_duration_ms?: number;
// Time taken in ms to run custom queries for go (or undefined if this language was not analyzed) /** Time taken in ms to run custom queries for go (or undefined if this language was not analyzed). */
analyze_custom_queries_go_duration_ms?: number; analyze_custom_queries_go_duration_ms?: number;
// Time taken in ms to run custom queries for java (or undefined if this language was not analyzed) /** Time taken in ms to run custom queries for java (or undefined if this language was not analyzed). */
analyze_custom_queries_java_duration_ms?: number; analyze_custom_queries_java_duration_ms?: number;
// Time taken in ms to run custom queries for javascript (or undefined if this language was not analyzed) /** Time taken in ms to run custom queries for javascript (or undefined if this language was not analyzed). */
analyze_custom_queries_javascript_duration_ms?: number; analyze_custom_queries_javascript_duration_ms?: number;
// Time taken in ms to run custom queries for python (or undefined if this language was not analyzed) /** Time taken in ms to run custom queries for python (or undefined if this language was not analyzed). */
analyze_custom_queries_python_duration_ms?: number; analyze_custom_queries_python_duration_ms?: number;
// Time taken in ms to run custom queries for ruby (or undefined if this language was not analyzed) /** Time taken in ms to run custom queries for ruby (or undefined if this language was not analyzed). */
analyze_custom_queries_ruby_duration_ms?: number; analyze_custom_queries_ruby_duration_ms?: number;
// Time taken in ms to interpret results for cpp (or undefined if this language was not analyzed) /** Time taken in ms to interpret results for cpp (or undefined if this language was not analyzed). */
interpret_results_cpp_duration_ms?: number; interpret_results_cpp_duration_ms?: number;
// Time taken in ms to interpret results for csharp (or undefined if this language was not analyzed) /** Time taken in ms to interpret results for csharp (or undefined if this language was not analyzed). */
interpret_results_csharp_duration_ms?: number; interpret_results_csharp_duration_ms?: number;
// Time taken in ms to interpret results for go (or undefined if this language was not analyzed) /** Time taken in ms to interpret results for go (or undefined if this language was not analyzed). */
interpret_results_go_duration_ms?: number; interpret_results_go_duration_ms?: number;
// Time taken in ms to interpret results for java (or undefined if this language was not analyzed) /** Time taken in ms to interpret results for java (or undefined if this language was not analyzed). */
interpret_results_java_duration_ms?: number; interpret_results_java_duration_ms?: number;
// Time taken in ms to interpret results for javascript (or undefined if this language was not analyzed) /** Time taken in ms to interpret results for javascript (or undefined if this language was not analyzed). */
interpret_results_javascript_duration_ms?: number; interpret_results_javascript_duration_ms?: number;
// Time taken in ms to interpret results for python (or undefined if this language was not analyzed) /** Time taken in ms to interpret results for python (or undefined if this language was not analyzed). */
interpret_results_python_duration_ms?: number; interpret_results_python_duration_ms?: number;
// Time taken in ms to interpret results for ruby (or undefined if this language was not analyzed) /** Time taken in ms to interpret results for ruby (or undefined if this language was not analyzed). */
interpret_results_ruby_duration_ms?: number; interpret_results_ruby_duration_ms?: number;
// Name of language that errored during analysis (or undefined if no language failed) /** Name of language that errored during analysis (or undefined if no language failed). */
analyze_failure_language?: string; analyze_failure_language?: string;
} }

View file

@ -16,9 +16,9 @@ import { initializeEnvironment, Mode } from "./util";
const pkg = require("../package.json"); const pkg = require("../package.json");
interface AutobuildStatusReport extends StatusReportBase { interface AutobuildStatusReport extends StatusReportBase {
// Comma-separated set of languages being auto-built /** Comma-separated set of languages being auto-built. */
autobuild_languages: string; autobuild_languages: string;
// Language that failed autobuilding (or undefined if all languages succeeded). /** Language that failed autobuilding (or undefined if all languages succeeded). */
autobuild_failure?: string; autobuild_failure?: string;
} }

View file

@ -1713,8 +1713,9 @@ const mlPoweredQueriesMacro = test.macro({
t: ExecutionContext, t: ExecutionContext,
codeQLVersion: string, codeQLVersion: string,
isMlPoweredQueriesFlagEnabled: boolean, isMlPoweredQueriesFlagEnabled: boolean,
packsInput: string | undefined,
queriesInput: string | undefined, queriesInput: string | undefined,
shouldRunMlPoweredQueries: boolean expectedVersionString: string | undefined
) => { ) => {
return await util.withTmpDir(async (tmpDir) => { return await util.withTmpDir(async (tmpDir) => {
const codeQL = setCodeQL({ const codeQL = setCodeQL({
@ -1735,7 +1736,7 @@ const mlPoweredQueriesMacro = test.macro({
const { packs } = await configUtils.initConfig( const { packs } = await configUtils.initConfig(
"javascript", "javascript",
queriesInput, queriesInput,
undefined, packsInput,
undefined, undefined,
undefined, undefined,
false, false,
@ -1755,12 +1756,12 @@ const mlPoweredQueriesMacro = test.macro({
), ),
getRunnerLogger(true) getRunnerLogger(true)
); );
if (shouldRunMlPoweredQueries) { if (expectedVersionString !== undefined) {
t.deepEqual(packs as unknown, { t.deepEqual(packs as unknown, {
[Language.javascript]: [ [Language.javascript]: [
{ {
packName: "codeql/javascript-experimental-atm-queries", packName: "codeql/javascript-experimental-atm-queries",
version: "~0.0.2", version: expectedVersionString,
}, },
], ],
}); });
@ -1773,24 +1774,58 @@ const mlPoweredQueriesMacro = test.macro({
_providedTitle: string | undefined, _providedTitle: string | undefined,
codeQLVersion: string, codeQLVersion: string,
isMlPoweredQueriesFlagEnabled: boolean, isMlPoweredQueriesFlagEnabled: boolean,
packsInput: string | undefined,
queriesInput: string | undefined, queriesInput: string | undefined,
shouldRunMlPoweredQueries: boolean expectedVersionString: string | undefined
) => { ) =>
const queriesInputDescription = queriesInput `ML-powered queries ${
? `'queries: ${queriesInput}'` expectedVersionString !== undefined
: "default config"; ? `${expectedVersionString} are`
: "aren't"
return `ML-powered queries ${ } loaded for packs: ${packsInput}, queries: ${queriesInput} using CLI v${codeQLVersion} when feature flag is ${
shouldRunMlPoweredQueries ? "are" : "aren't"
} loaded for ${queriesInputDescription} using CLI v${codeQLVersion} when feature flag is ${
isMlPoweredQueriesFlagEnabled ? "enabled" : "disabled" isMlPoweredQueriesFlagEnabled ? "enabled" : "disabled"
}`; }`,
},
}); });
// macro, isMlPoweredQueriesFlagEnabled, queriesInput, shouldRunMlPoweredQueries // macro, isMlPoweredQueriesFlagEnabled, packsInput, queriesInput, versionString
test(mlPoweredQueriesMacro, "2.7.4", true, "security-extended", false); test(
test(mlPoweredQueriesMacro, "2.7.5", false, "security-extended", false); mlPoweredQueriesMacro,
test(mlPoweredQueriesMacro, "2.7.5", true, undefined, false); "2.7.4",
test(mlPoweredQueriesMacro, "2.7.5", true, "security-extended", true); true,
test(mlPoweredQueriesMacro, "2.7.5", true, "security-and-quality", true); undefined,
"security-extended",
undefined
);
test(
mlPoweredQueriesMacro,
"2.7.5",
false,
undefined,
"security-extended",
undefined
);
test(mlPoweredQueriesMacro, "2.7.5", true, undefined, undefined, undefined);
test(
mlPoweredQueriesMacro,
"2.7.5",
true,
undefined,
"security-extended",
"~0.0.2"
);
test(
mlPoweredQueriesMacro,
"2.7.5",
true,
undefined,
"security-and-quality",
"~0.0.2"
);
test(
mlPoweredQueriesMacro,
"2.7.5",
true,
"codeql/javascript-experimental-atm-queries@0.0.1",
"security-and-quality",
"0.0.1"
);

View file

@ -15,7 +15,11 @@ import { FeatureFlag, FeatureFlags } from "./feature-flags";
import { Language, parseLanguage } from "./languages"; import { Language, parseLanguage } from "./languages";
import { Logger } from "./logging"; import { Logger } from "./logging";
import { RepositoryNwo } from "./repository"; import { RepositoryNwo } from "./repository";
import { codeQlVersionAbove, GitHubVersion } from "./util"; import {
codeQlVersionAbove,
GitHubVersion,
ML_POWERED_JS_QUERIES_PACK,
} from "./util";
// Property names from the user-supplied config file. // Property names from the user-supplied config file.
const NAME_PROPERTY = "name"; const NAME_PROPERTY = "name";
@ -285,22 +289,22 @@ async function addBuiltinSuiteQueries(
throw new Error(getQueryUsesInvalid(configFile, suiteName)); throw new Error(getQueryUsesInvalid(configFile, suiteName));
} }
// If we're running the JavaScript security-extended analysis (or a superset of it) and the repo // If we're running the JavaScript security-extended analysis (or a superset of it), the repo is
// is opted into the ML-powered queries beta, then add the ML-powered query pack so that we run // opted into the ML-powered queries beta, and a user hasn't already added the ML-powered query
// the ML-powered queries. // pack, then add the ML-powered query pack so that we run ML-powered queries.
if ( if (
languages.includes("javascript") && languages.includes("javascript") &&
(found === "security-extended" || found === "security-and-quality") && (found === "security-extended" || found === "security-and-quality") &&
!packs.javascript?.some(
(pack) => pack.packName === ML_POWERED_JS_QUERIES_PACK.packName
) &&
(await featureFlags.getValue(FeatureFlag.MlPoweredQueriesEnabled)) && (await featureFlags.getValue(FeatureFlag.MlPoweredQueriesEnabled)) &&
(await codeQlVersionAbove(codeQL, CODEQL_VERSION_ML_POWERED_QUERIES)) (await codeQlVersionAbove(codeQL, CODEQL_VERSION_ML_POWERED_QUERIES))
) { ) {
if (!packs.javascript) { if (!packs.javascript) {
packs.javascript = []; packs.javascript = [];
} }
packs.javascript.push({ packs.javascript.push(ML_POWERED_JS_QUERIES_PACK);
packName: "codeql/javascript-experimental-atm-queries",
version: "~0.0.2",
});
} }
const suites = languages.map((l) => `${l}-${suiteName}.qls`); const suites = languages.map((l) => `${l}-${suiteName}.qls`);

View file

@ -38,29 +38,39 @@ import {
DEFAULT_DEBUG_ARTIFACT_NAME, DEFAULT_DEBUG_ARTIFACT_NAME,
DEFAULT_DEBUG_DATABASE_NAME, DEFAULT_DEBUG_DATABASE_NAME,
checkNotWindows11, checkNotWindows11,
getMlPoweredJsQueriesStatus,
} from "./util"; } from "./util";
// eslint-disable-next-line import/no-commonjs // eslint-disable-next-line import/no-commonjs
const pkg = require("../package.json"); const pkg = require("../package.json");
interface InitSuccessStatusReport extends StatusReportBase { interface InitSuccessStatusReport extends StatusReportBase {
// Comma-separated list of languages that analysis was run for /** Comma-separated list of languages where the default queries are disabled. */
// This may be from the workflow file or may be calculated from repository contents
languages: string;
// Comma-separated list of languages specified explicitly in the workflow file
workflow_languages: string;
// Comma-separated list of paths, from the 'paths' config field
paths: string;
// Comma-separated list of paths, from the 'paths-ignore' config field
paths_ignore: string;
// Commas-separated list of languages where the default queries are disabled
disable_default_queries: string; disable_default_queries: string;
// Comma-separated list of queries sources, from the 'queries' config field or workflow input /**
* Comma-separated list of languages that analysis was run for.
*
* This may be from the workflow file or may be calculated from repository contents
*/
languages: string;
/**
* Information about the enablement of the ML-powered JS query pack.
*
* @see {@link getMlPoweredJsQueriesStatus}
*/
ml_powered_js_queries: string;
/** Comma-separated list of paths, from the 'paths' config field. */
paths: string;
/** Comma-separated list of paths, from the 'paths-ignore' config field. */
paths_ignore: string;
/** Comma-separated list of queries sources, from the 'queries' config field or workflow input. */
queries: string; queries: string;
// Value given by the user as the "tools" input /** Value given by the user as the "tools" input. */
tools_input: string; tools_input: string;
// Version of the bundle used /** Version of the bundle used. */
tools_resolved_version: string; tools_resolved_version: string;
/** Comma-separated list of languages specified explicitly in the workflow file. */
workflow_languages: string;
} }
async function sendSuccessStatusReport( async function sendSuccessStatusReport(
@ -102,14 +112,15 @@ async function sendSuccessStatusReport(
const statusReport: InitSuccessStatusReport = { const statusReport: InitSuccessStatusReport = {
...statusReportBase, ...statusReportBase,
disable_default_queries: disableDefaultQueries,
languages, languages,
workflow_languages: workflowLanguages || "", ml_powered_js_queries: getMlPoweredJsQueriesStatus(config),
paths, paths,
paths_ignore: pathsIgnore, paths_ignore: pathsIgnore,
disable_default_queries: disableDefaultQueries,
queries: queries.join(","), queries: queries.join(","),
tools_input: getOptionalInput("tools") || "", tools_input: getOptionalInput("tools") || "",
tools_resolved_version: toolsVersion, tools_resolved_version: toolsVersion,
workflow_languages: workflowLanguages || "",
}; };
await sendStatusReport(statusReport); await sendStatusReport(statusReport);

View file

@ -122,11 +122,11 @@ async function uploadPayload(
} }
export interface UploadStatusReport { export interface UploadStatusReport {
// Size in bytes of unzipped SARIF upload /** Size in bytes of unzipped SARIF upload. */
raw_upload_size_bytes?: number; raw_upload_size_bytes?: number;
// Size in bytes of actual SARIF upload /** Size in bytes of actual SARIF upload. */
zipped_upload_size_bytes?: number; zipped_upload_size_bytes?: number;
// Number of results in the SARIF upload /** Number of results in the SARIF upload. */
num_results_in_sarif?: number; num_results_in_sarif?: number;
} }

View file

@ -7,6 +7,7 @@ import test, { ExecutionContext } from "ava";
import * as sinon from "sinon"; import * as sinon from "sinon";
import * as api from "./api-client"; import * as api from "./api-client";
import { Config, PackWithVersion } from "./config-utils";
import { getRunnerLogger, Logger } from "./logging"; import { getRunnerLogger, Logger } from "./logging";
import { setupTests } from "./testing-utils"; import { setupTests } from "./testing-utils";
import * as util from "./util"; import * as util from "./util";
@ -291,3 +292,64 @@ async function mockStdInForAuthExpectError(
util.getGitHubAuth(mockLogger, undefined, true, stdin) util.getGitHubAuth(mockLogger, undefined, true, stdin)
); );
} }
const ML_POWERED_JS_STATUS_TESTS: Array<[PackWithVersion[], string]> = [
[[], "false"],
[[{ packName: "someOtherPack" }], "false"],
[
[{ packName: "someOtherPack" }, util.ML_POWERED_JS_QUERIES_PACK],
util.ML_POWERED_JS_QUERIES_PACK.version!,
],
[[util.ML_POWERED_JS_QUERIES_PACK], util.ML_POWERED_JS_QUERIES_PACK.version!],
[[{ packName: util.ML_POWERED_JS_QUERIES_PACK.packName }], "other"],
[
[{ packName: util.ML_POWERED_JS_QUERIES_PACK.packName, version: "~0.0.1" }],
"other",
],
[
[
{ packName: util.ML_POWERED_JS_QUERIES_PACK.packName, version: "0.0.1" },
{ packName: util.ML_POWERED_JS_QUERIES_PACK.packName, version: "0.0.2" },
],
"other",
],
[
[
{ packName: "someOtherPack" },
{ packName: util.ML_POWERED_JS_QUERIES_PACK.packName },
],
"other",
],
];
for (const [packs, expectedStatus] of ML_POWERED_JS_STATUS_TESTS) {
const packDescriptions = `[${packs
.map((pack) => JSON.stringify(pack))
.join(", ")}]`;
test(`ML-powered JS queries status report is "${expectedStatus}" for packs = ${packDescriptions}`, (t) => {
return util.withTmpDir(async (tmpDir) => {
const config: Config = {
languages: [],
queries: {},
paths: [],
pathsIgnore: [],
originalUserInput: {},
tempDir: tmpDir,
toolCacheDir: tmpDir,
codeQLCmd: "",
gitHubVersion: {
type: util.GitHubVariant.DOTCOM,
} as util.GitHubVersion,
dbLocation: "",
packs: {
javascript: packs,
},
debugMode: false,
debugArtifactName: util.DEFAULT_DEBUG_ARTIFACT_NAME,
debugDatabaseName: util.DEFAULT_DEBUG_DATABASE_NAME,
};
t.is(util.getMlPoweredJsQueriesStatus(config), expectedStatus);
});
});
}

View file

@ -10,7 +10,7 @@ import * as semver from "semver";
import { getApiClient, GitHubApiDetails } from "./api-client"; import { getApiClient, GitHubApiDetails } from "./api-client";
import * as apiCompatibility from "./api-compatibility.json"; import * as apiCompatibility from "./api-compatibility.json";
import { CodeQL, CODEQL_VERSION_NEW_TRACING } from "./codeql"; import { CodeQL, CODEQL_VERSION_NEW_TRACING } from "./codeql";
import { Config } from "./config-utils"; import { Config, PackWithVersion } from "./config-utils";
import { Language } from "./languages"; import { Language } from "./languages";
import { Logger } from "./logging"; import { Logger } from "./logging";
@ -627,3 +627,61 @@ export function checkNotWindows11() {
); );
} }
} }
/**
* The ML-powered JS query pack to add to the analysis if a repo is opted into the ML-powered
* queries beta.
*/
export const ML_POWERED_JS_QUERIES_PACK: PackWithVersion = {
packName: "codeql/javascript-experimental-atm-queries",
version: "~0.0.2",
};
/**
* Get information about ML-powered JS queries to populate status reports with.
*
* This will be:
*
* - The version string if the analysis is using the ML-powered query pack that will be added to the
* analysis if the repo is opted into the ML-powered queries beta, i.e.
* {@link ML_POWERED_JS_QUERIES_PACK.version}. If the version string
* {@link ML_POWERED_JS_QUERIES_PACK.version} is undefined, then the status report string will be
* "latest", however this shouldn't occur in practice (see comment below).
* - "false" if the analysis won't run any ML-powered JS queries.
* - "other" in all other cases.
*
* Our goal of the status report here is to allow us to compare the occurrence of timeouts and other
* errors with ML-powered queries turned on and off. We also want to be able to compare minor
* version bumps caused by us bumping the version range of `ML_POWERED_JS_QUERIES_PACK` in a new
* version of the CodeQL Action. For instance, we might want to compare the `~0.1.0` and `~0.0.2`
* version strings.
*
* We restrict the set of strings we report here by excluding other version strings and combinations
* of version strings. We do this to limit the cardinality of the ML-powered JS queries status
* report field, since some platforms that ingest this status report bill based on the cardinality
* of its fields.
*
* This function lives here rather than in `init-action.ts` so it's easier to test, since tests for
* `init-action.ts` would each need to live in their own file. See `analyze-action-env.ts` for an
* explanation as to why this is.
*/
export function getMlPoweredJsQueriesStatus(config: Config): string {
const mlPoweredJsQueryPacks = (config.packs.javascript || []).filter(
(pack) => pack.packName === ML_POWERED_JS_QUERIES_PACK.packName
);
if (mlPoweredJsQueryPacks.length === 0) {
return "false";
}
const firstVersionString = mlPoweredJsQueryPacks[0].version;
if (
mlPoweredJsQueryPacks.length === 1 &&
ML_POWERED_JS_QUERIES_PACK.version === firstVersionString
) {
// We should always specify an explicit version string in `ML_POWERED_JS_QUERIES_PACK`,
// otherwise we won't be able to make changes to the pack unless those changes are compatible
// with each version of the CodeQL Action. Therefore in practice, we should never hit the
// `latest` case here.
return ML_POWERED_JS_QUERIES_PACK.version || "latest";
}
return "other";
}