Compare commits

...
Author SHA1 Message Date
Michael B. Gale 5c1005e0ae Merge branch 'main' into mbg/refactor-util/errors 2026-10-21 16:58:03 +01:00
Michael B. Gale c29909a87f Improve typing of resolveFunction 2026-10-21 16:57:16 +01:00
Michael B. Gale 44f1c73c56 Fix resolveFunction call 2026-10-21 16:57:16 +01:00
Michael B. Gale 7def52843a Move initializeEnvironment out of util.ts 2026-10-21 16:57:16 +01:00
Michael B. Gale 774bc191bf Remove unused type parameters from Env classes 2026-10-21 16:57:15 +01:00
Henry Mercer c5a2f4b0fe Merge pull request #4245 from github/henrymercer/graduate-overlay-trap-caching
Graduate overlay TRAP caching defaults
2026-10-20 17:45:59 +00:00
Mario Campos 61a5a80dd9 Merge pull request #4256 from github/update-bundle/codeql-bundle-v2.27.3
Update default bundle to 2.27.3
2026-10-20 17:41:23 +00:00
Michael B. Gale 3dd33f8b69 Merge pull request #4249 from github/mbg/upload-improvements-for-4223
Failed SARIF testing and logging improvements
2026-10-20 17:35:13 +00:00
Michael B. Gale b96e3390db Change comment for getConfig call in upload-sarif 2026-10-20 18:07:32 +01:00
Michael B. Gale 7fa45180db Use shouldSkipSarifUpload in analyze-action.ts 2026-10-20 18:06:24 +01:00
Michael B. Gale a69c7cb332 Document that setting the env vars to false takes precedence 2026-10-20 18:02:30 +01:00
Michael B. Gale 74ddcd9f65 Fix typo in comment 2026-10-20 17:59:12 +01:00
github-actions[bot] 260a53409e Add changelog note 2026-10-20 16:53:41 +00:00
github-actions[bot] 72cb698832 Update default bundle to codeql-bundle-v2.27.3 2026-10-20 16:53:32 +00:00
Michael B. Gale 950b1479a1 Ensure that rootDirectory is suitable for sarifFile in uploadSarifArtifact 2026-10-20 16:07:25 +00:00
Michael B. Gale 5b69b28796 Improve logging in uploadSarifArtifact 2026-10-20 16:07:25 +00:00
Michael B. Gale 1d373e07cd Upload failed SARIF as workflow artifact in test mode 2026-10-20 16:07:25 +00:00
Michael B. Gale e7340eea1b Skip waiting for SARIF if nothing was uploaded 2026-10-20 16:07:25 +00:00
Michael B. Gale 02fb8cc38a Propagate Config to combineSarifFilesUsingCLI 2026-10-20 16:07:25 +00:00
Michael B. Gale 6e9aec682d Add and use shouldSkipGenerateFailedSarif 2026-10-20 16:07:25 +00:00
Michael B. Gale a9cd2f9fa7 Allow to explicitly not skip the SARIF upload 2026-10-20 16:07:25 +00:00
Michael B. Gale be1223f63e Log when we didn't get a normal configuration file 2026-10-20 16:07:25 +00:00
Michael B. Gale dc2ed81cc7 Remove InstanceURL from util.ts 2026-10-16 22:04:05 +01:00
Michael B. Gale 02283e9542 Move more GitHub-related definitions from util.ts to github.ts 2026-10-16 21:54:02 +01:00
Michael B. Gale 86bc4448d3 Mark additional imports in util.ts as type-only 2026-10-16 21:52:19 +01:00
Michael B. Gale 9c72af5b2b Move codeQlVersionAtLeast out of util.ts and into CodeQL 2026-10-16 21:50:31 +01:00
Michael B. Gale 929f5c0db4 Move isDiskConfigurationError out of codeql.ts 2026-10-16 21:50:09 +01:00
Michael B. Gale a76419a632 Move wrapError and getErrorMessage out of util.ts 2026-10-16 21:46:16 +01:00
Michael B. Gale 071544a67a Move HTTPError out of util.ts 2026-10-16 21:40:48 +01:00
Michael B. Gale 8bdea824e2 Move ConfigurationError out of util.ts 2026-10-16 21:39:54 +01:00
Henry MercerandCopilot App e344c793ad Document TRAP caching default with improved incremental analysis
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-10-16 15:28:39 +01:00
Henry MercerandCopilot App e038b67f1c Graduate overlay TRAP caching defaults
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-10-16 14:14:00 +01:00
36 changed files with 689 additions and 481 deletions

No files matched your search

+1 -1
View File
@@ -4,7 +4,7 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th
## [UNRELEASED]
No user facing changes.
- Update default CodeQL bundle version to [2.27.3](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.3). [#4256](https://github.com/github/codeql-action/pull/4256)
## 4.39.0 - 15 Oct 2026
+4 -1
View File
@@ -153,7 +153,10 @@ inputs:
required: false
trap-caching:
description: >-
Explicitly enable or disable TRAP caching rather than respecting the feature flag for it.
Explicitly enable or disable TRAP caching instead of using the automatically determined default.
TRAP caching is disabled by default when improved incremental analysis is enabled,
because improved incremental analysis of a pull request only extracts changed files,
which rarely benefit from TRAP caching.
required: false
dependency-caching:
description: >-
+4 -4
View File
@@ -1,6 +1,6 @@
{
"bundleVersion": "codeql-bundle-v2.27.2",
"cliVersion": "2.27.2",
"priorBundleVersion": "codeql-bundle-v2.27.1",
"priorCliVersion": "2.27.1"
"bundleVersion": "codeql-bundle-v2.27.3",
"cliVersion": "2.27.3",
"priorBundleVersion": "codeql-bundle-v2.27.2",
"priorCliVersion": "2.27.2"
}
+222 -176
View File
@@ -34719,7 +34719,7 @@ var require_cacheUtils = __commonJS({
var crypto3 = __importStar2(require("crypto"));
var fs32 = __importStar2(require("fs"));
var path30 = __importStar2(require("path"));
var semver11 = __importStar2(require_semver3());
var semver12 = __importStar2(require_semver3());
var util4 = __importStar2(require("util"));
var constants_1 = require_constants7();
var versionSalt = "1.0";
@@ -34812,7 +34812,7 @@ var require_cacheUtils = __commonJS({
function getCompressionMethod() {
return __awaiter2(this, void 0, void 0, function* () {
const versionOutput = yield getVersion("zstd", ["--quiet"]);
const version = semver11.clean(versionOutput);
const version = semver12.clean(versionOutput);
core29.debug(`zstd version: ${version}`);
if (versionOutput === "") {
return constants_1.CompressionMethod.Gzip;
@@ -42967,11 +42967,11 @@ var require_tracingPolicy = __commonJS({
var import_log = require_log3();
var import_core_util = require_commonjs4();
var import_restError = require_restError3();
var import_util59 = require_internal3();
var import_util58 = require_internal3();
var tracingPolicyName2 = "tracingPolicy";
function tracingPolicy2(options = {}) {
const userAgentPromise = (0, import_userAgent.getUserAgentValue)(options.userAgentPrefix);
const sanitizer = new import_util59.Sanitizer({
const sanitizer = new import_util58.Sanitizer({
additionalAllowedQueryParameters: options.additionalAllowedQueryParameters
});
const tracingClient = tryCreateTracingClient();
@@ -46597,11 +46597,11 @@ var require_response2 = __commonJS({
});
module2.exports = __toCommonJS2(response_exports);
var import_core_rest_pipeline = require_commonjs6();
var import_util59 = require_util9();
var import_util58 = require_util9();
var originalResponse = /* @__PURE__ */ Symbol("Original FullOperationResponse");
function toCompatResponse2(response, options) {
let request3 = (0, import_util59.toWebResourceLike)(response.request);
let headers = (0, import_util59.toHttpHeadersLike)(response.headers);
let request3 = (0, import_util58.toWebResourceLike)(response.request);
let headers = (0, import_util58.toHttpHeadersLike)(response.headers);
if (options?.createProxy) {
return new Proxy(response, {
get(target, prop, receiver) {
@@ -46642,7 +46642,7 @@ var require_response2 = __commonJS({
return {
...compatResponse,
headers,
request: (0, import_util59.toPipelineRequest)(compatResponse.request)
request: (0, import_util58.toPipelineRequest)(compatResponse.request)
};
}
}
@@ -46749,7 +46749,7 @@ var require_requestPolicyFactoryPolicy = __commonJS({
requestPolicyFactoryPolicyName: () => requestPolicyFactoryPolicyName2
});
module2.exports = __toCommonJS2(requestPolicyFactoryPolicy_exports);
var import_util59 = require_util9();
var import_util58 = require_util9();
var import_response = require_response2();
var HttpPipelineLogLevel2 = /* @__PURE__ */ ((HttpPipelineLogLevel22) => {
HttpPipelineLogLevel22[HttpPipelineLogLevel22["ERROR"] = 1] = "ERROR";
@@ -46773,14 +46773,14 @@ var require_requestPolicyFactoryPolicy = __commonJS({
async sendRequest(request3, next) {
let httpPipeline = {
async sendRequest(httpRequest) {
const response2 = await next((0, import_util59.toPipelineRequest)(httpRequest));
const response2 = await next((0, import_util58.toPipelineRequest)(httpRequest));
return (0, import_response.toCompatResponse)(response2, { createProxy: true });
}
};
for (const factory of orderedFactories) {
httpPipeline = factory.create(httpPipeline, mockRequestPolicyOptions);
}
const webResourceLike = (0, import_util59.toWebResourceLike)(request3, { createProxy: true });
const webResourceLike = (0, import_util58.toWebResourceLike)(request3, { createProxy: true });
const response = await httpPipeline.sendRequest(webResourceLike);
return (0, import_response.toPipelineResponse)(response);
}
@@ -46815,12 +46815,12 @@ var require_httpClientAdapter = __commonJS({
});
module2.exports = __toCommonJS2(httpClientAdapter_exports);
var import_response = require_response2();
var import_util59 = require_util9();
var import_util58 = require_util9();
function convertHttpClient2(requestPolicyClient) {
return {
sendRequest: async (request3) => {
const response = await requestPolicyClient.sendRequest(
(0, import_util59.toWebResourceLike)(request3, { createProxy: true })
(0, import_util58.toWebResourceLike)(request3, { createProxy: true })
);
return (0, import_response.toPipelineResponse)(response);
}
@@ -46858,7 +46858,7 @@ var require_commonjs9 = __commonJS({
disableKeepAlivePolicyName: () => import_disableKeepAlivePolicy.disableKeepAlivePolicyName,
requestPolicyFactoryPolicyName: () => import_requestPolicyFactoryPolicy.requestPolicyFactoryPolicyName,
toCompatResponse: () => import_response.toCompatResponse,
toHttpHeadersLike: () => import_util59.toHttpHeadersLike
toHttpHeadersLike: () => import_util58.toHttpHeadersLike
});
module2.exports = __toCommonJS2(src_exports);
var import_extendedClient = require_extendedClient();
@@ -46866,7 +46866,7 @@ var require_commonjs9 = __commonJS({
var import_requestPolicyFactoryPolicy = require_requestPolicyFactoryPolicy();
var import_disableKeepAlivePolicy = require_disableKeepAlivePolicy();
var import_httpClientAdapter = require_httpClientAdapter();
var import_util59 = require_util9();
var import_util58 = require_util9();
}
});
@@ -106361,7 +106361,7 @@ var require_manifest = __commonJS({
exports2._findMatch = _findMatch;
exports2._getOsVersion = _getOsVersion;
exports2._readLinuxVersionFile = _readLinuxVersionFile;
var semver11 = __importStar2(require_semver2());
var semver12 = __importStar2(require_semver2());
var core_1 = require_core();
var os7 = require("os");
var cp = require("child_process");
@@ -106375,7 +106375,7 @@ var require_manifest = __commonJS({
for (const candidate of candidates) {
const version = candidate.version;
(0, core_1.debug)(`check ${version} satisfies ${versionSpec}`);
if (semver11.satisfies(version, versionSpec) && (!stable || candidate.stable === stable)) {
if (semver12.satisfies(version, versionSpec) && (!stable || candidate.stable === stable)) {
file = candidate.files.find((item) => {
(0, core_1.debug)(`${item.arch}===${archFilter} && ${item.platform}===${platFilter}`);
let chk = item.arch === archFilter && item.platform === platFilter;
@@ -106384,7 +106384,7 @@ var require_manifest = __commonJS({
if (osVersion === item.platform_version) {
chk = true;
} else {
chk = semver11.satisfies(osVersion, item.platform_version);
chk = semver12.satisfies(osVersion, item.platform_version);
}
}
return chk;
@@ -106644,7 +106644,7 @@ var require_tool_cache = __commonJS({
var os7 = __importStar2(require("os"));
var path30 = __importStar2(require("path"));
var httpm = __importStar2(require_lib());
var semver11 = __importStar2(require_semver2());
var semver12 = __importStar2(require_semver2());
var stream2 = __importStar2(require("stream"));
var util4 = __importStar2(require("util"));
var assert_1 = require("assert");
@@ -106917,7 +106917,7 @@ var require_tool_cache = __commonJS({
}
function cacheDir2(sourceDir, tool, version, arch2) {
return __awaiter2(this, void 0, void 0, function* () {
version = semver11.clean(version) || version;
version = semver12.clean(version) || version;
arch2 = arch2 || os7.arch();
core29.debug(`Caching tool ${tool} ${version} ${arch2}`);
core29.debug(`source dir: ${sourceDir}`);
@@ -106935,7 +106935,7 @@ var require_tool_cache = __commonJS({
}
function cacheFile(sourceFile, targetFile, tool, version, arch2) {
return __awaiter2(this, void 0, void 0, function* () {
version = semver11.clean(version) || version;
version = semver12.clean(version) || version;
arch2 = arch2 || os7.arch();
core29.debug(`Caching tool ${tool} ${version} ${arch2}`);
core29.debug(`source file: ${sourceFile}`);
@@ -106965,7 +106965,7 @@ var require_tool_cache = __commonJS({
}
let toolPath = "";
if (versionSpec) {
versionSpec = semver11.clean(versionSpec) || "";
versionSpec = semver12.clean(versionSpec) || "";
const cachePath = path30.join(_getCacheDirectory(), toolName, versionSpec, arch2);
core29.debug(`checking cache: ${cachePath}`);
if (fs32.existsSync(cachePath) && fs32.existsSync(`${cachePath}.complete`)) {
@@ -107045,7 +107045,7 @@ var require_tool_cache = __commonJS({
}
function _createToolPath(tool, version, arch2) {
return __awaiter2(this, void 0, void 0, function* () {
const folderPath = path30.join(_getCacheDirectory(), tool, semver11.clean(version) || version, arch2 || "");
const folderPath = path30.join(_getCacheDirectory(), tool, semver12.clean(version) || version, arch2 || "");
core29.debug(`destination ${folderPath}`);
const markerPath = `${folderPath}.complete`;
yield io9.rmRF(folderPath);
@@ -107055,15 +107055,15 @@ var require_tool_cache = __commonJS({
});
}
function _completeToolPath(tool, version, arch2) {
const folderPath = path30.join(_getCacheDirectory(), tool, semver11.clean(version) || version, arch2 || "");
const folderPath = path30.join(_getCacheDirectory(), tool, semver12.clean(version) || version, arch2 || "");
const markerPath = `${folderPath}.complete`;
fs32.writeFileSync(markerPath, "");
core29.debug("finished caching tool");
}
function isExplicitVersion(versionSpec) {
const c = semver11.clean(versionSpec) || "";
const c = semver12.clean(versionSpec) || "";
core29.debug(`isExplicit: ${c}`);
const valid4 = semver11.valid(c) != null;
const valid4 = semver12.valid(c) != null;
core29.debug(`explicit? ${valid4}`);
return valid4;
}
@@ -107071,14 +107071,14 @@ var require_tool_cache = __commonJS({
let version = "";
core29.debug(`evaluating ${versions.length} versions`);
versions = versions.sort((a, b) => {
if (semver11.gt(a, b)) {
if (semver12.gt(a, b)) {
return 1;
}
return -1;
});
for (let i = versions.length - 1; i >= 0; i--) {
const potential = versions[i];
const satisfied = semver11.satisfies(potential, versionSpec);
const satisfied = semver12.satisfies(potential, versionSpec);
if (satisfied) {
version = potential;
break;
@@ -166182,6 +166182,17 @@ var Env = class extends ReadOnlyEnv {
core.exportVariable(name, val);
}
}
/**
* Set some initial environment variables that we can set even without
* knowing what version of CodeQL we're running.
*/
initialise(version) {
this.export("CODEQL_ACTION_FEATURE_MULTI_LANGUAGE" /* FEATURE_MULTI_LANGUAGE */, "false");
this.export("CODEQL_ACTION_FEATURE_SANDWICH" /* FEATURE_SANDWICH */, "false");
this.export("CODEQL_ACTION_FEATURE_SARIF_COMBINE" /* FEATURE_SARIF_COMBINE */, "true");
this.export("CODEQL_ACTION_FEATURE_WILL_UPLOAD" /* FEATURE_WILL_UPLOAD */, "true");
this.export("CODEQL_ACTION_VERSION" /* VERSION */, version);
}
/** Gets a value indicating whether `set` was called at least once. */
hasChanged() {
return this.changed;
@@ -169555,6 +169566,82 @@ function checkSchema(schema, obj, options = {}, path30 = "") {
return result;
}
// src/errors/index.ts
function wrapError(error3) {
return error3 instanceof Error ? error3 : new Error(String(error3));
}
function getErrorMessage(error3) {
return error3 instanceof Error ? error3.message : String(error3);
}
function isDiskConfigurationError(e) {
if (!(e instanceof Error)) {
return false;
}
return (
// out of disk space
e.message.includes("ENOSPC") || // access denied
e.message.includes("EACCES")
);
}
var ConfigurationError = class extends Error {
};
var HTTPError = class extends Error {
status;
constructor(message, status) {
super(message);
this.status = status;
}
};
function asHTTPError(arg) {
if (!isObject2(arg) || !isString(arg.message)) {
return void 0;
}
if (Number.isInteger(arg.status)) {
return new HTTPError(arg.message, arg.status);
}
if (Number.isInteger(arg.httpStatusCode)) {
return new HTTPError(arg.message, arg.httpStatusCode);
}
return void 0;
}
// src/github.ts
var GITHUB_DOTCOM_URL = "https://github.com";
function parseGitHubUrl(inputUrl) {
const originalUrl = inputUrl;
if (inputUrl.indexOf("://") === -1) {
inputUrl = `https://${inputUrl}`;
}
if (!inputUrl.startsWith("http://") && !inputUrl.startsWith("https://")) {
throw new ConfigurationError(`"${originalUrl}" is not a http or https URL`);
}
let url2;
try {
url2 = new URL(inputUrl);
} catch {
throw new ConfigurationError(`"${originalUrl}" is not a valid URL`);
}
if (url2.hostname === "github.com" || url2.hostname === "api.github.com") {
return GITHUB_DOTCOM_URL;
}
if (url2.pathname.indexOf("/api/v3") !== -1) {
url2.pathname = url2.pathname.substring(0, url2.pathname.indexOf("/api/v3"));
}
if (url2.hostname.startsWith("api.")) {
url2.hostname = url2.hostname.substring(4);
}
if (!url2.pathname.endsWith("/")) {
url2.pathname = `${url2.pathname}/`;
}
return url2.toString();
}
function getCurrentInstance(env) {
return {
url: env.getRequired("GITHUB_SERVER_URL" /* GITHUB_SERVER_URL */),
apiURL: env.getRequired("GITHUB_API_URL" /* GITHUB_API_URL */)
};
}
// src/util.ts
var BASE_DATABASE_OIDS_FILE_NAME = "base-database-oids.json";
var BROKEN_VERSIONS = ["0.0.0-20211207"];
@@ -169816,37 +169903,6 @@ var ExhaustivityCheckingError = class extends Error {
function assertNever(value) {
throw new ExhaustivityCheckingError(value);
}
function initializeEnvironment(version, env = getEnv()) {
env.export("CODEQL_ACTION_FEATURE_MULTI_LANGUAGE" /* FEATURE_MULTI_LANGUAGE */, "false");
env.export("CODEQL_ACTION_FEATURE_SANDWICH" /* FEATURE_SANDWICH */, "false");
env.export("CODEQL_ACTION_FEATURE_SARIF_COMBINE" /* FEATURE_SARIF_COMBINE */, "true");
env.export("CODEQL_ACTION_FEATURE_WILL_UPLOAD" /* FEATURE_WILL_UPLOAD */, "true");
env.export("CODEQL_ACTION_VERSION" /* VERSION */, version);
}
var HTTPError = class extends Error {
status;
constructor(message, status) {
super(message);
this.status = status;
}
};
var ConfigurationError = class extends Error {
};
function asHTTPError(arg) {
if (!isObject2(arg) || !isString(arg.message)) {
return void 0;
}
if (Number.isInteger(arg.status)) {
return new HTTPError(arg.message, arg.status);
}
if (Number.isInteger(arg.httpStatusCode)) {
return new HTTPError(arg.message, arg.httpStatusCode);
}
return void 0;
}
async function codeQlVersionAtLeast(codeql, requiredVersion) {
return semver.gte((await codeql.getVersion()).version, requiredVersion);
}
function getBaseDatabaseOidsFilePath(config) {
return path.join(config.dbLocation, BASE_DATABASE_OIDS_FILE_NAME);
}
@@ -169889,8 +169945,15 @@ async function delay(milliseconds, opts) {
function isGoodVersion(versionSpec) {
return !BROKEN_VERSIONS.includes(versionSpec);
}
function shouldSkipSarifUpload() {
return isInTestMode() || process.env["CODEQL_ACTION_SKIP_SARIF_UPLOAD" /* SKIP_SARIF_UPLOAD */] === "true";
function shouldSkipGenerateFailedSarif(env = getEnv()) {
const skipGenerateFailedSarif = env.getOptional(
"CODEQL_ACTION_SKIP_GENERATE_FAILED_SARIF" /* SKIP_GENERATE_FAILED_SARIF */
);
return skipGenerateFailedSarif !== "false" && (shouldSkipSarifUpload(env) || skipGenerateFailedSarif === "true");
}
function shouldSkipSarifUpload(env = getEnv()) {
const skipSarifUpload = env.getOptional("CODEQL_ACTION_SKIP_SARIF_UPLOAD" /* SKIP_SARIF_UPLOAD */);
return skipSarifUpload !== "false" && (env.isSkippingUploadsInTests() || skipSarifUpload === "true");
}
function getTestingEnvironment() {
const testingEnvironment = process.env["CODEQL_ACTION_TESTING_ENVIRONMENT" /* TESTING_ENVIRONMENT */] || "";
@@ -169981,12 +170044,6 @@ function parseMatrixInput(matrixInput) {
);
}
}
function wrapError(error3) {
return error3 instanceof Error ? error3 : new Error(String(error3));
}
function getErrorMessage(error3) {
return error3 instanceof Error ? error3.message : String(error3);
}
function prettyPrintPack(pack) {
return `${pack.name}${pack.version ? `@${pack.version}` : ""}${pack.path ? `:${pack.path}` : ""}`;
}
@@ -170630,43 +170687,6 @@ retry.VERSION = VERSION7;
// src/api-client.ts
var import_undici = __toESM(require_undici());
// src/github.ts
var GITHUB_DOTCOM_URL = "https://github.com";
function parseGitHubUrl(inputUrl) {
const originalUrl = inputUrl;
if (inputUrl.indexOf("://") === -1) {
inputUrl = `https://${inputUrl}`;
}
if (!inputUrl.startsWith("http://") && !inputUrl.startsWith("https://")) {
throw new ConfigurationError(`"${originalUrl}" is not a http or https URL`);
}
let url2;
try {
url2 = new URL(inputUrl);
} catch {
throw new ConfigurationError(`"${originalUrl}" is not a valid URL`);
}
if (url2.hostname === "github.com" || url2.hostname === "api.github.com") {
return GITHUB_DOTCOM_URL;
}
if (url2.pathname.indexOf("/api/v3") !== -1) {
url2.pathname = url2.pathname.substring(0, url2.pathname.indexOf("/api/v3"));
}
if (url2.hostname.startsWith("api.")) {
url2.hostname = url2.hostname.substring(4);
}
if (!url2.pathname.endsWith("/")) {
url2.pathname = `${url2.pathname}/`;
}
return url2.toString();
}
function getCurrentInstance(env) {
return {
url: env.getRequired("GITHUB_SERVER_URL" /* GITHUB_SERVER_URL */),
apiURL: env.getRequired("GITHUB_API_URL" /* GITHUB_API_URL */)
};
}
// src/repository.ts
function isRepositoryNwoStr(val) {
return val.includes("/");
@@ -171792,8 +171812,8 @@ var path6 = __toESM(require("path"));
var semver3 = __toESM(require_semver2());
// src/defaults.json
var bundleVersion = "codeql-bundle-v2.27.2";
var cliVersion = "2.27.2";
var bundleVersion = "codeql-bundle-v2.27.3";
var cliVersion = "2.27.3";
// src/overlay/index.ts
var fs5 = __toESM(require("fs"));
@@ -172085,11 +172105,6 @@ var featureConfig = {
minimumVersion: CODEQL_OVERLAY_MINIMUM_VERSION_RUBY
},
// Other overlay-related feature flags
["overlay_analysis_disable_trap_caching" /* OverlayAnalysisDisableTrapCaching */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_DISABLE_TRAP_CACHING",
minimumVersion: void 0
},
["overlay_analysis_match_codeql_version" /* OverlayAnalysisMatchCodeqlVersion */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_MATCH_CODEQL_VERSION",
@@ -172250,7 +172265,7 @@ var OfflineFeatures = class {
}
const minimumVersion2 = config.minimumVersion;
if (codeql && minimumVersion2) {
if (!await codeQlVersionAtLeast(codeql, minimumVersion2)) {
if (!await codeql.isVersionAtLeast(minimumVersion2)) {
this.logger.debug(
`Feature ${feature} is disabled because the CodeQL CLI version is older than the minimum version ${minimumVersion2}.`
);
@@ -172673,6 +172688,7 @@ var fs16 = __toESM(require("fs"));
var path15 = __toESM(require("path"));
var core12 = __toESM(require_core());
var toolrunner3 = __toESM(require_toolrunner());
var semver10 = __toESM(require_semver2());
// src/cli-errors.ts
var SUPPORTED_PLATFORMS = [
@@ -174661,10 +174677,7 @@ function runnerHasSufficientDiskSpace(diskUsage, logger2, minimumDiskSpaceMb) {
return true;
}
async function runnerHasSufficientMemory(codeql, ramInput, logger2) {
if (await codeQlVersionAtLeast(
codeql,
CODEQL_VERSION_REDUCED_OVERLAY_MEMORY_USAGE
)) {
if (await codeql.isVersionAtLeast(CODEQL_VERSION_REDUCED_OVERLAY_MEMORY_USAGE)) {
logger2.debug(
`Skipping memory check for overlay analysis because CodeQL version is at least ${CODEQL_VERSION_REDUCED_OVERLAY_MEMORY_USAGE}.`
);
@@ -174802,7 +174815,7 @@ async function validateOverlayDatabaseMode(overlayDatabaseMode, useOverlayDataba
);
return new Failure("incompatible-build-mode" /* IncompatibleBuildMode */);
}
if (!await codeQlVersionAtLeast(codeql, CODEQL_OVERLAY_MINIMUM_VERSION)) {
if (!await codeql.isVersionAtLeast(CODEQL_OVERLAY_MINIMUM_VERSION)) {
logger2.warning(
`Cannot build an ${overlayDatabaseMode} database because the CodeQL CLI is older than ${CODEQL_OVERLAY_MINIMUM_VERSION}. Falling back to creating a normal full database instead.`
);
@@ -174834,11 +174847,11 @@ async function validateOverlayDatabaseMode(overlayDatabaseMode, useOverlayDataba
overlayModeSetExplicitly
});
}
async function isTrapCachingEnabled(features, overlayDatabaseMode) {
function isTrapCachingEnabled(overlayDatabaseMode) {
const trapCaching = getOptionalInput("trap-caching");
if (trapCaching !== void 0) return trapCaching === "true";
if (!looksLikeHostedRunner()) return false;
if (overlayDatabaseMode !== "none" /* None */ && await features.getValue("overlay_analysis_disable_trap_caching" /* OverlayAnalysisDisableTrapCaching */)) {
if (overlayDatabaseMode !== "none" /* None */) {
return false;
}
return true;
@@ -175041,7 +175054,7 @@ async function initConfig(actionState, inputs) {
inputs.codeql,
logger2
);
if (await isTrapCachingEnabled(features, config.overlayDatabaseMode)) {
if (isTrapCachingEnabled(config.overlayDatabaseMode)) {
const { trapCaches, trapCacheDownloadTime } = await downloadCacheWithTime(
inputs.codeql,
config.languages,
@@ -177002,16 +177015,6 @@ var CODEQL_NEXT_MINIMUM_VERSION = "2.21.3";
var GHES_VERSION_MOST_RECENTLY_DEPRECATED = "3.17";
var GHES_MOST_RECENT_DEPRECATION_DATE = "2026-09-24";
var EXTRACTION_DEBUG_MODE_VERBOSITY = "progress++";
function isDiskConfigurationError(e) {
if (!(e instanceof Error)) {
return false;
}
return (
// out of disk space
e.message.includes("ENOSPC") || // access denied
e.message.includes("EACCES")
);
}
async function setupCodeQL(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, rawLanguages, otherLanguagePacksReason, useOverlayAwareDefaultCliVersion, features, logger2, checkVersion) {
try {
const {
@@ -177086,6 +177089,9 @@ async function getCodeQLForCmd(logger2, cmd, checkVersion) {
}
return result;
},
async isVersionAtLeast(requiredVersion) {
return semver10.gte((await this.getVersion()).version, requiredVersion);
},
async printVersion() {
core12.info(JSON.stringify(await this.getVersion(), null, 2));
},
@@ -177474,11 +177480,11 @@ Output was: ${extractorPath}`
await runCli(cmd, args);
}
};
if (checkVersion && !await codeQlVersionAtLeast(codeql, CODEQL_MINIMUM_VERSION)) {
if (checkVersion && !await codeql.isVersionAtLeast(CODEQL_MINIMUM_VERSION)) {
throw new ConfigurationError(
`Expected a CodeQL CLI with version at least ${CODEQL_MINIMUM_VERSION} but got version ${(await codeql.getVersion()).version}`
);
} else if (checkVersion && process.env["CODEQL_ACTION_SUPPRESS_DEPRECATED_SOON_WARNING" /* SUPPRESS_DEPRECATED_SOON_WARNING */] !== "true" && !await codeQlVersionAtLeast(codeql, CODEQL_NEXT_MINIMUM_VERSION)) {
} else if (checkVersion && process.env["CODEQL_ACTION_SUPPRESS_DEPRECATED_SOON_WARNING" /* SUPPRESS_DEPRECATED_SOON_WARNING */] !== "true" && !await codeql.isVersionAtLeast(CODEQL_NEXT_MINIMUM_VERSION)) {
const result = await codeql.getVersion();
core12.warning(
`CodeQL CLI version ${result.version} was discontinued on ${GHES_MOST_RECENT_DEPRECATION_DATE} alongside GitHub Enterprise Server ${GHES_VERSION_MOST_RECENTLY_DEPRECATED} and will not be supported by the next minor release of the CodeQL Action. Please update to CodeQL CLI version ${CODEQL_NEXT_MINIMUM_VERSION} or later. For instance, if you have specified a custom version of the CLI using the 'tools' input to the 'init' Action, you can remove this input to use the default version.
@@ -178539,6 +178545,7 @@ __export(upload_lib_exports, {
filterAlertsByDiffRange: () => filterAlertsByDiffRange,
findSarifFilesInDir: () => findSarifFilesInDir,
getGroupedSarifFilePaths: () => getGroupedSarifFilePaths,
getSavedPayloadPath: () => getSavedPayloadPath,
populateRunAutomationDetails: () => populateRunAutomationDetails,
postProcessSarifFiles: () => postProcessSarifFiles,
readSarifFileOrThrow: () => readSarifFileOrThrow,
@@ -180014,7 +180021,7 @@ async function shouldDisableCombineSarifFiles(sarifObjects, githubVersion) {
}
return true;
}
async function combineSarifFilesUsingCLI(sarifFiles, gitHubVersion, features, logger2) {
async function combineSarifFilesUsingCLI(sarifFiles, gitHubVersion, features, logger2, config) {
const env = getEnv();
logger2.info("Combining SARIF files using the CodeQL CLI");
const sarifObjects = sarifFiles.map(readSarifFile);
@@ -180035,7 +180042,6 @@ async function combineSarifFilesUsingCLI(sarifFiles, gitHubVersion, features, lo
}
let codeQL;
let tempDir = getTemporaryDirectory();
const config = await getConfig(tempDir, logger2);
if (config !== void 0) {
codeQL = await getCodeQL(logger2, config.codeQLCmd);
tempDir = config.tempDir;
@@ -180102,13 +180108,16 @@ function getAutomationID2(category, analysis_key, environment) {
}
return computeAutomationID(analysis_key, environment);
}
function getSavedPayloadPath(analysisKind) {
return path19.join(
getTemporaryDirectory(),
`payload-${analysisKind}.json`
);
}
async function uploadPayload(payload, repositoryNwo, logger2, analysis) {
logger2.info("Uploading results");
if (shouldSkipSarifUpload()) {
const payloadSaveFile = path19.join(
getTemporaryDirectory(),
`payload-${analysis.kind}.json`
);
const payloadSaveFile = getSavedPayloadPath(analysis.kind);
logger2.info(
`SARIF upload disabled by an environment variable. Saving to ${payloadSaveFile}`
);
@@ -180320,7 +180329,7 @@ function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, wo
}
return payloadObj;
}
async function postProcessSarifFiles(logger2, features, checkoutPath, sarifPaths, category, analysis) {
async function postProcessSarifFiles(logger2, features, config, checkoutPath, sarifPaths, category, analysis) {
logger2.info(`Post-processing sarif files: ${JSON.stringify(sarifPaths)}`);
const gitHubVersion = await getGitHubVersion();
let sarifLog;
@@ -180334,7 +180343,8 @@ async function postProcessSarifFiles(logger2, features, checkoutPath, sarifPaths
sarifPaths,
gitHubVersion,
features,
logger2
logger2,
config
);
} else {
const sarifPath = sarifPaths[0];
@@ -180367,13 +180377,14 @@ async function writePostProcessedFiles(logger2, pathInput, uploadTarget, postPro
logger2.debug(`Not writing post-processed SARIF files.`);
}
}
async function uploadFiles(inputSarifPath, checkoutPath, category, features, logger2, uploadTarget) {
async function uploadFiles(config, inputSarifPath, checkoutPath, category, features, logger2, uploadTarget) {
const sarifPaths = getSarifFilePaths(
inputSarifPath,
uploadTarget.sarifPredicate
);
return uploadSpecifiedFiles(
sarifPaths,
config,
checkoutPath,
category,
features,
@@ -180381,10 +180392,11 @@ async function uploadFiles(inputSarifPath, checkoutPath, category, features, log
uploadTarget
);
}
async function uploadSpecifiedFiles(sarifPaths, checkoutPath, category, features, logger2, uploadTarget) {
async function uploadSpecifiedFiles(sarifPaths, config, checkoutPath, category, features, logger2, uploadTarget) {
const processingResults = await postProcessSarifFiles(
logger2,
features,
config,
checkoutPath,
sarifPaths,
category,
@@ -180469,6 +180481,12 @@ async function waitForProcessing(repositoryNwo, sarifID, logger2, options = {
}) {
logger2.startGroup("Waiting for processing to finish");
try {
if (shouldSkipSarifUpload()) {
logger2.info(
"Nothing to wait for, because SARIF upload is disabled by an environment variable and the SARIF was saved to disk."
);
return;
}
const client = getApiClient();
let statusCheckBackoff = STATUS_CHECK_INITIAL_BACKOFF_MILLISECONDS;
if (process.env["NODE_ENV"] !== "test") {
@@ -180614,7 +180632,7 @@ function filterAlertsByDiffRange(logger2, sarifLog) {
}
// src/upload-sarif.ts
async function postProcessAndUploadSarif(logger2, features, uploadKind, checkoutPath, sarifPath, category, postProcessedOutputPath) {
async function postProcessAndUploadSarif(logger2, features, config, uploadKind, checkoutPath, sarifPath, category, postProcessedOutputPath) {
const sarifGroups = await getGroupedSarifFilePaths(
logger2,
sarifPath
@@ -180627,6 +180645,7 @@ async function postProcessAndUploadSarif(logger2, features, uploadKind, checkout
const postProcessingResults = await postProcessSarifFiles(
logger2,
features,
config,
checkoutPath,
sarifFiles,
category,
@@ -180759,7 +180778,7 @@ async function run(action) {
let dependencyCacheResults;
let databaseUploadResults = [];
try {
initializeEnvironment(getActionVersion());
action.env.initialise(getActionVersion());
persistInputs();
const statusReportBase = await createStatusReportBase(
"finish" /* Analyze */,
@@ -180857,6 +180876,7 @@ async function run(action) {
uploadResults = await postProcessAndUploadSarif(
logger2,
features,
config,
uploadKind,
checkoutPath,
outputDir,
@@ -180909,8 +180929,10 @@ async function run(action) {
logger2
);
}
if (isInTestMode()) {
logger2.debug("In test mode. Waiting for processing is disabled.");
if (shouldSkipSarifUpload()) {
logger2.debug(
"SARIF upload is disabled and nothing was uploaded, so we do not need to wait for processing to finish."
);
} else if (uploadResults?.["code-scanning" /* CodeScanning */] !== void 0 && getRequiredInput("wait-for-processing") === "true") {
await waitForProcessing(
getRepositoryNwo(),
@@ -183090,7 +183112,7 @@ var import_async = __toESM(require_async(), 1);
var import_path7 = require("path");
// node_modules/archiver/lib/error.js
var import_util37 = __toESM(require("util"), 1);
var import_util36 = __toESM(require("util"), 1);
var ERROR_CODES = {
ABORTED: "archive was aborted",
DIRECTORYDIRPATHREQUIRED: "diretory dirpath argument must be a non-empty string value",
@@ -183115,7 +183137,7 @@ function ArchiverError(code, data) {
this.code = code;
this.data = data;
}
import_util37.default.inherits(ArchiverError, Error);
import_util36.default.inherits(ArchiverError, Error);
// node_modules/archiver/lib/core.js
var import_readable_stream2 = __toESM(require_ours(), 1);
@@ -185938,8 +185960,8 @@ async function runWrapper2() {
// src/autobuild-action.ts
var core17 = __toESM(require_core());
async function sendCompletedStatusReport(config, logger2, startedAt, allLanguages, failingLanguage, cause) {
initializeEnvironment(getActionVersion());
async function sendCompletedStatusReport(env, config, logger2, startedAt, allLanguages, failingLanguage, cause) {
env.initialise(getActionVersion());
const status = getActionsStatus(cause, failingLanguage);
const statusReportBase = await createStatusReportBase(
"autobuild" /* Autobuild */,
@@ -186011,6 +186033,7 @@ async function run2({
`We were unable to automatically build your code. Please replace the call to the autobuild action with your custom build steps. ${error3.message}`
);
await sendCompletedStatusReport(
env,
config,
logger2,
startedAt,
@@ -186021,7 +186044,13 @@ async function run2({
return;
}
env.export("CODEQL_ACTION_AUTOBUILD_DID_COMPLETE_SUCCESSFULLY" /* AUTOBUILD_DID_COMPLETE_SUCCESSFULLY */, "true");
await sendCompletedStatusReport(config, logger2, startedAt, languages ?? []);
await sendCompletedStatusReport(
env,
config,
logger2,
startedAt,
languages ?? []
);
}
var autobuild = {
name: "autobuild" /* Autobuild */,
@@ -186036,7 +186065,7 @@ var fs29 = __toESM(require("fs"));
var path25 = __toESM(require("path"));
var core19 = __toESM(require_core());
var io7 = __toESM(require_io());
var semver10 = __toESM(require_semver2());
var semver11 = __toESM(require_semver2());
// src/config/inputs.ts
async function getToolsInput(action, repositoryProperties) {
@@ -186449,7 +186478,7 @@ async function run3(actionState) {
let toolsSource;
let toolsVersion;
try {
initializeEnvironment(getActionVersion());
actionState.env.initialise(getActionVersion());
persistInputs();
apiDetails = {
auth: getRequiredInput("token"),
@@ -186546,7 +186575,7 @@ async function run3(actionState) {
) {
const publicPreview = "2.22.1";
const actualVer = (await codeql.getVersion()).version;
if (semver10.lt(actualVer, publicPreview)) {
if (semver11.lt(actualVer, publicPreview)) {
actionState.env.export("CODEQL_ENABLE_EXPERIMENTAL_FEATURES" /* EXPERIMENTAL_FEATURES */, "true");
logger2.info("Experimental Rust analysis enabled");
}
@@ -186779,7 +186808,7 @@ exec ${goBinaryPath} "$@"`
logger2.debug(
`${"CODEQL_EXTRACTOR_JAVA_OPTION_MINIMIZE_DEPENDENCY_JARS" /* JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS */} is already set to '${process.env["CODEQL_EXTRACTOR_JAVA_OPTION_MINIMIZE_DEPENDENCY_JARS" /* JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS */]}', so the Action will not override it.`
);
} else if (await codeQlVersionAtLeast(codeql, CODEQL_VERSION_JAR_MINIMIZATION) && config.dependencyCachingEnabled && config.buildMode === "none" /* None */ && config.languages.includes("java" /* java */)) {
} else if (await codeql.isVersionAtLeast(CODEQL_VERSION_JAR_MINIMIZATION) && config.dependencyCachingEnabled && config.buildMode === "none" /* None */ && config.languages.includes("java" /* java */)) {
actionState.env.export(
"CODEQL_EXTRACTOR_JAVA_OPTION_MINIMIZE_DEPENDENCY_JARS" /* JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS */,
"true"
@@ -186903,7 +186932,7 @@ async function prepareFailedSarif(logger2, features, config) {
}
const jobName = getRequiredEnvParam("GITHUB_JOB");
const matrix = parseMatrixInput(getRequiredInput("matrix"));
if (shouldSkipSarifUpload()) {
if (shouldSkipGenerateFailedSarif()) {
return new Failure({
upload_failed_run_skipped_because: "SARIF upload is disabled"
});
@@ -186974,6 +187003,7 @@ async function maybeUploadFailedSarif(config, repositoryNwo, features, logger2)
const failedSarif = failedSarifResult.value;
logger2.info(`Uploading failed SARIF file ${failedSarif.sarifFile}`);
const uploadResult = await uploadFiles(
config,
failedSarif.sarifFile,
failedSarif.checkoutPath,
failedSarif.category,
@@ -186987,6 +187017,9 @@ async function maybeUploadFailedSarif(config, repositoryNwo, features, logger2)
logger2,
{ isUnsuccessfulExecution: true }
);
if (uploadResult.sarifID && shouldSkipSarifUpload()) {
await uploadSarifArtifact(logger2, "test-mode-sarif", failedSarif);
}
return uploadResult ? { ...uploadResult.statusReport, sarifID: uploadResult.sarifID } : {};
}
async function maybeUploadFailedSarifArtifact(config, features, logger2) {
@@ -186995,19 +187028,25 @@ async function maybeUploadFailedSarifArtifact(config, features, logger2) {
return failedSarifResult.value;
}
const failedSarif = failedSarifResult.value;
logger2.info(
`Uploading failed SARIF file ${failedSarif.sarifFile} as artifact`
);
const gitHubVersion = await getGitHubVersion();
const client = await getArtifactUploaderClient(logger2, gitHubVersion.type);
const suffix = getArtifactSuffix(getOptionalInput("matrix"));
const name = sanitizeArtifactName(`sarif-artifact-${suffix}`);
await client.uploadArtifact(
name,
[import_path8.default.normalize(failedSarif.sarifFile)],
import_path8.default.normalize("..")
);
return { sarifID: name };
return uploadSarifArtifact(logger2, "sarif-artifact", failedSarif);
}
async function uploadSarifArtifact(logger2, prefix, failedSarif) {
logger2.startGroup(`Uploading failed SARIF file as artifact`);
logger2.info(`Uploading '${failedSarif.sarifFile}' as artifact`);
try {
const gitHubVersion = await getGitHubVersion();
const client = await getArtifactUploaderClient(logger2, gitHubVersion.type);
const suffix = getArtifactSuffix(getOptionalInput("matrix"));
const name = sanitizeArtifactName(`${prefix}-${suffix}`);
await client.uploadArtifact(
name,
[import_path8.default.normalize(failedSarif.sarifFile)],
import_path8.default.normalize(import_path8.default.dirname(failedSarif.sarifFile))
);
return { sarifID: name };
} finally {
logger2.endGroup();
}
}
async function tryUploadSarifIfRunFailed(config, repositoryNwo, features, logger2) {
if (process.env["CODEQL_ACTION_ANALYZE_DID_COMPLETE_SUCCESSFULLY" /* ANALYZE_DID_COMPLETE_SUCCESSFULLY */] === "true") {
@@ -187232,6 +187271,9 @@ async function run4(action) {
const tmpDir = getTemporaryDirectory();
config = await getConfig(tmpDir, logger2);
if (config === void 0) {
logger2.debug(
"Will try to load the configuration file from an aborted 'init' step, since there is no regular one."
);
config = getAbortedInitConfig(action, tmpDir);
}
const gitHubVersion = config?.gitHubVersion ?? await getGitHubVersion();
@@ -187492,7 +187534,7 @@ async function run6(actionState) {
let toolsSource;
let toolsVersion;
try {
initializeEnvironment(getActionVersion());
actionState.env.initialise(getActionVersion());
const apiDetails = {
auth: getRequiredInput("token"),
externalRepoAuth: getOptionalInput("external-repository-token"),
@@ -188444,23 +188486,25 @@ async function sendSuccessStatusReport2(startedAt, uploadStats, logger2) {
await sendStatusReport(statusReport);
}
}
async function run8({ startedAt, logger: logger2 }) {
async function run8(action) {
const logger2 = action.logger;
try {
initializeEnvironment(getActionVersion());
action.env.initialise(getActionVersion());
const gitHubVersion = await getGitHubVersion();
checkActionVersion(getActionVersion(), gitHubVersion);
persistInputs();
const tempDir = getTemporaryDirectory();
const repositoryNwo = getRepositoryNwo();
const features = initFeatures(
gitHubVersion,
repositoryNwo,
getTemporaryDirectory(),
tempDir,
logger2
);
const startingStatusReportBase = await createStatusReportBase(
"upload-sarif" /* UploadSarif */,
"starting",
startedAt,
action.startedAt,
void 0,
await checkDiskUsage(logger2),
logger2
@@ -188471,9 +188515,11 @@ async function run8({ startedAt, logger: logger2 }) {
const sarifPath = getRequiredInput("sarif_file");
const checkoutPath = getRequiredInput("checkout_path");
const category = getOptionalInput("category");
const maybeConfig = await getConfig(tempDir, logger2);
const uploadResults = await postProcessAndUploadSarif(
logger2,
features,
maybeConfig,
"always",
checkoutPath,
sarifPath,
@@ -188503,7 +188549,7 @@ async function run8({ startedAt, logger: logger2 }) {
}
}
await sendSuccessStatusReport2(
startedAt,
action.startedAt,
codeScanningResult?.statusReport || {},
logger2
);
@@ -188514,7 +188560,7 @@ async function run8({ startedAt, logger: logger2 }) {
const errorStatusReportBase = await createStatusReportBase(
"upload-sarif" /* UploadSarif */,
getActionsStatus(error3),
startedAt,
action.startedAt,
void 0,
await checkDiskUsage(logger2),
logger2,
+5 -4
View File
@@ -12,8 +12,8 @@ import {
import { computeAutomationID } from "./api-client";
import { EnvVar } from "./environment";
import { getRunnerLogger } from "./logging";
import { RecordingLogger, setupTests } from "./testing-utils";
import { initializeEnvironment, withTmpDir } from "./util";
import { getTestEnv, RecordingLogger, setupTests } from "./testing-utils";
import { withTmpDir } from "./util";
setupTests(test);
@@ -228,8 +228,9 @@ test.serial(
);
test.serial("initializeEnvironment", (t) => {
initializeEnvironment("1.2.3");
t.deepEqual(process.env[EnvVar.VERSION], "1.2.3");
const env = getTestEnv();
env.initialise("1.2.3");
t.deepEqual(env.getOptional(EnvVar.VERSION), "1.2.3");
});
test.serial("fixCodeQualityCategory", (t) => {
+6 -3
View File
@@ -238,7 +238,7 @@ async function run(action: ActionState<["Base", "Logger", "Env", "Actions"]>) {
let databaseUploadResults: DatabaseUploadResult[] = [];
try {
util.initializeEnvironment(actionsUtil.getActionVersion());
action.env.initialise(actionsUtil.getActionVersion());
// Make inputs accessible in the `post` step, details at
// https://github.com/github/codeql-action/issues/2553
@@ -361,6 +361,7 @@ async function run(action: ActionState<["Base", "Logger", "Env", "Actions"]>) {
uploadResults = await postProcessAndUploadSarif(
logger,
features,
config,
uploadKind,
checkoutPath,
outputDir,
@@ -433,8 +434,10 @@ async function run(action: ActionState<["Base", "Logger", "Env", "Actions"]>) {
}
// We don't upload results in test mode, so don't wait for processing
if (util.isInTestMode()) {
logger.debug("In test mode. Waiting for processing is disabled.");
if (util.shouldSkipSarifUpload()) {
logger.debug(
"SARIF upload is disabled and nothing was uploaded, so we do not need to wait for processing to finish.",
);
} else if (
uploadResults?.[analyses.AnalysisKind.CodeScanning] !== undefined &&
actionsUtil.getRequiredInput("wait-for-processing") === "true"
+2 -2
View File
@@ -7,7 +7,7 @@ import { ProxyAgent } from "undici";
import * as actionsUtil from "./actions-util";
import * as api from "./api-client";
import { DO_NOT_RETRY_STATUSES } from "./api-client";
import { ActionsEnvVars, RegistryProxyVars } from "./environment";
import { ActionsEnvVars, RegistryProxyVars, getEnv } from "./environment";
import { GITHUB_DOTCOM_API_URL, GITHUB_DOTCOM_URL } from "./github";
import {
callee,
@@ -21,7 +21,7 @@ import * as util from "./util";
setupTests(test);
test.beforeEach(() => {
util.initializeEnvironment(actionsUtil.getActionVersion());
getEnv().initialise(actionsUtil.getActionVersion());
});
test.serial("getApiClient", async (t) => {
+11 -4
View File
@@ -10,7 +10,7 @@ import { getGitHubVersion } from "./api-client";
import { determineAutobuildLanguages, runAutobuild } from "./autobuild";
import { getCodeQL } from "./codeql";
import { Config, getConfig } from "./config-utils";
import { EnvVar } from "./environment";
import { EnvVar, type Env } from "./environment";
import { Language } from "./languages";
import { Logger } from "./logging";
import {
@@ -26,7 +26,6 @@ import {
checkDiskUsage,
checkGitHubVersionInRange,
ConfigurationError,
initializeEnvironment,
wrapError,
} from "./util";
@@ -38,6 +37,7 @@ interface AutobuildStatusReport extends StatusReportBase {
}
async function sendCompletedStatusReport(
env: Env,
config: Config | undefined,
logger: Logger,
startedAt: Date,
@@ -45,7 +45,7 @@ async function sendCompletedStatusReport(
failingLanguage?: string,
cause?: Error,
) {
initializeEnvironment(getActionVersion());
env.initialise(getActionVersion());
const status = getActionsStatus(cause, failingLanguage);
const statusReportBase = await createStatusReportBase(
@@ -129,6 +129,7 @@ async function run({
`We were unable to automatically build your code. Please replace the call to the autobuild action with your custom build steps. ${error.message}`,
);
await sendCompletedStatusReport(
env,
config,
logger,
startedAt,
@@ -141,7 +142,13 @@ async function run({
env.export(EnvVar.AUTOBUILD_DID_COMPLETE_SUCCESSFULLY, "true");
await sendCompletedStatusReport(config, logger, startedAt, languages ?? []);
await sendCompletedStatusReport(
env,
config,
logger,
startedAt,
languages ?? [],
);
}
/** Defines the `autobuild` Action. */
+2 -2
View File
@@ -21,6 +21,7 @@ import {
import type { Config } from "./config-utils";
import * as defaults from "./defaults.json";
import { DocUrl } from "./doc-url";
import { getEnv } from "./environment";
import { BuiltInLanguage } from "./languages";
import { getRunnerLogger } from "./logging";
import { ToolsSource } from "./setup-codeql";
@@ -37,14 +38,13 @@ import {
} from "./testing-utils";
import { ToolsDownloadStatusReport } from "./tools-download";
import * as util from "./util";
import { initializeEnvironment } from "./util";
setupTests(test);
let stubConfig: Config;
test.beforeEach(() => {
initializeEnvironment("1.2.3");
getEnv().initialise("1.2.3");
stubConfig = createTestConfig({
languages: [BuiltInLanguage.cpp],
+31 -26
View File
@@ -4,6 +4,7 @@ import * as path from "path";
import * as core from "@actions/core";
import * as toolrunner from "@actions/exec/lib/toolrunner";
import * as yaml from "js-yaml";
import * as semver from "semver";
import {
CommandInvocationError,
@@ -19,6 +20,7 @@ import type { ActionConfig } from "./config/action-config";
import { appendExtraQueryExclusions, type Config } from "./config-utils";
import { DocUrl } from "./doc-url";
import { EnvVar, getEnv, exportEnvVar } from "./environment";
import { getErrorMessage, isDiskConfigurationError } from "./errors";
import {
CodeQLDefaultVersionInfo,
Feature,
@@ -34,7 +36,9 @@ import { ToolsDownloadStatusReport } from "./tools-download";
import { ToolsFeature, isSupportedToolsFeature } from "./tools-features";
import { shouldEnableIndirectTracing } from "./tracer-config";
import * as util from "./util";
import { BuildMode, CleanupLevel, getErrorMessage } from "./util";
import { BuildMode, CleanupLevel } from "./util";
export { isDiskConfigurationError } from "./errors";
type Options = Array<string | number | boolean>;
@@ -70,6 +74,11 @@ export interface CodeQL {
* Get a string containing the semver version of the CodeQL executable.
*/
getVersion(): Promise<VersionInfo>;
/**
* Determines whether the CLI installation represented by this {@link CodeQL} instance
* has at least the {@link requiredVersion}.
*/
isVersionAtLeast(requiredVersion: string): Promise<boolean>;
/**
* Print version information about CodeQL.
*/
@@ -274,26 +283,6 @@ const GHES_MOST_RECENT_DEPRECATION_DATE = "2026-09-24";
/** The CLI verbosity level to use for extraction in debug mode. */
const EXTRACTION_DEBUG_MODE_VERBOSITY = "progress++";
/**
* Decides whether `e` is a disk-related error outside of our control
* that should be classified as a `ConfigurationError`.
*
* @param e The error to check.
* @returns True if the error should be treated as a `ConfigurationError` or false if not.
*/
export function isDiskConfigurationError(e: unknown): boolean {
if (!(e instanceof Error)) {
return false;
}
return (
// out of disk space
e.message.includes("ENOSPC") ||
// access denied
e.message.includes("EACCES")
);
}
/**
* Set up CodeQL CLI access.
*
@@ -402,9 +391,9 @@ export function setCodeQL(codeql: Partial<CodeQL>): void {
cachedCodeQL = createStubCodeQL(codeql);
}
function resolveFunction<T>(
function resolveFunction<K extends keyof CodeQL, T extends CodeQL[K]>(
partialCodeql: Partial<CodeQL>,
methodName: string,
methodName: K,
defaultImplementation?: T,
): T {
if (typeof partialCodeql[methodName] !== "function") {
@@ -414,7 +403,7 @@ function resolveFunction<T>(
const dummyMethod = () => {
throw new Error(`CodeQL ${methodName} method not correctly defined`);
};
return dummyMethod as T;
return dummyMethod as unknown as T;
}
return partialCodeql[methodName] as T;
}
@@ -431,6 +420,19 @@ export function createStubCodeQL(partialCodeql: Partial<CodeQL>): CodeQL {
getVersion: resolveFunction(partialCodeql, "getVersion", async () => ({
version: "1.0.0",
})),
isVersionAtLeast: resolveFunction(
partialCodeql,
"isVersionAtLeast",
async (requiredVersion) => {
return (
!!partialCodeql.getVersion &&
semver.gte(
(await partialCodeql.getVersion()).version,
requiredVersion,
)
);
},
),
printVersion: resolveFunction(partialCodeql, "printVersion"),
supportsFeature: resolveFunction(
partialCodeql,
@@ -534,6 +536,9 @@ async function getCodeQLForCmd(
}
return result;
},
async isVersionAtLeast(requiredVersion: string) {
return semver.gte((await this.getVersion()).version, requiredVersion);
},
async printVersion() {
// Reuse the cached version information rather than invoking the CLI again.
core.info(JSON.stringify(await this.getVersion(), null, 2));
@@ -1028,7 +1033,7 @@ async function getCodeQLForCmd(
// CodeQL object is created.
if (
checkVersion &&
!(await util.codeQlVersionAtLeast(codeql, CODEQL_MINIMUM_VERSION))
!(await codeql.isVersionAtLeast(CODEQL_MINIMUM_VERSION))
) {
throw new util.ConfigurationError(
`Expected a CodeQL CLI with version at least ${CODEQL_MINIMUM_VERSION} but got version ${
@@ -1038,7 +1043,7 @@ async function getCodeQLForCmd(
} else if (
checkVersion &&
process.env[EnvVar.SUPPRESS_DEPRECATED_SOON_WARNING] !== "true" &&
!(await util.codeQlVersionAtLeast(codeql, CODEQL_NEXT_MINIMUM_VERSION))
!(await codeql.isVersionAtLeast(CODEQL_NEXT_MINIMUM_VERSION))
) {
const result = await codeql.getVersion();
core.warning(
+45 -67
View File
@@ -2126,7 +2126,7 @@ test.serial("getPrimaryAnalysisConfig - Code Scanning + Code Quality", (t) => {
});
test.serial(
"isTrapCachingEnabled: explicit input true is respected",
"isTrapCachingEnabled: explicit true input overrides self-hosted default",
async (t) => {
return await withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir);
@@ -2134,12 +2134,40 @@ test.serial(
.stub(actionsUtil, "getOptionalInput")
.withArgs("trap-caching")
.returns("true");
t.true(
await configUtils.isTrapCachingEnabled(
createFeatures([]),
OverlayDatabaseMode.None,
),
);
t.true(configUtils.isTrapCachingEnabled(OverlayDatabaseMode.None));
});
},
);
test.serial(
"isTrapCachingEnabled: explicit true input overrides overlay defaults",
async (t) => {
return await withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, path.join(tmpDir, "hostedtoolcache"));
sinon
.stub(actionsUtil, "getOptionalInput")
.withArgs("trap-caching")
.returns("true");
for (const overlayDatabaseMode of [
OverlayDatabaseMode.Overlay,
OverlayDatabaseMode.OverlayBase,
]) {
t.true(configUtils.isTrapCachingEnabled(overlayDatabaseMode));
}
});
},
);
test.serial(
"isTrapCachingEnabled: explicit false input overrides hosted default",
async (t) => {
return await withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, path.join(tmpDir, "hostedtoolcache"));
sinon
.stub(actionsUtil, "getOptionalInput")
.withArgs("trap-caching")
.returns("false");
t.false(configUtils.isTrapCachingEnabled(OverlayDatabaseMode.None));
});
},
);
@@ -2153,18 +2181,13 @@ test.serial(
.stub(actionsUtil, "getOptionalInput")
.withArgs("trap-caching")
.returns(undefined);
t.false(
await configUtils.isTrapCachingEnabled(
createFeatures([]),
OverlayDatabaseMode.None,
),
);
t.false(configUtils.isTrapCachingEnabled(OverlayDatabaseMode.None));
});
},
);
test.serial(
"isTrapCachingEnabled: enabled on hosted runner by default",
"isTrapCachingEnabled: enabled on hosted runner without overlay analysis",
async (t) => {
return await withTmpDir(async (tmpDir) => {
const hostedToolCache = path.join(tmpDir, "hostedtoolcache");
@@ -2173,18 +2196,13 @@ test.serial(
.stub(actionsUtil, "getOptionalInput")
.withArgs("trap-caching")
.returns(undefined);
t.true(
await configUtils.isTrapCachingEnabled(
createFeatures([]),
OverlayDatabaseMode.None,
),
);
t.true(configUtils.isTrapCachingEnabled(OverlayDatabaseMode.None));
});
},
);
test.serial(
"isTrapCachingEnabled: enabled on hosted runner when overlay enabled but feature flag off",
"isTrapCachingEnabled: disabled on hosted runner with overlay analysis",
async (t) => {
return await withTmpDir(async (tmpDir) => {
const hostedToolCache = path.join(tmpDir, "hostedtoolcache");
@@ -2193,52 +2211,12 @@ test.serial(
.stub(actionsUtil, "getOptionalInput")
.withArgs("trap-caching")
.returns(undefined);
t.true(
await configUtils.isTrapCachingEnabled(
createFeatures([]),
OverlayDatabaseMode.Overlay,
),
);
});
},
);
test.serial(
"isTrapCachingEnabled: disabled on hosted runner when overlay enabled and feature flag on",
async (t) => {
return await withTmpDir(async (tmpDir) => {
const hostedToolCache = path.join(tmpDir, "hostedtoolcache");
setupActionsVars(tmpDir, hostedToolCache);
sinon
.stub(actionsUtil, "getOptionalInput")
.withArgs("trap-caching")
.returns(undefined);
t.false(
await configUtils.isTrapCachingEnabled(
createFeatures([Feature.OverlayAnalysisDisableTrapCaching]),
OverlayDatabaseMode.Overlay,
),
);
});
},
);
test.serial(
"isTrapCachingEnabled: enabled on hosted runner when overlay is None even with feature flag on",
async (t) => {
return await withTmpDir(async (tmpDir) => {
const hostedToolCache = path.join(tmpDir, "hostedtoolcache");
setupActionsVars(tmpDir, hostedToolCache);
sinon
.stub(actionsUtil, "getOptionalInput")
.withArgs("trap-caching")
.returns(undefined);
t.true(
await configUtils.isTrapCachingEnabled(
createFeatures([Feature.OverlayAnalysisDisableTrapCaching]),
OverlayDatabaseMode.None,
),
);
for (const overlayDatabaseMode of [
OverlayDatabaseMode.Overlay,
OverlayDatabaseMode.OverlayBase,
]) {
t.false(configUtils.isTrapCachingEnabled(overlayDatabaseMode));
}
});
},
);
+12 -16
View File
@@ -82,7 +82,6 @@ import {
GitHubVersion,
ConfigurationError,
BuildMode,
codeQlVersionAtLeast,
cloneObject,
isDefined,
checkDiskUsage,
@@ -652,10 +651,7 @@ async function runnerHasSufficientMemory(
logger: Logger,
): Promise<boolean> {
if (
await codeQlVersionAtLeast(
codeql,
CODEQL_VERSION_REDUCED_OVERLAY_MEMORY_USAGE,
)
await codeql.isVersionAtLeast(CODEQL_VERSION_REDUCED_OVERLAY_MEMORY_USAGE)
) {
logger.debug(
`Skipping memory check for overlay analysis because CodeQL version is at least ${CODEQL_VERSION_REDUCED_OVERLAY_MEMORY_USAGE}.`,
@@ -899,7 +895,7 @@ async function validateOverlayDatabaseMode(
);
return new Failure(OverlayDisabledReason.IncompatibleBuildMode);
}
if (!(await codeQlVersionAtLeast(codeql, CODEQL_OVERLAY_MINIMUM_VERSION))) {
if (!(await codeql.isVersionAtLeast(CODEQL_OVERLAY_MINIMUM_VERSION))) {
logger.warning(
`Cannot build an ${overlayDatabaseMode} database because ` +
`the CodeQL CLI is older than ${CODEQL_OVERLAY_MINIMUM_VERSION}. ` +
@@ -944,10 +940,14 @@ async function validateOverlayDatabaseMode(
});
}
export async function isTrapCachingEnabled(
features: FeatureEnablement,
/**
* Determines whether TRAP caching is enabled for the current run.
*
* @returns Whether TRAP caches should be downloaded and uploaded.
*/
export function isTrapCachingEnabled(
overlayDatabaseMode: OverlayDatabaseMode,
): Promise<boolean> {
): boolean {
// If the workflow specified something, always respect that.
const trapCaching = getOptionalInput("trap-caching");
if (trapCaching !== undefined) return trapCaching === "true";
@@ -955,12 +955,8 @@ export async function isTrapCachingEnabled(
// On self-hosted runners which may have slow network access, disable TRAP caching by default.
if (!looksLikeHostedRunner()) return false;
// If overlay analysis is enabled, then disable TRAP caching since overlay analysis supersedes it.
// This change is gated behind a feature flag.
if (
overlayDatabaseMode !== OverlayDatabaseMode.None &&
(await features.getValue(Feature.OverlayAnalysisDisableTrapCaching))
) {
// Overlay analysis supersedes TRAP caching, so disable TRAP caching by default when it is active.
if (overlayDatabaseMode !== OverlayDatabaseMode.None) {
return false;
}
@@ -1302,7 +1298,7 @@ export async function initConfig(
logger,
);
if (await isTrapCachingEnabled(features, config.overlayDatabaseMode)) {
if (isTrapCachingEnabled(config.overlayDatabaseMode)) {
const { trapCaches, trapCacheDownloadTime } = await downloadCacheWithTime(
inputs.codeql,
config.languages,
+3 -8
View File
@@ -15,6 +15,7 @@ import {
cleanupAndUploadDatabases,
uploadBundledDatabase,
} from "./database-upload";
import { getEnv } from "./environment";
import { Feature } from "./feature-flags";
import * as gitUtils from "./git-utils";
import { BuiltInLanguage } from "./languages";
@@ -31,18 +32,12 @@ import {
setupActionsVars,
setupTests,
} from "./testing-utils";
import {
CleanupLevel,
GitHubVariant,
HTTPError,
initializeEnvironment,
withTmpDir,
} from "./util";
import { CleanupLevel, GitHubVariant, HTTPError, withTmpDir } from "./util";
setupTests(test);
test.beforeEach(() => {
initializeEnvironment("1.2.3");
getEnv().initialise("1.2.3");
});
const testRepoName: RepositoryNwo = { owner: "github", repo: "example" };
+4 -4
View File
@@ -1,6 +1,6 @@
{
"bundleVersion": "codeql-bundle-v2.27.2",
"cliVersion": "2.27.2",
"priorBundleVersion": "codeql-bundle-v2.27.1",
"priorCliVersion": "2.27.1"
"bundleVersion": "codeql-bundle-v2.27.3",
"cliVersion": "2.27.3",
"priorBundleVersion": "codeql-bundle-v2.27.2",
"priorCliVersion": "2.27.2"
}
+32 -10
View File
@@ -165,9 +165,21 @@ export enum EnvVar {
*/
SARIF_DUMP_DIR = "CODEQL_ACTION_SARIF_DUMP_DIR",
/**
* Whether to skip generating a failed SARIF file. Intended for testing purposes.
* This setting is more specific than `CODEQL_ACTION_TEST_MODE` and
* `CODEQL_ACTION_SKIP_SARIF_UPLOAD`, which imply this option.
*
* Setting this to `false` takes precedence over `CODEQL_ACTION_TEST_MODE: true` or
* `CODEQL_ACTION_SKIP_SARIF_UPLOAD: true`.
*/
SKIP_GENERATE_FAILED_SARIF = "CODEQL_ACTION_SKIP_GENERATE_FAILED_SARIF",
/**
* Whether to skip uploading SARIF results to GitHub. Intended for testing purposes.
* This setting is more specific than `CODEQL_ACTION_TEST_MODE`, which implies this option.
*
* Setting this to `false` takes precedence over `CODEQL_ACTION_TEST_MODE: true`.
*/
SKIP_SARIF_UPLOAD = "CODEQL_ACTION_SKIP_SARIF_UPLOAD",
@@ -281,8 +293,8 @@ export function getOptionalEnvVar(paramName: string): string | undefined {
* in tests, while clearly signalling in regular code that the consumer of the `ReadOnlyEnv` instance
* will only read from it.
*/
export class ReadOnlyEnv<T extends string | undefined = string | undefined> {
constructor(protected readonly vars: Record<string, T>) {}
export class ReadOnlyEnv {
constructor(protected readonly vars: Record<string, string | undefined>) {}
/** Clones the object while detaching the underlying environment from the original. */
public clone(): this {
@@ -290,7 +302,7 @@ export class ReadOnlyEnv<T extends string | undefined = string | undefined> {
}
/** Gets a copy of the underlying environment. */
public get(): Record<string, T> {
public get(): Record<string, string | undefined> {
return { ...this.vars };
}
@@ -305,7 +317,7 @@ export class ReadOnlyEnv<T extends string | undefined = string | undefined> {
}
/** Gets the entries of the underlying `ProcessEnv`. */
public entries(): Array<[string, T]> {
public entries(): Array<[string, string | undefined]> {
return Object.entries(this.vars);
}
@@ -335,19 +347,17 @@ export class ReadOnlyEnv<T extends string | undefined = string | undefined> {
* Use `ReadOnlyEnv` instead if you only plan to read from the environment.
* This type allows writing to the environment.
*/
export class Env<
T extends string | undefined = string | undefined,
> extends ReadOnlyEnv<T> {
export class Env extends ReadOnlyEnv {
private changed: boolean = false;
/** Sets an environment variable. */
public set(name: string, value: T): void {
public set(name: string, value: string | undefined): void {
this.vars[name] = value;
this.changed = true;
}
/** Sets all environment variables given by `vars`. */
public setAll(vars: Record<string, T>): void {
public setAll(vars: Record<string, string | undefined>): void {
for (const [key, val] of Object.entries(vars)) {
this.set(key, val);
}
@@ -361,7 +371,7 @@ export class Env<
* @param name The name of the environment variable to set and export.
* @param val The value to set and export for the environment variable.
*/
public export(name: string, val: T): void {
public export(name: string, val: string): void {
// Setting the environment variable for this instance is always OK, including
// in tests, since we use fresh `Env` instances whenever needed. This allows
// tests to pass that rely on that part of the `core.exportVariable` behaviour.
@@ -373,6 +383,18 @@ export class Env<
}
}
/**
* Set some initial environment variables that we can set even without
* knowing what version of CodeQL we're running.
*/
public initialise(version: string) {
this.export(EnvVar.FEATURE_MULTI_LANGUAGE, "false");
this.export(EnvVar.FEATURE_SANDWICH, "false");
this.export(EnvVar.FEATURE_SARIF_COMBINE, "true");
this.export(EnvVar.FEATURE_WILL_UPLOAD, "true");
this.export(EnvVar.VERSION, version);
}
/** Gets a value indicating whether `set` was called at least once. */
public hasChanged(): boolean {
return this.changed;
+73
View File
@@ -0,0 +1,73 @@
import * as json from "../json";
/**
* If {@link error} is not already an instance of {@link Error}, then this function constructs
* an {@link Error} with a string representation of {@link error} as the message.
*/
export function wrapError(error: unknown): Error {
return error instanceof Error ? error : new Error(String(error));
}
/**
* Returns an appropriate message for the error.
*
* If the error is an {@link Error} instance, this returns the error message without
* an `Error: ` prefix.
*/
export function getErrorMessage(error: unknown): string {
return error instanceof Error ? error.message : String(error);
}
/**
* Decides whether `e` is a disk-related error outside of our control
* that should be classified as a `ConfigurationError`.
*
* @param e The error to check.
* @returns True if the error should be treated as a `ConfigurationError` or false if not.
*/
export function isDiskConfigurationError(e: unknown): boolean {
if (!(e instanceof Error)) {
return false;
}
return (
// out of disk space
e.message.includes("ENOSPC") ||
// access denied
e.message.includes("EACCES")
);
}
/**
* An Error class that indicates an error that occurred due to
* a misconfiguration of the action or the CodeQL CLI.
*/
export class ConfigurationError extends Error {}
/** Minimal representation of errors resulting from HTTP requests. */
export class HTTPError extends Error {
public status: number;
constructor(message: string, status: number) {
super(message);
this.status = status;
}
}
/**
* Tries to convert {@link arg} to a {@link HTTPError}, but returns `undefined` if
* {@link arg} is not like a {@link HTTPError}.
*/
export function asHTTPError(arg: any): HTTPError | undefined {
if (!json.isObject<any>(arg) || !json.isString(arg.message)) {
return undefined;
}
if (Number.isInteger(arg.status)) {
return new HTTPError(arg.message, arg.status as number);
}
// See https://github.com/actions/toolkit/blob/acb230b99a46ed33a3f04a758cd68b47b9a82908/packages/tool-cache/src/tool-cache.ts#L19
if (Number.isInteger(arg.httpStatusCode)) {
return new HTTPError(arg.message, arg.httpStatusCode as number);
}
return undefined;
}
+3 -2
View File
@@ -4,6 +4,7 @@ import * as path from "path";
import test from "ava";
import * as defaults from "./defaults.json";
import { getEnv } from "./environment";
import {
Feature,
featureConfig,
@@ -26,12 +27,12 @@ import {
setupTests,
stubFeatureFlagApiEndpoint,
} from "./testing-utils";
import { GitHubVariant, initializeEnvironment, withTmpDir } from "./util";
import { GitHubVariant, withTmpDir } from "./util";
setupTests(test);
test.beforeEach(() => {
initializeEnvironment("1.2.3");
getEnv().initialise("1.2.3");
});
test.serial(
+1 -8
View File
@@ -103,8 +103,6 @@ export enum Feature {
OverlayAnalysisCodeScanningRuby = "overlay_analysis_code_scanning_ruby",
OverlayAnalysisCpp = "overlay_analysis_cpp",
OverlayAnalysisCsharp = "overlay_analysis_csharp",
/** Disable TRAP caching when overlay analysis is enabled. */
OverlayAnalysisDisableTrapCaching = "overlay_analysis_disable_trap_caching",
OverlayAnalysisGo = "overlay_analysis_go",
OverlayAnalysisJava = "overlay_analysis_java",
OverlayAnalysisJavascript = "overlay_analysis_javascript",
@@ -369,11 +367,6 @@ export const featureConfig = {
minimumVersion: CODEQL_OVERLAY_MINIMUM_VERSION_RUBY,
},
// Other overlay-related feature flags
[Feature.OverlayAnalysisDisableTrapCaching]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_DISABLE_TRAP_CACHING",
minimumVersion: undefined,
},
[Feature.OverlayAnalysisMatchCodeqlVersion]: {
defaultValue: false,
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_MATCH_CODEQL_VERSION",
@@ -589,7 +582,7 @@ class OfflineFeatures implements FeatureEnablement {
// Never use this feature if the CLI version explicitly can't support it.
const minimumVersion = config.minimumVersion;
if (codeql && minimumVersion) {
if (!(await util.codeQlVersionAtLeast(codeql, minimumVersion))) {
if (!(await codeql.isVersionAtLeast(minimumVersion))) {
this.logger.debug(
`Feature ${feature} is disabled because the CodeQL CLI version is older than the minimum ` +
`version ${minimumVersion}.`,
+2 -2
View File
@@ -8,7 +8,7 @@ import {
LoggedMessage,
setupTests,
} from "../testing-utils";
import { GitHubVariant, initializeEnvironment, withTmpDir } from "../util";
import { getEnv, GitHubVariant, withTmpDir } from "../util";
import {
assertAllFeaturesHaveDefaultValues,
@@ -18,7 +18,7 @@ import {
setupTests(test);
test.beforeEach(() => {
initializeEnvironment("1.2.3");
getEnv().initialise("1.2.3");
});
test("OfflineFeatures makes no API requests", async (t) => {
+15 -1
View File
@@ -1,5 +1,19 @@
import { ActionsEnvVars, type ReadOnlyEnv } from "./environment";
import { ConfigurationError } from "./util";
import { ConfigurationError } from "./errors";
export enum GitHubVariant {
/** [GitHub.com](https://github.com) */
DOTCOM = "GitHub.com",
/** [GitHub Enterprise Server](https://docs.github.com/en/enterprise-server@latest/admin/overview/about-github-enterprise-server) */
GHES = "GitHub Enterprise Server",
/** [GitHub Enterprise Cloud with data residency](https://docs.github.com/en/enterprise-cloud@latest/admin/data-residency/about-github-enterprise-cloud-with-data-residency) */
GHEC_DR = "GitHub Enterprise Cloud with data residency",
}
export type GitHubVersion =
| { type: GitHubVariant.DOTCOM }
| { type: GitHubVariant.GHEC_DR }
| { type: GitHubVariant.GHES; version: string };
/** A string representing a GitHub instance address. */
export type InstanceURL = string;
+1
View File
@@ -793,6 +793,7 @@ async function testFailedSarifUpload(
}
t.true(
uploadFiles.calledOnceWith(
config,
sinon.match.string,
sinon.match.string,
category,
+35 -14
View File
@@ -44,6 +44,7 @@ import {
getRequiredEnvParam,
parseMatrixInput,
Result,
shouldSkipGenerateFailedSarif,
shouldSkipSarifUpload,
Success,
wrapError,
@@ -115,7 +116,7 @@ async function prepareFailedSarif(
const jobName = getRequiredEnvParam("GITHUB_JOB");
const matrix = parseMatrixInput(actionsUtil.getRequiredInput("matrix"));
if (shouldSkipSarifUpload()) {
if (shouldSkipGenerateFailedSarif()) {
return new Failure({
upload_failed_run_skipped_because: "SARIF upload is disabled",
});
@@ -226,6 +227,7 @@ async function maybeUploadFailedSarif(
logger.info(`Uploading failed SARIF file ${failedSarif.sarifFile}`);
const uploadResult = await uploadLib.uploadFiles(
config,
failedSarif.sarifFile,
failedSarif.checkoutPath,
failedSarif.category,
@@ -239,6 +241,14 @@ async function maybeUploadFailedSarif(
logger,
{ isUnsuccessfulExecution: true },
);
// If SARIF upload is disabled for testing, `uploadFiles` will not have uploaded the failed
// SARIF file and instead will have written it to disk. Upload it as a workflow artifact so that
// we can inspect it in validation jobs.
if (uploadResult.sarifID && shouldSkipSarifUpload()) {
await uploadSarifArtifact(logger, "test-mode-sarif", failedSarif);
}
return uploadResult
? { ...uploadResult.statusReport, sarifID: uploadResult.sarifID }
: {};
@@ -257,23 +267,34 @@ async function maybeUploadFailedSarifArtifact(
}
const failedSarif = failedSarifResult.value;
return uploadSarifArtifact(logger, "sarif-artifact", failedSarif);
}
logger.info(
`Uploading failed SARIF file ${failedSarif.sarifFile} as artifact`,
);
/** Uploads a failed SARIF file as workflow artifact. */
async function uploadSarifArtifact(
logger: Logger,
prefix: string,
failedSarif: FailedSarifInfo,
): Promise<UploadFailedSarifResult> {
logger.startGroup(`Uploading failed SARIF file as artifact`);
logger.info(`Uploading '${failedSarif.sarifFile}' as artifact`);
const gitHubVersion = await getGitHubVersion();
const client = await getArtifactUploaderClient(logger, gitHubVersion.type);
try {
const gitHubVersion = await getGitHubVersion();
const client = await getArtifactUploaderClient(logger, gitHubVersion.type);
const suffix = getArtifactSuffix(actionsUtil.getOptionalInput("matrix"));
const name = sanitizeArtifactName(`sarif-artifact-${suffix}`);
await client.uploadArtifact(
name,
[path.normalize(failedSarif.sarifFile)],
path.normalize(".."),
);
const suffix = getArtifactSuffix(actionsUtil.getOptionalInput("matrix"));
const name = sanitizeArtifactName(`${prefix}-${suffix}`);
await client.uploadArtifact(
name,
[path.normalize(failedSarif.sarifFile)],
path.normalize(path.dirname(failedSarif.sarifFile)),
);
return { sarifID: name };
return { sarifID: name };
} finally {
logger.endGroup();
}
}
/**
+3
View File
@@ -76,6 +76,9 @@ async function run(action: ActionState<["Base", "Logger", "Env"]>) {
// Try to load the "failed" configuration file instead which may have been written by the `init` step
// with a minimal configuration for this post-action.
if (config === undefined) {
logger.debug(
"Will try to load the configuration file from an aborted 'init' step, since there is no regular one.",
);
config = getAbortedInitConfig(action, tmpDir);
}
+2 -4
View File
@@ -88,12 +88,10 @@ import {
checkDiskUsage,
checkForTimeout,
checkGitHubVersionInRange,
codeQlVersionAtLeast,
DEFAULT_DEBUG_ARTIFACT_NAME,
DEFAULT_DEBUG_DATABASE_NAME,
getCodeQLMemoryLimit,
getThreadsFlagValue,
initializeEnvironment,
ConfigurationError,
wrapError,
checkActionVersion,
@@ -226,7 +224,7 @@ async function run(
let toolsVersion: string;
try {
initializeEnvironment(getActionVersion());
actionState.env.initialise(getActionVersion());
// Make inputs accessible in the `post` step.
persistInputs();
@@ -686,7 +684,7 @@ async function run(
`${EnvVar.JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS} is already set to '${process.env[EnvVar.JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS]}', so the Action will not override it.`,
);
} else if (
(await codeQlVersionAtLeast(codeql, CODEQL_VERSION_JAR_MINIMIZATION)) &&
(await codeql.isVersionAtLeast(CODEQL_VERSION_JAR_MINIMIZATION)) &&
config.dependencyCachingEnabled &&
config.buildMode === BuildMode.None &&
config.languages.includes(BuiltInLanguage.java)
+1 -2
View File
@@ -38,7 +38,6 @@ import {
checkDiskUsage,
checkForTimeout,
checkGitHubVersionInRange,
initializeEnvironment,
ConfigurationError,
wrapError,
checkActionVersion,
@@ -108,7 +107,7 @@ async function run(
let toolsVersion: string;
try {
initializeEnvironment(getActionVersion());
actionState.env.initialise(getActionVersion());
const apiDetails = {
auth: getRequiredInput("token"),
+9 -9
View File
@@ -11,7 +11,13 @@ import * as sinon from "sinon";
import * as actionsUtil from "./actions-util";
import * as api from "./api-client";
import * as diagnostics from "./diagnostics";
import { ActionsEnvVars, Env, EnvVar, ReadOnlyEnv } from "./environment";
import {
ActionsEnvVars,
Env,
EnvVar,
getEnv,
ReadOnlyEnv,
} from "./environment";
import { Feature } from "./feature-flags";
import { BuiltInLanguage } from "./languages";
import { getRunnerLogger } from "./logging";
@@ -37,18 +43,12 @@ import {
setupTests,
} from "./testing-utils";
import * as toolsDownload from "./tools-download";
import {
getErrorMessage,
GitHubVariant,
HTTPError,
initializeEnvironment,
withTmpDir,
} from "./util";
import { getErrorMessage, GitHubVariant, HTTPError, withTmpDir } from "./util";
setupTests(test);
test.beforeEach(() => {
initializeEnvironment("1.2.3");
getEnv().initialise("1.2.3");
});
function stubDownloadAndExtract() {
+1 -2
View File
@@ -6,7 +6,6 @@ import * as sinon from "sinon";
import * as actionsUtil from "../actions-util";
import { ActionsEnvVars } from "../environment";
import { callee, getTestEnv, setupTests } from "../testing-utils";
import { initializeEnvironment } from "../util";
import { getCodeQLActionRepository } from "./repository";
@@ -16,7 +15,7 @@ test.serial("getCodeQLActionRepository", async (t) => {
const initialEnv = getTestEnv({
[ActionsEnvVars.RUNNER_TEMP]: path.dirname(__dirname),
});
initializeEnvironment("1.2.3", initialEnv);
initialEnv.initialise("1.2.3");
const target = callee(getCodeQLActionRepository)
.withArgs()
+1 -2
View File
@@ -2,13 +2,12 @@ import { ActionState } from "../action-common";
import { isRunningLocalAction } from "../actions-util";
import * as api from "../api-client";
import { ActionsEnvVars } from "../environment";
import { GITHUB_DOTCOM_URL } from "../github";
import { GITHUB_DOTCOM_URL, type InstanceURL } from "../github";
import {
isRepositoryNwoStr,
parseRepositoryNwo,
type RepositoryNwoStr,
} from "../repository";
import { type InstanceURL } from "../util";
/** The NWO of the standard CodeQL Action repository. */
export const CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action";
+2 -1
View File
@@ -10,6 +10,7 @@ import { https } from "follow-redirects";
import nock from "nock";
import * as sinon from "sinon";
import * as errors from "./errors";
import { getRunnerLogger } from "./logging";
import * as tar from "./tar";
import { setupTests } from "./testing-utils";
@@ -164,7 +165,7 @@ test.serial(
test.serial(
"downloadAndExtract handles an unknown status as a non-HTTP error",
async (t) => {
const asHTTPError = sinon.spy(util, "asHTTPError");
const asHTTPError = sinon.spy(errors, "asHTTPError");
await util.withTmpDir(async (tmpDir) => {
sinon.stub(process, "platform").value("linux");
const archivePath = path.join(tmpDir, "codeql-bundle.tar.zst");
+3 -2
View File
@@ -10,17 +10,18 @@ import * as analyses from "./analyses";
import { AnalysisKind, CodeQuality, CodeScanning } from "./analyses";
import * as api from "./api-client";
import * as diffUtils from "./diff-informed-analysis-utils";
import { getEnv } from "./environment";
import { getRunnerLogger, Logger } from "./logging";
import * as sarif from "./sarif";
import { setupTests } from "./testing-utils";
import * as uploadLib from "./upload-lib";
import { UploadPayload } from "./upload-lib/types";
import { GitHubVariant, initializeEnvironment, withTmpDir } from "./util";
import { GitHubVariant, withTmpDir } from "./util";
setupTests(test);
test.beforeEach(() => {
initializeEnvironment("1.2.3");
getEnv().initialise("1.2.3");
});
test.serial("validateSarifFileSchema - valid", (t) => {
+34 -10
View File
@@ -12,7 +12,7 @@ import * as analyses from "./analyses";
import * as api from "./api-client";
import { getGitHubVersion, wrapApiConfigurationError } from "./api-client";
import { CodeQL, getCodeQL } from "./codeql";
import { getConfig } from "./config-utils";
import type { ActionConfig } from "./config/action-config";
import { readDiffRangesJsonFile } from "./diff-informed-analysis-utils";
import { ActionsEnvVars, EnvVar, exportEnvVar } from "./environment";
import { FeatureEnablement } from "./feature-flags";
@@ -94,15 +94,19 @@ async function shouldDisableCombineSarifFiles(
return true;
}
// Takes a list of paths to sarif files and combines them together using the
// CLI `github merge-results` command when all SARIF files are produced by
// CodeQL. Otherwise, it will fall back to combining the files in the action.
// Returns the contents of the combined sarif file.
/**
* Takes a list of paths to sarif files and combines them together using the
* CLI `github merge-results` command when all SARIF files are produced by
* CodeQL. Otherwise, it will fall back to combining the files in the action.
*
* @returns The contents of the combined sarif file.
*/
async function combineSarifFilesUsingCLI(
sarifFiles: string[],
gitHubVersion: GitHubVersion,
features: FeatureEnablement,
logger: Logger,
config: ActionConfig<"codeQLCmd" | "tempDir"> | undefined,
): Promise<Partial<sarif.Log>> {
const env = util.getEnv();
@@ -140,7 +144,6 @@ async function combineSarifFilesUsingCLI(
let codeQL: CodeQL;
let tempDir: string = actionsUtil.getTemporaryDirectory();
const config = await getConfig(tempDir, logger);
if (config !== undefined) {
codeQL = await getCodeQL(logger, config.codeQLCmd);
tempDir = config.tempDir;
@@ -228,6 +231,14 @@ function getAutomationID(
return api.computeAutomationID(analysis_key, environment);
}
/** Gets the path to a saved payload file for {@link analysisKind}. */
export function getSavedPayloadPath(analysisKind: analyses.AnalysisKind) {
return path.join(
actionsUtil.getTemporaryDirectory(),
`payload-${analysisKind}.json`,
);
}
/**
* Upload the given payload.
* If the request fails then this will retry a small number of times.
@@ -242,10 +253,7 @@ export async function uploadPayload(
logger.info("Uploading results");
if (util.shouldSkipSarifUpload()) {
const payloadSaveFile = path.join(
actionsUtil.getTemporaryDirectory(),
`payload-${analysis.kind}.json`,
);
const payloadSaveFile = getSavedPayloadPath(analysis.kind);
logger.info(
`SARIF upload disabled by an environment variable. Saving to ${payloadSaveFile}`,
);
@@ -599,6 +607,7 @@ export interface PostProcessingResults {
export async function postProcessSarifFiles(
logger: Logger,
features: FeatureEnablement,
config: ActionConfig<"codeQLCmd" | "tempDir"> | undefined,
checkoutPath: string,
sarifPaths: string[],
category: string | undefined,
@@ -623,6 +632,7 @@ export async function postProcessSarifFiles(
gitHubVersion,
features,
logger,
config,
);
} else {
const sarifPath = sarifPaths[0];
@@ -683,6 +693,7 @@ export async function writePostProcessedFiles(
* to.
*/
export async function uploadFiles(
config: ActionConfig<"codeQLCmd" | "tempDir"> | undefined,
inputSarifPath: string,
checkoutPath: string,
category: string | undefined,
@@ -697,6 +708,7 @@ export async function uploadFiles(
return uploadSpecifiedFiles(
sarifPaths,
config,
checkoutPath,
category,
features,
@@ -710,6 +722,7 @@ export async function uploadFiles(
*/
async function uploadSpecifiedFiles(
sarifPaths: string[],
config: ActionConfig<"codeQLCmd" | "tempDir"> | undefined,
checkoutPath: string,
category: string | undefined,
features: FeatureEnablement,
@@ -719,6 +732,7 @@ async function uploadSpecifiedFiles(
const processingResults: PostProcessingResults = await postProcessSarifFiles(
logger,
features,
config,
checkoutPath,
sarifPaths,
category,
@@ -857,6 +871,16 @@ export async function waitForProcessing(
): Promise<void> {
logger.startGroup("Waiting for processing to finish");
try {
// If SARIF upload is disabled and we reach this point, then the file was written to disk and
// there is nothing to wait for. We still allow ourselves to get to this point so that we can
// see in the log that we would have waited for processing to finish if the upload had happened.
if (util.shouldSkipSarifUpload()) {
logger.info(
"Nothing to wait for, because SARIF upload is disabled by an environment variable and the SARIF was saved to disk.",
);
return;
}
const client = api.getApiClient();
// Do an initial wait because processing will always take a minimum of 2-3 seconds
+14 -7
View File
@@ -5,6 +5,7 @@ import * as actionsUtil from "./actions-util";
import { getActionVersion, getTemporaryDirectory } from "./actions-util";
import * as analyses from "./analyses";
import { getGitHubVersion } from "./api-client";
import { getConfig } from "./config-utils";
import { initFeatures } from "./feature-flags";
import { Logger } from "./logging";
import { getRepositoryNwo } from "./repository";
@@ -23,7 +24,6 @@ import {
ConfigurationError,
checkActionVersion,
checkDiskUsage,
initializeEnvironment,
shouldSkipSarifUpload,
wrapError,
} from "./util";
@@ -54,11 +54,13 @@ async function sendSuccessStatusReport(
}
}
async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) {
async function run(action: ActionState<["Base", "Env", "Logger"]>) {
// To capture errors appropriately, keep as much code within the try-catch as
// possible, and only use safe functions outside.
const logger = action.logger;
try {
initializeEnvironment(getActionVersion());
action.env.initialise(getActionVersion());
const gitHubVersion = await getGitHubVersion();
checkActionVersion(getActionVersion(), gitHubVersion);
@@ -66,18 +68,19 @@ async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) {
// Make inputs accessible in the `post` step.
actionsUtil.persistInputs();
const tempDir = getTemporaryDirectory();
const repositoryNwo = getRepositoryNwo();
const features = initFeatures(
gitHubVersion,
repositoryNwo,
getTemporaryDirectory(),
tempDir,
logger,
);
const startingStatusReportBase = await createStatusReportBase(
ActionName.UploadSarif,
"starting",
startedAt,
action.startedAt,
undefined,
await checkDiskUsage(logger),
logger,
@@ -91,9 +94,13 @@ async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) {
const checkoutPath = actionsUtil.getRequiredInput("checkout_path");
const category = actionsUtil.getOptionalInput("category");
// Load the configuration from a previous step if there is one. This allows us to reuse the CLI that
// may have been installed by a previous step.
const maybeConfig = await getConfig(tempDir, logger);
const uploadResults = await postProcessAndUploadSarif(
logger,
features,
maybeConfig,
"always",
checkoutPath,
sarifPath,
@@ -131,7 +138,7 @@ async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) {
// so we can't wait for that here.
}
await sendSuccessStatusReport(
startedAt,
action.startedAt,
codeScanningResult?.statusReport || {},
logger,
);
@@ -147,7 +154,7 @@ async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) {
const errorStatusReportBase = await createStatusReportBase(
ActionName.UploadSarif,
getActionsStatus(error),
startedAt,
action.startedAt,
undefined,
await checkDiskUsage(logger),
logger,
+6
View File
@@ -26,6 +26,7 @@ function mockPostProcessSarifFiles() {
const analysisConfig = getAnalysisConfig(analysisKind);
postProcessSarifFiles
.withArgs(
sinon.match.object,
sinon.match.any,
sinon.match.any,
sinon.match.any,
@@ -75,9 +76,11 @@ const postProcessAndUploadSarifMacro = makeMacro({
fs.writeFileSync(sarifFile, "");
}
const config = undefined;
const actual = await postProcessAndUploadSarif(
logger,
features,
config,
"always",
"",
testPath,
@@ -94,6 +97,7 @@ const postProcessAndUploadSarifMacro = makeMacro({
postProcessSarifFiles.calledWith(
logger,
features,
config,
sinon.match.any,
analysisKindResult.expectedFiles?.map(toFullPath) ??
fullSarifPaths,
@@ -223,6 +227,7 @@ test.serial(
const actual = await postProcessAndUploadSarif(
logger,
features,
undefined,
"never",
"",
tempDir,
@@ -253,6 +258,7 @@ test.serial(
const actual = await postProcessAndUploadSarif(
logger,
features,
undefined,
"never",
"",
tempDir,
+3
View File
@@ -1,5 +1,6 @@
import { UploadKind } from "./actions-util";
import * as analyses from "./analyses";
import type { ActionConfig } from "./config/action-config";
import { FeatureEnablement } from "./feature-flags";
import { Logger } from "./logging";
import * as upload_lib from "./upload-lib";
@@ -26,6 +27,7 @@ export type UploadSarifResults = Partial<
export async function postProcessAndUploadSarif(
logger: Logger,
features: FeatureEnablement,
config: ActionConfig<"codeQLCmd" | "tempDir"> | undefined,
uploadKind: UploadKind,
checkoutPath: string,
sarifPath: string,
@@ -45,6 +47,7 @@ export async function postProcessAndUploadSarif(
const postProcessingResults = await upload_lib.postProcessSarifFiles(
logger,
features,
config,
checkoutPath,
sarifFiles,
category,
+68 -1
View File
@@ -11,7 +11,7 @@ import * as sinon from "sinon";
import * as api from "./api-client";
import { EnvVar } from "./environment";
import { getRunnerLogger } from "./logging";
import { setupTests } from "./testing-utils";
import { getTestEnv, setupTests } from "./testing-utils";
import * as util from "./util";
setupTests(test);
@@ -493,3 +493,70 @@ test("Failure.orElse returns the default value for a failure result", (t) => {
const result = new util.Failure(new Error("test error"));
t.is(result.orElse("default value"), "default value");
});
test("shouldSkipGenerateFailedSarif", (t) => {
const env = getTestEnv();
// Don't skip by default
t.is(util.shouldSkipGenerateFailedSarif(env), false);
// Skip in test mode
env.setAll({
[EnvVar.TEST_MODE]: "true",
[EnvVar.SKIP_SARIF_UPLOAD]: undefined,
[EnvVar.SKIP_GENERATE_FAILED_SARIF]: undefined,
});
t.is(util.shouldSkipGenerateFailedSarif(env), true);
// Skip if explicitly requested
env.setAll({
[EnvVar.TEST_MODE]: undefined,
[EnvVar.SKIP_SARIF_UPLOAD]: undefined,
[EnvVar.SKIP_GENERATE_FAILED_SARIF]: "true",
});
t.is(util.shouldSkipGenerateFailedSarif(env), true);
// Skip if not uploading SARIF
env.setAll({
[EnvVar.TEST_MODE]: undefined,
[EnvVar.SKIP_SARIF_UPLOAD]: "true",
[EnvVar.SKIP_GENERATE_FAILED_SARIF]: undefined,
});
t.is(util.shouldSkipGenerateFailedSarif(env), true);
// Don't skip if explicitly requested
env.setAll({
[EnvVar.TEST_MODE]: "true",
[EnvVar.SKIP_SARIF_UPLOAD]: "true",
[EnvVar.SKIP_GENERATE_FAILED_SARIF]: "false",
});
t.is(util.shouldSkipGenerateFailedSarif(env), false);
});
test("shouldSkipSarifUpload", (t) => {
const env = getTestEnv();
// Don't skip by default
t.is(util.shouldSkipSarifUpload(env), false);
// Skip in test mode
env.setAll({
[EnvVar.TEST_MODE]: "true",
[EnvVar.SKIP_SARIF_UPLOAD]: undefined,
});
t.is(util.shouldSkipSarifUpload(env), true);
// Skip if explicitly requested
env.setAll({
[EnvVar.TEST_MODE]: undefined,
[EnvVar.SKIP_SARIF_UPLOAD]: "true",
});
t.is(util.shouldSkipSarifUpload(env), true);
// Don't skip if explicitly requested
env.setAll({
[EnvVar.TEST_MODE]: "true",
[EnvVar.SKIP_SARIF_UPLOAD]: "false",
});
t.is(util.shouldSkipSarifUpload(env), false);
});
+28 -86
View File
@@ -18,22 +18,24 @@ import type { Config } from "./config-utils";
import {
EnvVar,
getRequiredEnvParam,
isInTestMode,
exportEnvVar,
getEnv,
type Env,
type ReadOnlyEnv,
} from "./environment";
import * as json from "./json";
import { Language } from "./languages";
import { Logger } from "./logging";
import { ConfigurationError, getErrorMessage, wrapError } from "./errors";
import { GitHubVariant, type GitHubVersion } from "./github";
import type { Language } from "./languages";
import type { Logger } from "./logging";
// Re-export for backwards compatibility to avoid updating a lot of imports elsewhere.
export * from "./errors";
export {
getRequiredEnvParam,
getOptionalEnvVar,
getEnv,
isInTestMode,
} from "./environment";
export { GitHubVariant, type GitHubVersion } from "./github";
/**
* The name of the file containing the base database OIDs, as stored in the
@@ -47,9 +49,6 @@ const BASE_DATABASE_OIDS_FILE_NAME = "base-database-oids.json";
*/
const BROKEN_VERSIONS = ["0.0.0-20211207"];
/** A string representing a GitHub instance. */
export type InstanceURL = string;
/**
* Default name of the debugging artifact.
*/
@@ -470,20 +469,6 @@ const CODEQL_ACTION_WARNED_ABOUT_VERSION_ENV_VAR =
let hasBeenWarnedAboutVersion = false;
export enum GitHubVariant {
/** [GitHub.com](https://github.com) */
DOTCOM = "GitHub.com",
/** [GitHub Enterprise Server](https://docs.github.com/en/enterprise-server@latest/admin/overview/about-github-enterprise-server) */
GHES = "GitHub Enterprise Server",
/** [GitHub Enterprise Cloud with data residency](https://docs.github.com/en/enterprise-cloud@latest/admin/data-residency/about-github-enterprise-cloud-with-data-residency) */
GHEC_DR = "GitHub Enterprise Cloud with data residency",
}
export type GitHubVersion =
| { type: GitHubVariant.DOTCOM }
| { type: GitHubVariant.GHEC_DR }
| { type: GitHubVariant.GHES; version: string };
export function checkGitHubVersionInRange(
version: GitHubVersion,
logger: Logger,
@@ -552,54 +537,6 @@ export function assertNever(value: never): never {
throw new ExhaustivityCheckingError(value);
}
/**
* Set some initial environment variables that we can set even without
* knowing what version of CodeQL we're running.
*/
export function initializeEnvironment(version: string, env: Env = getEnv()) {
env.export(EnvVar.FEATURE_MULTI_LANGUAGE, "false");
env.export(EnvVar.FEATURE_SANDWICH, "false");
env.export(EnvVar.FEATURE_SARIF_COMBINE, "true");
env.export(EnvVar.FEATURE_WILL_UPLOAD, "true");
env.export(EnvVar.VERSION, version);
}
export class HTTPError extends Error {
public status: number;
constructor(message: string, status: number) {
super(message);
this.status = status;
}
}
/**
* An Error class that indicates an error that occurred due to
* a misconfiguration of the action or the CodeQL CLI.
*/
export class ConfigurationError extends Error {}
export function asHTTPError(arg: any): HTTPError | undefined {
if (!json.isObject<any>(arg) || !json.isString(arg.message)) {
return undefined;
}
if (Number.isInteger(arg.status)) {
return new HTTPError(arg.message, arg.status as number);
}
// See https://github.com/actions/toolkit/blob/acb230b99a46ed33a3f04a758cd68b47b9a82908/packages/tool-cache/src/tool-cache.ts#L19
if (Number.isInteger(arg.httpStatusCode)) {
return new HTTPError(arg.message, arg.httpStatusCode as number);
}
return undefined;
}
export async function codeQlVersionAtLeast(
codeql: CodeQL,
requiredVersion: string,
): Promise<boolean> {
return semver.gte((await codeql.getVersion()).version, requiredVersion);
}
export function getBaseDatabaseOidsFilePath(
config: ActionConfig<"dbLocation">,
): string {
@@ -684,11 +621,30 @@ export function isGoodVersion(versionSpec: string) {
return !BROKEN_VERSIONS.includes(versionSpec);
}
/**
* Returns whether we specifically want to skip generating a failed SARIF.
*/
export function shouldSkipGenerateFailedSarif(
env: ReadOnlyEnv = getEnv(),
): boolean {
const skipGenerateFailedSarif = env.getOptional(
EnvVar.SKIP_GENERATE_FAILED_SARIF,
);
return (
skipGenerateFailedSarif !== "false" &&
(shouldSkipSarifUpload(env) || skipGenerateFailedSarif === "true")
);
}
/**
* Returns whether we specifically want to skip uploading SARIF files.
*/
export function shouldSkipSarifUpload(): boolean {
return isInTestMode() || process.env[EnvVar.SKIP_SARIF_UPLOAD] === "true";
export function shouldSkipSarifUpload(env: ReadOnlyEnv = getEnv()): boolean {
const skipSarifUpload = env.getOptional(EnvVar.SKIP_SARIF_UPLOAD);
return (
skipSarifUpload !== "false" &&
(env.isSkippingUploadsInTests() || skipSarifUpload === "true")
);
}
/**
@@ -867,20 +823,6 @@ export function parseMatrixInput(
}
}
export function wrapError(error: unknown): Error {
return error instanceof Error ? error : new Error(String(error));
}
/**
* Returns an appropriate message for the error.
*
* If the error is an `Error` instance, this returns the error message without
* an `Error: ` prefix.
*/
export function getErrorMessage(error: unknown): string {
return error instanceof Error ? error.message : String(error);
}
export function prettyPrintPack(pack: Pack) {
return `${pack.name}${pack.version ? `@${pack.version}` : ""}${
pack.path ? `:${pack.path}` : ""