Address review

This commit is contained in:
Paolo Tranquilli
2025-08-07 15:43:56 +02:00
parent 1cfc0c2621
commit bb56324516
12 changed files with 155 additions and 147 deletions

2
lib/actions-util.js generated
View File

@@ -264,7 +264,7 @@ function prettyPrintInvocation(cmd, args) {
* An error from a tool invocation, with associated exit code, stderr, etc.
*/
class CommandInvocationError extends Error {
constructor(cmd, args, exitCode, stderr, stdout) {
constructor(cmd, args, exitCode, stderr, stdout = "") {
const prettyCommand = prettyPrintInvocation(cmd, args);
const lastLine = ensureEndsInPeriod(stderr.trim().split("\n").pop()?.trim() || "n/a");
super(`Failed to run "${prettyCommand}". ` +

File diff suppressed because one or more lines are too long

35
lib/cli-errors.js generated
View File

@@ -5,6 +5,12 @@ exports.wrapCliConfigurationError = wrapCliConfigurationError;
const actions_util_1 = require("./actions-util");
const doc_url_1 = require("./doc-url");
const util_1 = require("./util");
const SUPPORTED_PLATFORMS = [
["linux", "x64"],
["win32", "x64"],
["darwin", "x64"],
["darwin", "arm64"],
];
/**
* An error from a CodeQL CLI invocation, with associated exit code, stderr, etc.
*/
@@ -272,22 +278,18 @@ function getCliConfigCategoryIfExists(cliError) {
}
/**
* Check if we are running on an unsupported platform/architecture combination.
* If so, return a ConfigurationError with a message that explains that, mentioning
* the underlying `cliError`. Otherwise, reutrn `undefined`.
*/
function isUnsupportedPlatform() {
return !SUPPORTED_PLATFORMS.some(([platform, arch]) => platform === process.platform && arch === process.arch);
}
/**
* Transform a CLI error into a ConfigurationError for an unsupported platform.
*/
function getUnsupportedPlatformError(cliError) {
if (![
["linux", "x64"],
["win32", "x64"],
["darwin", "x64"],
["darwin", "arm64"],
].some(([platform, arch]) => platform === process.platform && arch === process.arch)) {
return new util_1.ConfigurationError("The CodeQL CLI does not support the platform/architecture combination of " +
`${process.platform}/${process.arch} ` +
"(see https://codeql.github.com/docs/codeql-overview/system-requirements). " +
`The underlying error was: ${cliError.message}`);
}
return undefined;
return new util_1.ConfigurationError("The CodeQL CLI does not support the platform/architecture combination of " +
`${process.platform}/${process.arch} ` +
`(see ${doc_url_1.DocUrl.SYSTEM_REQUIREMENTS}). ` +
`The underlying error was: ${cliError.message}`);
}
/**
* Changes an error received from the CLI to a ConfigurationError with the message
@@ -295,9 +297,8 @@ function getUnsupportedPlatformError(cliError) {
* simply returns the original error.
*/
function wrapCliConfigurationError(cliError) {
const unsupportedPlatformError = getUnsupportedPlatformError(cliError);
if (unsupportedPlatformError !== undefined) {
return unsupportedPlatformError;
if (isUnsupportedPlatform()) {
return getUnsupportedPlatformError(cliError);
}
const cliConfigErrorCategory = getCliConfigCategoryIfExists(cliError);
if (cliConfigErrorCategory === undefined) {

File diff suppressed because one or more lines are too long

110
lib/cli-errors.test.js generated
View File

@@ -1,20 +1,50 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const ava_1 = __importDefault(require("ava"));
const sinon = __importStar(require("sinon"));
const actions_util_1 = require("./actions-util");
const cli_errors_1 = require("./cli-errors");
const testing_utils_1 = require("./testing-utils");
const util_1 = require("./util");
(0, testing_utils_1.setupTests)(ava_1.default);
// Helper function to create CommandInvocationError for testing
function createCommandInvocationError(cmd, args, exitCode, stderr, stdout = "") {
return new actions_util_1.CommandInvocationError(cmd, args, exitCode, stderr, stdout);
}
(0, ava_1.default)("CliError constructor with fatal errors", (t) => {
const commandError = createCommandInvocationError("codeql", ["database", "finalize"], 32, "Running TRAP import for CodeQL database...\nA fatal error occurred: Evaluator heap must be at least 384.00 MiB\nA fatal error occurred: Dataset import failed with code 2");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["database", "finalize"], 32, "Running TRAP import for CodeQL database...\nA fatal error occurred: Evaluator heap must be at least 384.00 MiB\nA fatal error occurred: Dataset import failed with code 2");
const cliError = new cli_errors_1.CliError(commandError);
t.is(cliError.exitCode, 32);
t.is(cliError.stderr, "Running TRAP import for CodeQL database...\nA fatal error occurred: Evaluator heap must be at least 384.00 MiB\nA fatal error occurred: Dataset import failed with code 2");
@@ -22,14 +52,14 @@ function createCommandInvocationError(cmd, args, exitCode, stderr, stdout = "")
t.true(cliError.message.includes("Context: A fatal error occurred: Evaluator heap must be at least 384.00 MiB."));
});
(0, ava_1.default)("CliError constructor with single fatal error", (t) => {
const commandError = createCommandInvocationError("codeql", ["database", "create"], 1, "A fatal error occurred: Out of memory");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["database", "create"], 1, "A fatal error occurred: Out of memory");
const cliError = new cli_errors_1.CliError(commandError);
t.is(cliError.exitCode, 1);
t.true(cliError.message.includes("A fatal error occurred: Out of memory"));
t.false(cliError.message.includes("Context:"));
});
(0, ava_1.default)("CliError constructor with autobuild errors", (t) => {
const commandError = createCommandInvocationError("codeql", ["database", "create"], 1, "[autobuild] [ERROR] Build failed\n[autobuild] [ERROR] Compilation error");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["database", "create"], 1, "[autobuild] [ERROR] Build failed\n[autobuild] [ERROR] Compilation error");
const cliError = new cli_errors_1.CliError(commandError);
t.is(cliError.exitCode, 1);
t.true(cliError.message.includes("We were unable to automatically build your code"));
@@ -37,7 +67,7 @@ function createCommandInvocationError(cmd, args, exitCode, stderr, stdout = "")
});
(0, ava_1.default)("CliError constructor with truncated autobuild errors", (t) => {
const stderr = Array.from({ length: 12 }, (_, i) => `[autobuild] [ERROR] Error ${i + 1}`).join("\n");
const commandError = createCommandInvocationError("codeql", ["database", "create"], 1, stderr);
const commandError = new actions_util_1.CommandInvocationError("codeql", ["database", "create"], 1, stderr);
const cliError = new cli_errors_1.CliError(commandError);
t.true(cliError.message.includes("(truncated)"));
// Should only include first 10 errors plus truncation message
@@ -47,121 +77,117 @@ function createCommandInvocationError(cmd, args, exitCode, stderr, stdout = "")
t.is(errorLines.length, 11); // 10 errors + "(truncated)"
});
(0, ava_1.default)("CliError constructor with generic error", (t) => {
const commandError = createCommandInvocationError("codeql", ["version"], 1, "Some generic error message\nLast line of error");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["version"], 1, "Some generic error message\nLast line of error");
const cliError = new cli_errors_1.CliError(commandError);
t.is(cliError.exitCode, 1);
t.true(cliError.message.includes('Encountered a fatal error while running "codeql version"'));
t.true(cliError.message.includes("Exit code was 1 and last log line was: Last line of error."));
});
(0, ava_1.default)("CliError constructor with empty stderr", (t) => {
const commandError = createCommandInvocationError("codeql", ["version"], 1, "");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["version"], 1, "");
const cliError = new cli_errors_1.CliError(commandError);
t.true(cliError.message.includes("last log line was: n/a"));
});
(0, ava_1.default)("wrapCliConfigurationError - unsupported platform", (t) => {
const originalPlatform = process.platform;
const originalArch = process.arch;
try {
// Mock unsupported platform/arch
Object.defineProperty(process, "platform", { value: "unsupported" });
Object.defineProperty(process, "arch", { value: "unsupported" });
const commandError = createCommandInvocationError("codeql", ["version"], 1, "Some error");
for (const [platform, arch] of [
["weird_plat", "x64"],
["linux", "arm64"],
["win32", "arm64"],
]) {
(0, ava_1.default)(`wrapCliConfigurationError - ${platform}/${arch} unsupported`, (t) => {
sinon.stub(process, "platform").value(platform);
sinon.stub(process, "arch").value(arch);
const commandError = new actions_util_1.CommandInvocationError("codeql", ["version"], 1, "Some error");
const cliError = new cli_errors_1.CliError(commandError);
const wrappedError = (0, cli_errors_1.wrapCliConfigurationError)(cliError);
t.true(wrappedError instanceof util_1.ConfigurationError);
t.true(wrappedError.message.includes("CodeQL CLI does not support the platform/architecture combination"));
t.true(wrappedError.message.includes("unsupported/unsupported"));
}
finally {
// Restore original values
Object.defineProperty(process, "platform", { value: originalPlatform });
Object.defineProperty(process, "arch", { value: originalArch });
}
});
t.true(wrappedError.message.includes(`${platform}/${arch}`));
});
}
(0, ava_1.default)("wrapCliConfigurationError - supported platform", (t) => {
const commandError = createCommandInvocationError("codeql", ["version"], 1, "Some error");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["version"], 1, "Some error");
const cliError = new cli_errors_1.CliError(commandError);
const wrappedError = (0, cli_errors_1.wrapCliConfigurationError)(cliError);
// Should return the original error since platform is supported
t.is(wrappedError, cliError);
});
(0, ava_1.default)("wrapCliConfigurationError - autobuild error", (t) => {
const commandError = createCommandInvocationError("codeql", ["database", "create"], 1, "We were unable to automatically build your code");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["database", "create"], 1, "We were unable to automatically build your code");
const cliError = new cli_errors_1.CliError(commandError);
const wrappedError = (0, cli_errors_1.wrapCliConfigurationError)(cliError);
t.true(wrappedError instanceof util_1.ConfigurationError);
t.true(wrappedError.message.includes("We were unable to automatically build your code"));
});
(0, ava_1.default)("wrapCliConfigurationError - init called twice", (t) => {
const commandError = createCommandInvocationError("codeql", ["database", "create"], 1, "Refusing to create databases /some/path but could not process any of it");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["database", "create"], 1, "Refusing to create databases /some/path but could not process any of it");
const cliError = new cli_errors_1.CliError(commandError);
const wrappedError = (0, cli_errors_1.wrapCliConfigurationError)(cliError);
t.true(wrappedError instanceof util_1.ConfigurationError);
t.true(wrappedError.message.includes('Is the "init" action called twice in the same job?'));
});
(0, ava_1.default)("wrapCliConfigurationError - no source code seen by exit code", (t) => {
const commandError = createCommandInvocationError("codeql", ["database", "finalize"], 32, "Some other error message");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["database", "finalize"], 32, "Some other error message");
const cliError = new cli_errors_1.CliError(commandError);
const wrappedError = (0, cli_errors_1.wrapCliConfigurationError)(cliError);
t.true(wrappedError instanceof util_1.ConfigurationError);
});
(0, ava_1.default)("wrapCliConfigurationError - no source code seen by message", (t) => {
const commandError = createCommandInvocationError("codeql", ["database", "finalize"], 1, "CodeQL detected code written in JavaScript but could not process any of it");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["database", "finalize"], 1, "CodeQL detected code written in JavaScript but could not process any of it");
const cliError = new cli_errors_1.CliError(commandError);
const wrappedError = (0, cli_errors_1.wrapCliConfigurationError)(cliError);
t.true(wrappedError instanceof util_1.ConfigurationError);
});
(0, ava_1.default)("wrapCliConfigurationError - out of memory error with additional message", (t) => {
const commandError = createCommandInvocationError("codeql", ["database", "analyze"], 1, "CodeQL is out of memory.");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["database", "analyze"], 1, "CodeQL is out of memory.");
const cliError = new cli_errors_1.CliError(commandError);
const wrappedError = (0, cli_errors_1.wrapCliConfigurationError)(cliError);
t.true(wrappedError instanceof util_1.ConfigurationError);
t.true(wrappedError.message.includes("For more information, see https://gh.io/troubleshooting-code-scanning/out-of-disk-or-memory"));
});
(0, ava_1.default)("wrapCliConfigurationError - gradle build failed", (t) => {
const commandError = createCommandInvocationError("codeql", ["database", "create"], 1, "[autobuild] FAILURE: Build failed with an exception.");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["database", "create"], 1, "[autobuild] FAILURE: Build failed with an exception.");
const cliError = new cli_errors_1.CliError(commandError);
const wrappedError = (0, cli_errors_1.wrapCliConfigurationError)(cliError);
t.true(wrappedError instanceof util_1.ConfigurationError);
});
(0, ava_1.default)("wrapCliConfigurationError - maven build failed", (t) => {
const commandError = createCommandInvocationError("codeql", ["database", "create"], 1, "[autobuild] [ERROR] Failed to execute goal");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["database", "create"], 1, "[autobuild] [ERROR] Failed to execute goal");
const cliError = new cli_errors_1.CliError(commandError);
const wrappedError = (0, cli_errors_1.wrapCliConfigurationError)(cliError);
t.true(wrappedError instanceof util_1.ConfigurationError);
});
(0, ava_1.default)("wrapCliConfigurationError - swift build failed", (t) => {
const commandError = createCommandInvocationError("codeql", ["database", "create"], 1, "[autobuilder/build] [build-command-failed] `autobuild` failed to run the build command");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["database", "create"], 1, "[autobuilder/build] [build-command-failed] `autobuild` failed to run the build command");
const cliError = new cli_errors_1.CliError(commandError);
const wrappedError = (0, cli_errors_1.wrapCliConfigurationError)(cliError);
t.true(wrappedError instanceof util_1.ConfigurationError);
});
(0, ava_1.default)("wrapCliConfigurationError - pack cannot be found", (t) => {
const commandError = createCommandInvocationError("codeql", ["pack", "install"], 1, "Query pack my-pack cannot be found. Check the spelling of the pack.");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["pack", "install"], 1, "Query pack my-pack cannot be found. Check the spelling of the pack.");
const cliError = new cli_errors_1.CliError(commandError);
const wrappedError = (0, cli_errors_1.wrapCliConfigurationError)(cliError);
t.true(wrappedError instanceof util_1.ConfigurationError);
});
(0, ava_1.default)("wrapCliConfigurationError - pack missing auth", (t) => {
const commandError = createCommandInvocationError("codeql", ["pack", "download"], 1, "GitHub Container registry returned 403 Forbidden");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["pack", "download"], 1, "GitHub Container registry returned 403 Forbidden");
const cliError = new cli_errors_1.CliError(commandError);
const wrappedError = (0, cli_errors_1.wrapCliConfigurationError)(cliError);
t.true(wrappedError instanceof util_1.ConfigurationError);
});
(0, ava_1.default)("wrapCliConfigurationError - invalid config file", (t) => {
const commandError = createCommandInvocationError("codeql", ["database", "create"], 1, "Config file .codeql/config.yml is not valid");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["database", "create"], 1, "Config file .codeql/config.yml is not valid");
const cliError = new cli_errors_1.CliError(commandError);
const wrappedError = (0, cli_errors_1.wrapCliConfigurationError)(cliError);
t.true(wrappedError instanceof util_1.ConfigurationError);
});
(0, ava_1.default)("wrapCliConfigurationError - incompatible CLI version", (t) => {
const commandError = createCommandInvocationError("codeql", ["version"], 1, "is not compatible with this CodeQL CLI");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["version"], 1, "is not compatible with this CodeQL CLI");
const cliError = new cli_errors_1.CliError(commandError);
const wrappedError = (0, cli_errors_1.wrapCliConfigurationError)(cliError);
t.true(wrappedError instanceof util_1.ConfigurationError);
});
(0, ava_1.default)("wrapCliConfigurationError - unknown error remains unchanged", (t) => {
const commandError = createCommandInvocationError("codeql", ["version"], 1, "Some unknown error that doesn't match any patterns");
const commandError = new actions_util_1.CommandInvocationError("codeql", ["version"], 1, "Some unknown error that doesn't match any patterns");
const cliError = new cli_errors_1.CliError(commandError);
const wrappedError = (0, cli_errors_1.wrapCliConfigurationError)(cliError);
// Should return the original CliError since it doesn't match any known patterns
@@ -180,11 +206,11 @@ function createCommandInvocationError(cmd, args, exitCode, stderr, stdout = "")
switch (category) {
case cli_errors_1.CliConfigErrorCategory.NoSourceCodeSeen:
// This category matches by exit code
testError = new cli_errors_1.CliError(createCommandInvocationError("codeql", [], 32, "some error"));
testError = new cli_errors_1.CliError(new actions_util_1.CommandInvocationError("codeql", [], 32, "some error"));
break;
default:
// For other categories, we'll test with a generic message that should not match
testError = new cli_errors_1.CliError(createCommandInvocationError("codeql", [], 1, "generic error"));
testError = new cli_errors_1.CliError(new actions_util_1.CommandInvocationError("codeql", [], 1, "generic error"));
break;
}
// The test should not throw an error when processing

File diff suppressed because one or more lines are too long

1
lib/doc-url.js generated
View File

@@ -13,5 +13,6 @@ var DocUrl;
DocUrl["SPECIFY_BUILD_STEPS_MANUALLY"] = "https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#about-specifying-build-steps-manually";
DocUrl["TRACK_CODE_SCANNING_ALERTS_ACROSS_RUNS"] = "https://docs.github.com/en/enterprise-cloud@latest/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning#providing-data-to-track-code-scanning-alerts-across-runs";
DocUrl["CODEQL_BUILD_MODES"] = "https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#codeql-build-modes";
DocUrl["SYSTEM_REQUIREMENTS"] = "https://codeql.github.com/docs/codeql-overview/system-requirements/";
})(DocUrl || (exports.DocUrl = DocUrl = {}));
//# sourceMappingURL=doc-url.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"doc-url.js","sourceRoot":"","sources":["../src/doc-url.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,IAAY,MAQX;AARD,WAAY,MAAM;IAChB,uHAA6G,CAAA;IAC7G,gJAAsI,CAAA;IACtI,yJAA+I,CAAA;IAC/I,qMAA2L,CAAA;IAC3L,gOAAsN,CAAA;IACtN,2PAAiP,CAAA;IACjP,mMAAyL,CAAA;AAC3L,CAAC,EARW,MAAM,sBAAN,MAAM,QAQjB"}
{"version":3,"file":"doc-url.js","sourceRoot":"","sources":["../src/doc-url.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,IAAY,MASX;AATD,WAAY,MAAM;IAChB,uHAA6G,CAAA;IAC7G,gJAAsI,CAAA;IACtI,yJAA+I,CAAA;IAC/I,qMAA2L,CAAA;IAC3L,gOAAsN,CAAA;IACtN,2PAAiP,CAAA;IACjP,mMAAyL,CAAA;IACzL,qGAA2F,CAAA;AAC7F,CAAC,EATW,MAAM,sBAAN,MAAM,QASjB"}

View File

@@ -264,7 +264,7 @@ export class CommandInvocationError extends Error {
public args: string[],
public exitCode: number | undefined,
public stderr: string,
public stdout: string,
public stdout: string = "",
) {
const prettyCommand = prettyPrintInvocation(cmd, args);
const lastLine = ensureEndsInPeriod(

View File

@@ -1,4 +1,5 @@
import test from "ava";
import * as sinon from "sinon";
import { CommandInvocationError } from "./actions-util";
import {
@@ -11,19 +12,8 @@ import { ConfigurationError } from "./util";
setupTests(test);
// Helper function to create CommandInvocationError for testing
function createCommandInvocationError(
cmd: string,
args: string[],
exitCode: number | undefined,
stderr: string,
stdout: string = "",
): CommandInvocationError {
return new CommandInvocationError(cmd, args, exitCode, stderr, stdout);
}
test("CliError constructor with fatal errors", (t) => {
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["database", "finalize"],
32,
@@ -50,7 +40,7 @@ test("CliError constructor with fatal errors", (t) => {
});
test("CliError constructor with single fatal error", (t) => {
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["database", "create"],
1,
@@ -65,7 +55,7 @@ test("CliError constructor with single fatal error", (t) => {
});
test("CliError constructor with autobuild errors", (t) => {
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["database", "create"],
1,
@@ -88,7 +78,7 @@ test("CliError constructor with truncated autobuild errors", (t) => {
{ length: 12 },
(_, i) => `[autobuild] [ERROR] Error ${i + 1}`,
).join("\n");
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["database", "create"],
1,
@@ -106,7 +96,7 @@ test("CliError constructor with truncated autobuild errors", (t) => {
});
test("CliError constructor with generic error", (t) => {
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["version"],
1,
@@ -129,28 +119,22 @@ test("CliError constructor with generic error", (t) => {
});
test("CliError constructor with empty stderr", (t) => {
const commandError = createCommandInvocationError(
"codeql",
["version"],
1,
"",
);
const commandError = new CommandInvocationError("codeql", ["version"], 1, "");
const cliError = new CliError(commandError);
t.true(cliError.message.includes("last log line was: n/a"));
});
test("wrapCliConfigurationError - unsupported platform", (t) => {
const originalPlatform = process.platform;
const originalArch = process.arch;
try {
// Mock unsupported platform/arch
Object.defineProperty(process, "platform", { value: "unsupported" });
Object.defineProperty(process, "arch", { value: "unsupported" });
const commandError = createCommandInvocationError(
for (const [platform, arch] of [
["weird_plat", "x64"],
["linux", "arm64"],
["win32", "arm64"],
]) {
test(`wrapCliConfigurationError - ${platform}/${arch} unsupported`, (t) => {
sinon.stub(process, "platform").value(platform);
sinon.stub(process, "arch").value(arch);
const commandError = new CommandInvocationError(
"codeql",
["version"],
1,
@@ -166,16 +150,12 @@ test("wrapCliConfigurationError - unsupported platform", (t) => {
"CodeQL CLI does not support the platform/architecture combination",
),
);
t.true(wrappedError.message.includes("unsupported/unsupported"));
} finally {
// Restore original values
Object.defineProperty(process, "platform", { value: originalPlatform });
Object.defineProperty(process, "arch", { value: originalArch });
}
});
t.true(wrappedError.message.includes(`${platform}/${arch}`));
});
}
test("wrapCliConfigurationError - supported platform", (t) => {
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["version"],
1,
@@ -190,7 +170,7 @@ test("wrapCliConfigurationError - supported platform", (t) => {
});
test("wrapCliConfigurationError - autobuild error", (t) => {
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["database", "create"],
1,
@@ -209,7 +189,7 @@ test("wrapCliConfigurationError - autobuild error", (t) => {
});
test("wrapCliConfigurationError - init called twice", (t) => {
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["database", "create"],
1,
@@ -228,7 +208,7 @@ test("wrapCliConfigurationError - init called twice", (t) => {
});
test("wrapCliConfigurationError - no source code seen by exit code", (t) => {
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["database", "finalize"],
32,
@@ -242,7 +222,7 @@ test("wrapCliConfigurationError - no source code seen by exit code", (t) => {
});
test("wrapCliConfigurationError - no source code seen by message", (t) => {
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["database", "finalize"],
1,
@@ -256,7 +236,7 @@ test("wrapCliConfigurationError - no source code seen by message", (t) => {
});
test("wrapCliConfigurationError - out of memory error with additional message", (t) => {
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["database", "analyze"],
1,
@@ -275,7 +255,7 @@ test("wrapCliConfigurationError - out of memory error with additional message",
});
test("wrapCliConfigurationError - gradle build failed", (t) => {
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["database", "create"],
1,
@@ -289,7 +269,7 @@ test("wrapCliConfigurationError - gradle build failed", (t) => {
});
test("wrapCliConfigurationError - maven build failed", (t) => {
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["database", "create"],
1,
@@ -303,7 +283,7 @@ test("wrapCliConfigurationError - maven build failed", (t) => {
});
test("wrapCliConfigurationError - swift build failed", (t) => {
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["database", "create"],
1,
@@ -317,7 +297,7 @@ test("wrapCliConfigurationError - swift build failed", (t) => {
});
test("wrapCliConfigurationError - pack cannot be found", (t) => {
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["pack", "install"],
1,
@@ -331,7 +311,7 @@ test("wrapCliConfigurationError - pack cannot be found", (t) => {
});
test("wrapCliConfigurationError - pack missing auth", (t) => {
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["pack", "download"],
1,
@@ -345,7 +325,7 @@ test("wrapCliConfigurationError - pack missing auth", (t) => {
});
test("wrapCliConfigurationError - invalid config file", (t) => {
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["database", "create"],
1,
@@ -359,7 +339,7 @@ test("wrapCliConfigurationError - invalid config file", (t) => {
});
test("wrapCliConfigurationError - incompatible CLI version", (t) => {
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["version"],
1,
@@ -373,7 +353,7 @@ test("wrapCliConfigurationError - incompatible CLI version", (t) => {
});
test("wrapCliConfigurationError - unknown error remains unchanged", (t) => {
const commandError = createCommandInvocationError(
const commandError = new CommandInvocationError(
"codeql",
["version"],
1,
@@ -404,13 +384,13 @@ test("all CLI config error categories have valid configurations", (t) => {
case CliConfigErrorCategory.NoSourceCodeSeen:
// This category matches by exit code
testError = new CliError(
createCommandInvocationError("codeql", [], 32, "some error"),
new CommandInvocationError("codeql", [], 32, "some error"),
);
break;
default:
// For other categories, we'll test with a generic message that should not match
testError = new CliError(
createCommandInvocationError("codeql", [], 1, "generic error"),
new CommandInvocationError("codeql", [], 1, "generic error"),
);
break;
}

View File

@@ -6,6 +6,13 @@ import {
import { DocUrl } from "./doc-url";
import { ConfigurationError } from "./util";
const SUPPORTED_PLATFORMS = [
["linux", "x64"],
["win32", "x64"],
["darwin", "x64"],
["darwin", "arm64"],
];
/**
* An error from a CodeQL CLI invocation, with associated exit code, stderr, etc.
*/
@@ -318,31 +325,24 @@ function getCliConfigCategoryIfExists(
/**
* Check if we are running on an unsupported platform/architecture combination.
* If so, return a ConfigurationError with a message that explains that, mentioning
* the underlying `cliError`. Otherwise, reutrn `undefined`.
*/
function getUnsupportedPlatformError(
cliError: CliError,
): ConfigurationError | undefined {
if (
![
["linux", "x64"],
["win32", "x64"],
["darwin", "x64"],
["darwin", "arm64"],
].some(
([platform, arch]) =>
platform === process.platform && arch === process.arch,
)
) {
return new ConfigurationError(
"The CodeQL CLI does not support the platform/architecture combination of " +
`${process.platform}/${process.arch} ` +
"(see https://codeql.github.com/docs/codeql-overview/system-requirements). " +
`The underlying error was: ${cliError.message}`,
);
}
return undefined;
function isUnsupportedPlatform(): boolean {
return !SUPPORTED_PLATFORMS.some(
([platform, arch]) =>
platform === process.platform && arch === process.arch,
);
}
/**
* Transform a CLI error into a ConfigurationError for an unsupported platform.
*/
function getUnsupportedPlatformError(cliError: CliError): ConfigurationError {
return new ConfigurationError(
"The CodeQL CLI does not support the platform/architecture combination of " +
`${process.platform}/${process.arch} ` +
`(see ${DocUrl.SYSTEM_REQUIREMENTS}). ` +
`The underlying error was: ${cliError.message}`,
);
}
/**
@@ -351,9 +351,8 @@ function getUnsupportedPlatformError(
* simply returns the original error.
*/
export function wrapCliConfigurationError(cliError: CliError): Error {
const unsupportedPlatformError = getUnsupportedPlatformError(cliError);
if (unsupportedPlatformError !== undefined) {
return unsupportedPlatformError;
if (isUnsupportedPlatform()) {
return getUnsupportedPlatformError(cliError);
}
const cliConfigErrorCategory = getCliConfigCategoryIfExists(cliError);

View File

@@ -10,4 +10,5 @@ export enum DocUrl {
SPECIFY_BUILD_STEPS_MANUALLY = "https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#about-specifying-build-steps-manually",
TRACK_CODE_SCANNING_ALERTS_ACROSS_RUNS = "https://docs.github.com/en/enterprise-cloud@latest/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning#providing-data-to-track-code-scanning-alerts-across-runs",
CODEQL_BUILD_MODES = "https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#codeql-build-modes",
SYSTEM_REQUIREMENTS = "https://codeql.github.com/docs/codeql-overview/system-requirements/",
}