From 70419e32737de18f4a5e3e1fc15a56c19e953814 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Tue, 12 May 2026 14:49:49 +0100 Subject: [PATCH 1/3] Throw error if multiple analysis kinds are specified --- lib/analyze-action-post.js | 135 +- lib/analyze-action.js | 2077 ++++++++++++------------ lib/autobuild-action.js | 119 +- lib/init-action-post.js | 393 ++--- lib/init-action.js | 2492 +++++++++++++++-------------- lib/resolve-environment-action.js | 117 +- lib/setup-codeql-action.js | 5 + lib/start-proxy-action-post.js | 111 +- lib/start-proxy-action.js | 5 + lib/upload-lib.js | 1223 +++++++------- lib/upload-sarif-action-post.js | 433 ++--- lib/upload-sarif-action.js | 151 +- src/analyses.test.ts | 61 +- src/analyses.ts | 17 +- src/feature-flags.ts | 7 + src/init-action.ts | 4 +- 16 files changed, 3736 insertions(+), 3614 deletions(-) diff --git a/lib/analyze-action-post.js b/lib/analyze-action-post.js index 0f1b660594..3a63a9687a 100644 --- a/lib/analyze-action-post.js +++ b/lib/analyze-action-post.js @@ -127358,65 +127358,8 @@ var fs4 = __toESM(require("fs")); var path5 = __toESM(require("path")); var core9 = __toESM(require_core()); -// src/analyses.ts -var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { - AnalysisKind2["CodeScanning"] = "code-scanning"; - AnalysisKind2["CodeQuality"] = "code-quality"; - AnalysisKind2["RiskAssessment"] = "risk-assessment"; - return AnalysisKind2; -})(AnalysisKind || {}); -var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); - -// src/caching-utils.ts -var core6 = __toESM(require_core()); - -// src/config/db-config.ts -var jsonschema = __toESM(require_lib2()); -var semver2 = __toESM(require_semver2()); - -// src/feature-flags/properties.ts -var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => { - RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay"; - RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries"; - RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs"; - return RepositoryPropertyName2; -})(RepositoryPropertyName || {}); -var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set( - Object.values(RepositoryPropertyName) -); - -// src/config/db-config.ts -var PACK_IDENTIFIER_PATTERN = (function() { - const alphaNumeric = "[a-z0-9]"; - const alphaNumericDash = "[a-z0-9-]"; - const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`; - return new RegExp(`^${component}/${component}$`); -})(); - -// src/logging.ts -var core7 = __toESM(require_core()); -function getActionsLogger() { - return { - debug: core7.debug, - info: core7.info, - warning: core7.warning, - error: core7.error, - isDebug: core7.isDebug, - startGroup: core7.startGroup, - endGroup: core7.endGroup - }; -} -function withGroup(groupName, f) { - core7.startGroup(groupName); - try { - return f(); - } finally { - core7.endGroup(); - } -} - // src/feature-flags.ts -var semver5 = __toESM(require_semver2()); +var semver4 = __toESM(require_semver2()); // src/overlay/index.ts var fs3 = __toESM(require("fs")); @@ -127425,14 +127368,14 @@ var path4 = __toESM(require("path")); // src/git-utils.ts var fs2 = __toESM(require("fs")); var path3 = __toESM(require("path")); -var core8 = __toESM(require_core()); +var core6 = __toESM(require_core()); var toolrunner2 = __toESM(require_toolrunner()); var io3 = __toESM(require_io()); -var semver3 = __toESM(require_semver2()); +var semver2 = __toESM(require_semver2()); var runGitCommand = async function(workingDirectory, args, customErrorMessage, options) { let stdout = ""; let stderr = ""; - core8.debug(`Running git command: git ${args.join(" ")}`); + core6.debug(`Running git command: git ${args.join(" ")}`); try { await new toolrunner2.ToolRunner(await io3.which("git", true), args, { silent: true, @@ -127453,7 +127396,7 @@ var runGitCommand = async function(workingDirectory, args, customErrorMessage, o if (stderr.includes("not a git repository")) { reason = "The checkout path provided to the action does not appear to be a git repository."; } - core8.info(`git call failed. ${customErrorMessage} Error: ${reason}`); + core6.info(`git call failed. ${customErrorMessage} Error: ${reason}`); throw error3; } }; @@ -127582,7 +127525,7 @@ async function getRef() { ) !== head; if (hasChangedRef) { const newRef = ref.replace(pull_ref_regex, "refs/pull/$1/head"); - core8.debug( + core6.debug( `No longer on merge commit, rewriting ref from ${ref} to ${newRef}.` ); return newRef; @@ -127719,17 +127662,22 @@ async function getDiffRangeFilePaths(sourceRoot, logger) { } // src/tools-features.ts -var semver4 = __toESM(require_semver2()); +var semver3 = __toESM(require_semver2()); function isSupportedToolsFeature(versionInfo, feature) { return !!versionInfo.features && versionInfo.features[feature]; } var SafeArtifactUploadVersion = "2.20.3"; function isSafeArtifactUpload(codeQlVersion) { - return !codeQlVersion ? true : semver4.gte(codeQlVersion, SafeArtifactUploadVersion); + return !codeQlVersion ? true : semver3.gte(codeQlVersion, SafeArtifactUploadVersion); } // src/feature-flags.ts var featureConfig = { + ["allow_multiple_analysis_kinds" /* AllowMultipleAnalysisKinds */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_ALLOW_MULTIPLE_ANALYSIS_KINDS", + minimumVersion: void 0 + }, ["allow_toolcache_input" /* AllowToolcacheInput */]: { defaultValue: false, envVar: "CODEQL_ACTION_ALLOW_TOOLCACHE_INPUT", @@ -127938,6 +127886,63 @@ var featureConfig = { } }; +// src/analyses.ts +var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { + AnalysisKind2["CodeScanning"] = "code-scanning"; + AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["RiskAssessment"] = "risk-assessment"; + return AnalysisKind2; +})(AnalysisKind || {}); +var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); + +// src/caching-utils.ts +var core7 = __toESM(require_core()); + +// src/config/db-config.ts +var jsonschema = __toESM(require_lib2()); +var semver5 = __toESM(require_semver2()); + +// src/feature-flags/properties.ts +var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => { + RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay"; + RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries"; + RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs"; + return RepositoryPropertyName2; +})(RepositoryPropertyName || {}); +var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set( + Object.values(RepositoryPropertyName) +); + +// src/config/db-config.ts +var PACK_IDENTIFIER_PATTERN = (function() { + const alphaNumeric = "[a-z0-9]"; + const alphaNumericDash = "[a-z0-9-]"; + const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`; + return new RegExp(`^${component}/${component}$`); +})(); + +// src/logging.ts +var core8 = __toESM(require_core()); +function getActionsLogger() { + return { + debug: core8.debug, + info: core8.info, + warning: core8.warning, + error: core8.error, + isDebug: core8.isDebug, + startGroup: core8.startGroup, + endGroup: core8.endGroup + }; +} +function withGroup(groupName, f) { + core8.startGroup(groupName); + try { + return f(); + } finally { + core8.endGroup(); + } +} + // src/languages/builtin.json var builtin_default = { languages: [ diff --git a/lib/analyze-action.js b/lib/analyze-action.js index 7b3ec243cb..6ca15fa59b 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -88977,84 +88977,10 @@ function fixCodeQualityCategory(logger, category) { return category; } -// src/analyses.ts -var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { - AnalysisKind2["CodeScanning"] = "code-scanning"; - AnalysisKind2["CodeQuality"] = "code-quality"; - AnalysisKind2["RiskAssessment"] = "risk-assessment"; - return AnalysisKind2; -})(AnalysisKind || {}); -var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); -var codeQualityQueries = ["code-quality"]; -var CodeScanning = { - kind: "code-scanning" /* CodeScanning */, - name: "code scanning", - target: "PUT /repos/:owner/:repo/code-scanning/analysis" /* CODE_SCANNING */, - sarifExtension: ".sarif", - sarifPredicate: (name) => name.endsWith(CodeScanning.sarifExtension) && !CodeQuality.sarifPredicate(name) && !RiskAssessment.sarifPredicate(name), - fixCategory: (_, category) => category, - sentinelPrefix: "CODEQL_UPLOAD_SARIF_", - transformPayload: (payload) => payload -}; -var CodeQuality = { - kind: "code-quality" /* CodeQuality */, - name: "code quality", - target: "PUT /repos/:owner/:repo/code-quality/analysis" /* CODE_QUALITY */, - sarifExtension: ".quality.sarif", - sarifPredicate: (name) => name.endsWith(CodeQuality.sarifExtension), - fixCategory: fixCodeQualityCategory, - sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_", - transformPayload: (payload) => payload -}; -function addAssessmentId(payload) { - const rawAssessmentId = getRequiredEnvParam("CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */); - const assessmentId = parseInt(rawAssessmentId, 10); - if (Number.isNaN(assessmentId)) { - throw new Error( - `${"CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */} must not be NaN: ${rawAssessmentId}` - ); - } - if (assessmentId < 0) { - throw new Error( - `${"CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */} must not be negative: ${rawAssessmentId}` - ); - } - return { sarif: payload.sarif, assessment_id: assessmentId }; -} -var RiskAssessment = { - kind: "risk-assessment" /* RiskAssessment */, - name: "code scanning risk assessment", - target: "PUT /repos/:owner/:repo/code-scanning/risk-assessment" /* RISK_ASSESSMENT */, - sarifExtension: ".csra.sarif", - sarifPredicate: (name) => name.endsWith(RiskAssessment.sarifExtension), - fixCategory: (_, category) => category, - sentinelPrefix: "CODEQL_UPLOAD_CSRA_SARIF_", - transformPayload: addAssessmentId -}; -function getAnalysisConfig(kind) { - switch (kind) { - case "code-scanning" /* CodeScanning */: - return CodeScanning; - case "code-quality" /* CodeQuality */: - return CodeQuality; - case "risk-assessment" /* RiskAssessment */: - return RiskAssessment; - } -} -var SarifScanOrder = [ - RiskAssessment, - CodeQuality, - CodeScanning -]; - -// src/analyze.ts -var fs13 = __toESM(require("fs")); -var path12 = __toESM(require("path")); -var import_perf_hooks2 = require("perf_hooks"); -var io5 = __toESM(require_io()); - -// src/autobuild.ts -var core12 = __toESM(require_core()); +// src/feature-flags.ts +var fs5 = __toESM(require("fs")); +var path5 = __toESM(require("path")); +var semver4 = __toESM(require_semver2()); // src/api-client.ts var core5 = __toESM(require_core()); @@ -89331,762 +89257,360 @@ function wrapApiConfigurationError(e) { return e; } -// src/codeql.ts -var fs12 = __toESM(require("fs")); -var path11 = __toESM(require("path")); -var core11 = __toESM(require_core()); -var toolrunner3 = __toESM(require_toolrunner()); +// src/defaults.json +var bundleVersion = "codeql-bundle-v2.25.4"; +var cliVersion = "2.25.4"; -// src/cli-errors.ts -var SUPPORTED_PLATFORMS = [ - ["linux", "x64"], - ["win32", "x64"], - ["darwin", "x64"], - ["darwin", "arm64"] -]; -var CliError = class extends Error { - exitCode; - stderr; - constructor({ cmd, args, exitCode, stderr }) { - const prettyCommand = prettyPrintInvocation(cmd, args); - const fatalErrors = extractFatalErrors(stderr); - const autobuildErrors = extractAutobuildErrors(stderr); - let message; - if (fatalErrors) { - message = `Encountered a fatal error while running "${prettyCommand}". Exit code was ${exitCode} and error was: ${ensureEndsInPeriod( - fatalErrors.trim() - )} See the logs for more details.`; - } else if (autobuildErrors) { - message = `We were unable to automatically build your code. Please provide manual build steps. See ${"https://docs.github.com/en/code-security/code-scanning/troubleshooting-code-scanning/automatic-build-failed" /* AUTOMATIC_BUILD_FAILED */} for more information. Encountered the following error: ${autobuildErrors}`; - } else { - const lastLine = ensureEndsInPeriod( - stderr.trim().split("\n").pop()?.trim() || "n/a" - ); - message = `Encountered a fatal error while running "${prettyCommand}". Exit code was ${exitCode} and last log line was: ${lastLine} See the logs for more details.`; +// src/overlay/index.ts +var fs4 = __toESM(require("fs")); +var path4 = __toESM(require("path")); + +// src/git-utils.ts +var fs3 = __toESM(require("fs")); +var path3 = __toESM(require("path")); +var core6 = __toESM(require_core()); +var toolrunner2 = __toESM(require_toolrunner()); +var io3 = __toESM(require_io()); +var semver2 = __toESM(require_semver2()); +var runGitCommand = async function(workingDirectory, args, customErrorMessage, options) { + let stdout = ""; + let stderr = ""; + core6.debug(`Running git command: git ${args.join(" ")}`); + try { + await new toolrunner2.ToolRunner(await io3.which("git", true), args, { + silent: true, + listeners: { + stdout: (data) => { + stdout += data.toString(); + }, + stderr: (data) => { + stderr += data.toString(); + } + }, + cwd: workingDirectory, + ...options + }).exec(); + return stdout; + } catch (error3) { + let reason = stderr; + if (stderr.includes("not a git repository")) { + reason = "The checkout path provided to the action does not appear to be a git repository."; } - super(message); - this.exitCode = exitCode; - this.stderr = stderr; + core6.info(`git call failed. ${customErrorMessage} Error: ${reason}`); + throw error3; } }; -function extractFatalErrors(error3) { - const fatalErrorRegex = /.*fatal (internal )?error occurr?ed(. Details)?:/gi; - let fatalErrors = []; - let lastFatalErrorIndex; - let match; - while ((match = fatalErrorRegex.exec(error3)) !== null) { - if (lastFatalErrorIndex !== void 0) { - fatalErrors.push(error3.slice(lastFatalErrorIndex, match.index).trim()); - } - lastFatalErrorIndex = match.index; +var getCommitOid = async function(checkoutPath, ref = "HEAD") { + try { + const stdout = await runGitCommand( + checkoutPath, + ["rev-parse", ref], + "Continuing with commit SHA from user input or environment." + ); + return stdout.trim(); + } catch { + return getOptionalInput("sha") || getRequiredEnvParam("GITHUB_SHA"); } - if (lastFatalErrorIndex !== void 0) { - const lastError = error3.slice(lastFatalErrorIndex).trim(); - if (fatalErrors.length === 0) { - return lastError; +}; +var determineBaseBranchHeadCommitOid = async function(checkoutPathOverride) { + if (getWorkflowEventName() !== "pull_request") { + return void 0; + } + const mergeSha = getRequiredEnvParam("GITHUB_SHA"); + const checkoutPath = checkoutPathOverride ?? getOptionalInput("checkout_path"); + try { + let commitOid = ""; + let baseOid = ""; + let headOid = ""; + const stdout = await runGitCommand( + checkoutPath, + ["show", "-s", "--format=raw", mergeSha], + "Will calculate the base branch SHA on the server." + ); + for (const data of stdout.split("\n")) { + if (data.startsWith("commit ") && commitOid === "") { + commitOid = data.substring(7); + } else if (data.startsWith("parent ")) { + if (baseOid === "") { + baseOid = data.substring(7); + } else if (headOid === "") { + headOid = data.substring(7); + } + } } - const isOneLiner = !fatalErrors.some((e) => e.includes("\n")); - if (isOneLiner) { - fatalErrors = fatalErrors.map(ensureEndsInPeriod); + if (commitOid === mergeSha && headOid.length === 40 && baseOid.length === 40) { + return baseOid; } - return [ - ensureEndsInPeriod(lastError), - "Context:", - ...fatalErrors.reverse() - ].join(isOneLiner ? " " : "\n"); + return void 0; + } catch { + return void 0; } - return void 0; -} -function extractAutobuildErrors(error3) { - const pattern = /.*\[autobuild\] \[ERROR\] (.*)/gi; - let errorLines = [...error3.matchAll(pattern)].map((match) => match[1]); - if (errorLines.length > 10) { - errorLines = errorLines.slice(0, 10); - errorLines.push("(truncated)"); +}; +var decodeGitFilePath = function(filePath) { + if (filePath.startsWith('"') && filePath.endsWith('"')) { + filePath = filePath.substring(1, filePath.length - 1); + return filePath.replace( + /\\([abfnrtv\\"]|[0-7]{1,3})/g, + (_match, seq2) => { + switch (seq2[0]) { + case "a": + return "\x07"; + case "b": + return "\b"; + case "f": + return "\f"; + case "n": + return "\n"; + case "r": + return "\r"; + case "t": + return " "; + case "v": + return "\v"; + case "\\": + return "\\"; + case '"': + return '"'; + default: + return String.fromCharCode(parseInt(seq2, 8)); + } + } + ); } - return errorLines.join("\n") || void 0; -} -var cliErrorsConfig = { - ["AutobuildError" /* AutobuildError */]: { - cliErrorMessageCandidates: [ - new RegExp("We were unable to automatically build your code") - ] - }, - ["CouldNotCreateTempDir" /* CouldNotCreateTempDir */]: { - cliErrorMessageCandidates: [new RegExp("Could not create temp directory")] - }, - ["ExternalRepositoryCloneFailed" /* ExternalRepositoryCloneFailed */]: { - cliErrorMessageCandidates: [ - new RegExp("Failed to clone external Git repository") - ] - }, - ["GradleBuildFailed" /* GradleBuildFailed */]: { - cliErrorMessageCandidates: [ - new RegExp("\\[autobuild\\] FAILURE: Build failed with an exception.") - ] - }, - // Version of CodeQL CLI is incompatible with this version of the CodeQL Action - ["IncompatibleWithActionVersion" /* IncompatibleWithActionVersion */]: { - cliErrorMessageCandidates: [ - new RegExp("is not compatible with this CodeQL CLI") - ] - }, - ["InitCalledTwice" /* InitCalledTwice */]: { - cliErrorMessageCandidates: [ - new RegExp( - "Refusing to create databases .* but could not process any of it" - ) - ], - additionalErrorMessageToAppend: `Is the "init" action called twice in the same job?` - }, - ["InvalidConfigFile" /* InvalidConfigFile */]: { - cliErrorMessageCandidates: [ - new RegExp("Config file .* is not valid"), - new RegExp("The supplied config file is empty") - ] - }, - ["InvalidExternalRepoSpecifier" /* InvalidExternalRepoSpecifier */]: { - cliErrorMessageCandidates: [ - new RegExp("Specifier for external repository is invalid") - ] - }, - // Expected source location for database creation does not exist - ["InvalidSourceRoot" /* InvalidSourceRoot */]: { - cliErrorMessageCandidates: [new RegExp("Invalid source root")] - }, - ["MavenBuildFailed" /* MavenBuildFailed */]: { - cliErrorMessageCandidates: [ - new RegExp("\\[autobuild\\] \\[ERROR\\] Failed to execute goal") - ] - }, - ["NoBuildCommandAutodetected" /* NoBuildCommandAutodetected */]: { - cliErrorMessageCandidates: [ - new RegExp("Could not auto-detect a suitable build method") - ] - }, - ["NoBuildMethodAutodetected" /* NoBuildMethodAutodetected */]: { - cliErrorMessageCandidates: [ - new RegExp( - "Could not detect a suitable build command for the source checkout" - ) - ] - }, - // Usually when a manual build script has failed, or if an autodetected language - // was unintended to have CodeQL analysis run on it. - ["NoSourceCodeSeen" /* NoSourceCodeSeen */]: { - exitCode: 32, - cliErrorMessageCandidates: [ - new RegExp( - "CodeQL detected code written in .* but could not process any of it" - ), - new RegExp( - "CodeQL did not detect any code written in languages supported by CodeQL" - ) - ] - }, - ["NoSupportedBuildCommandSucceeded" /* NoSupportedBuildCommandSucceeded */]: { - cliErrorMessageCandidates: [ - new RegExp("No supported build command succeeded") - ] - }, - ["NoSupportedBuildSystemDetected" /* NoSupportedBuildSystemDetected */]: { - cliErrorMessageCandidates: [ - new RegExp("No supported build system detected") - ] - }, - ["OutOfMemoryOrDisk" /* OutOfMemoryOrDisk */]: { - cliErrorMessageCandidates: [ - new RegExp("CodeQL is out of memory."), - new RegExp("out of disk"), - new RegExp("No space left on device") - ], - additionalErrorMessageToAppend: "For more information, see https://gh.io/troubleshooting-code-scanning/out-of-disk-or-memory" - }, - ["PackCannotBeFound" /* PackCannotBeFound */]: { - cliErrorMessageCandidates: [ - new RegExp( - "Query pack .* cannot be found\\. Check the spelling of the pack\\." - ), - new RegExp( - "is not a .ql file, .qls file, a directory, or a query pack specification." - ) - ] - }, - ["PackMissingAuth" /* PackMissingAuth */]: { - cliErrorMessageCandidates: [ - new RegExp("GitHub Container registry .* 403 Forbidden"), - new RegExp( - "Do you need to specify a token to authenticate to the registry?" - ) - ] - }, - ["SwiftBuildFailed" /* SwiftBuildFailed */]: { - cliErrorMessageCandidates: [ - new RegExp( - "\\[autobuilder/build\\] \\[build-command-failed\\] `autobuild` failed to run the build command" - ) - ] - }, - ["SwiftIncompatibleOs" /* SwiftIncompatibleOs */]: { - cliErrorMessageCandidates: [ - new RegExp("\\[incompatible-os\\]"), - new RegExp("Swift analysis is only supported on macOS") - ] - }, - ["UnsupportedBuildMode" /* UnsupportedBuildMode */]: { - cliErrorMessageCandidates: [ - new RegExp( - "does not support the .* build mode. Please try using one of the following build modes instead" - ) - ] - }, - ["NotFoundInRegistry" /* NotFoundInRegistry */]: { - cliErrorMessageCandidates: [ - new RegExp("'.*' not found in the registry '.*'") - ] + return filePath; +}; +var getGitRoot = async function(sourceRoot) { + try { + const stdout = await runGitCommand( + sourceRoot, + ["rev-parse", "--show-toplevel"], + `Cannot find Git repository root from the source root ${sourceRoot}.` + ); + return stdout.trim(); + } catch { + return void 0; } }; -function getCliConfigCategoryIfExists(cliError) { - for (const [category, configuration] of Object.entries(cliErrorsConfig)) { - if (cliError.exitCode !== void 0 && configuration.exitCode !== void 0 && cliError.exitCode === configuration.exitCode) { - return category; - } - for (const e of configuration.cliErrorMessageCandidates) { - if (cliError.message.match(e) || cliError.stderr.match(e)) { - return category; +function hasSubmodules(gitRoot) { + return fs3.existsSync(path3.join(gitRoot, ".gitmodules")); +} +var getFileOidsUnderPath = async function(basePath) { + const gitRoot = await getGitRoot(basePath); + const mayHaveSubmodules = gitRoot === void 0 ? true : hasSubmodules(gitRoot); + const args = mayHaveSubmodules ? ["ls-files", "--recurse-submodules", "--stage"] : ["ls-files", "--stage"]; + const stdout = await runGitCommand( + basePath, + args, + "Cannot list Git OIDs of tracked files." + ); + const fileOidMap = {}; + const regex = /^[0-9]+ ([0-9a-f]{40}) [0-9]+\t(.+)$/; + for (const line of stdout.split("\n")) { + if (line) { + const match = line.match(regex); + if (match) { + const oid = match[1]; + const filePath = decodeGitFilePath(match[2]); + fileOidMap[filePath] = oid; + } else { + throw new Error(`Unexpected "git ls-files" output: ${line}`); } } } - return void 0; -} -function isUnsupportedPlatform() { - return !SUPPORTED_PLATFORMS.some( - ([platform2, arch2]) => platform2 === process.platform && arch2 === process.arch - ); -} -function getUnsupportedPlatformError(cliError) { - return new ConfigurationError( - `The CodeQL CLI does not support the platform/architecture combination of ${process.platform}/${process.arch} (see ${"https://codeql.github.com/docs/codeql-overview/system-requirements/" /* SYSTEM_REQUIREMENTS */}). The underlying error was: ${cliError.message}` - ); + return fileOidMap; +}; +function getRefFromEnv() { + let refEnv; + try { + refEnv = getRequiredEnvParam("GITHUB_REF"); + } catch (e) { + const maybeRef = process.env["CODE_SCANNING_REF"]; + if (maybeRef === void 0 || maybeRef.length === 0) { + throw e; + } + refEnv = maybeRef; + } + return refEnv; } -function wrapCliConfigurationError(cliError) { - if (isUnsupportedPlatform()) { - return getUnsupportedPlatformError(cliError); +async function getRef() { + const refInput = getOptionalInput("ref"); + const shaInput = getOptionalInput("sha"); + const checkoutPath = getOptionalInput("checkout_path") || getOptionalInput("source-root") || getRequiredEnvParam("GITHUB_WORKSPACE"); + const hasRefInput = !!refInput; + const hasShaInput = !!shaInput; + if ((hasRefInput || hasShaInput) && !(hasRefInput && hasShaInput)) { + throw new ConfigurationError( + "Both 'ref' and 'sha' are required if one of them is provided." + ); } - const cliConfigErrorCategory = getCliConfigCategoryIfExists(cliError); - if (cliConfigErrorCategory === void 0) { - return cliError; + const ref = refInput || getRefFromEnv(); + const sha = shaInput || getRequiredEnvParam("GITHUB_SHA"); + if (refInput) { + return refInput; } - let errorMessageBuilder = cliError.message; - const additionalErrorMessageToAppend = cliErrorsConfig[cliConfigErrorCategory].additionalErrorMessageToAppend; - if (additionalErrorMessageToAppend !== void 0) { - errorMessageBuilder = `${errorMessageBuilder} ${additionalErrorMessageToAppend}`; + const pull_ref_regex = /refs\/pull\/(\d+)\/merge/; + if (!pull_ref_regex.test(ref)) { + return ref; + } + const head = await getCommitOid(checkoutPath, "HEAD"); + const hasChangedRef = sha !== head && await getCommitOid( + checkoutPath, + ref.replace(/^refs\/pull\//, "refs/remotes/pull/") + ) !== head; + if (hasChangedRef) { + const newRef = ref.replace(pull_ref_regex, "refs/pull/$1/head"); + core6.debug( + `No longer on merge commit, rewriting ref from ${ref} to ${newRef}.` + ); + return newRef; + } else { + return ref; } - return new ConfigurationError(errorMessageBuilder); } - -// src/config-utils.ts -var fs7 = __toESM(require("fs")); -var path7 = __toESM(require("path")); -var core9 = __toESM(require_core()); - -// src/caching-utils.ts -var crypto2 = __toESM(require("crypto")); -var core6 = __toESM(require_core()); -async function getTotalCacheSize(paths, logger, quiet = false) { - const sizes = await Promise.all( - paths.map((cacheDir) => tryGetFolderBytes(cacheDir, logger, quiet)) - ); - return sizes.map((a) => a || 0).reduce((a, b) => a + b, 0); -} -function shouldStoreCache(kind) { - return kind === "full" /* Full */ || kind === "store" /* Store */; +function removeRefsHeadsPrefix(ref) { + return ref.startsWith("refs/heads/") ? ref.slice("refs/heads/".length) : ref; } -var cacheKeyHashLength = 16; -function createCacheKeyHash(components) { - const componentsJson = JSON.stringify(components); - return crypto2.createHash("sha256").update(componentsJson).digest("hex").substring(0, cacheKeyHashLength); +async function isAnalyzingDefaultBranch() { + if (process.env.CODE_SCANNING_IS_ANALYZING_DEFAULT_BRANCH === "true") { + return true; + } + let currentRef = await getRef(); + currentRef = removeRefsHeadsPrefix(currentRef); + const event = getWorkflowEvent(); + let defaultBranch = event?.repository?.default_branch; + if (getWorkflowEventName() === "schedule") { + defaultBranch = removeRefsHeadsPrefix(getRefFromEnv()); + } + return currentRef === defaultBranch; } -// src/config/db-config.ts -var jsonschema = __toESM(require_lib2()); -var semver2 = __toESM(require_semver2()); - -// src/feature-flags/properties.ts -var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => { - RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay"; - RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries"; - RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs"; - return RepositoryPropertyName2; -})(RepositoryPropertyName || {}); -var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set( - Object.values(RepositoryPropertyName) -); - -// src/config/db-config.ts -var PACK_IDENTIFIER_PATTERN = (function() { - const alphaNumeric = "[a-z0-9]"; - const alphaNumericDash = "[a-z0-9-]"; - const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`; - return new RegExp(`^${component}/${component}$`); -})(); - -// src/diagnostics.ts -var import_fs = require("fs"); -var import_path = __toESM(require("path")); - -// src/logging.ts -var core7 = __toESM(require_core()); -function getActionsLogger() { - return { - debug: core7.debug, - info: core7.info, - warning: core7.warning, - error: core7.error, - isDebug: core7.isDebug, - startGroup: core7.startGroup, - endGroup: core7.endGroup - }; +// src/overlay/index.ts +var CODEQL_OVERLAY_MINIMUM_VERSION = "2.23.8"; +var CODEQL_OVERLAY_MINIMUM_VERSION_CPP = "2.25.0"; +var CODEQL_OVERLAY_MINIMUM_VERSION_CSHARP = "2.24.1"; +var CODEQL_OVERLAY_MINIMUM_VERSION_GO = "2.24.2"; +var CODEQL_OVERLAY_MINIMUM_VERSION_JAVA = "2.23.8"; +var CODEQL_OVERLAY_MINIMUM_VERSION_JAVASCRIPT = "2.23.9"; +var CODEQL_OVERLAY_MINIMUM_VERSION_PYTHON = "2.23.9"; +var CODEQL_OVERLAY_MINIMUM_VERSION_RUBY = "2.23.9"; +async function writeBaseDatabaseOidsFile(config, sourceRoot) { + const gitFileOids = await getFileOidsUnderPath(sourceRoot); + const gitFileOidsJson = JSON.stringify(gitFileOids); + const baseDatabaseOidsFilePath = getBaseDatabaseOidsFilePath(config); + await fs4.promises.writeFile(baseDatabaseOidsFilePath, gitFileOidsJson); } -async function withGroupAsync(groupName, f) { - core7.startGroup(groupName); +async function readBaseDatabaseOidsFile(config, logger) { + const baseDatabaseOidsFilePath = getBaseDatabaseOidsFilePath(config); try { - return await f(); - } finally { - core7.endGroup(); + const contents = await fs4.promises.readFile( + baseDatabaseOidsFilePath, + "utf-8" + ); + return JSON.parse(contents); + } catch (e) { + logger.error( + `Failed to read overlay-base file OIDs from ${baseDatabaseOidsFilePath}: ${e.message || e}` + ); + throw e; } } -function formatDuration(durationMs) { - if (durationMs < 1e3) { - return `${durationMs}ms`; +async function writeOverlayChangesFile(config, sourceRoot, logger) { + const baseFileOids = await readBaseDatabaseOidsFile(config, logger); + const overlayFileOids = await getFileOidsUnderPath(sourceRoot); + const oidChangedFiles = computeChangedFiles(baseFileOids, overlayFileOids); + logger.info( + `Found ${oidChangedFiles.length} changed file(s) under ${sourceRoot} from OID comparison.` + ); + const diffRangeFiles = await getDiffRangeFilePaths(sourceRoot, logger); + const changedFiles = [.../* @__PURE__ */ new Set([...oidChangedFiles, ...diffRangeFiles])]; + const changedFilesJson = JSON.stringify({ changes: changedFiles }); + const overlayChangesFile = path4.join( + getTemporaryDirectory(), + "overlay-changes.json" + ); + logger.debug( + `Writing overlay changed files to ${overlayChangesFile}: ${changedFilesJson}` + ); + await fs4.promises.writeFile(overlayChangesFile, changedFilesJson); + return overlayChangesFile; +} +function computeChangedFiles(baseFileOids, overlayFileOids) { + const changes = []; + for (const [file, oid] of Object.entries(overlayFileOids)) { + if (!(file in baseFileOids) || baseFileOids[file] !== oid) { + changes.push(file); + } } - if (durationMs < 60 * 1e3) { - return `${(durationMs / 1e3).toFixed(1)}s`; + for (const file of Object.keys(baseFileOids)) { + if (!(file in overlayFileOids)) { + changes.push(file); + } } - const minutes = Math.floor(durationMs / (60 * 1e3)); - const seconds = Math.floor(durationMs % (60 * 1e3) / 1e3); - return `${minutes}m${seconds}s`; -} - -// src/diagnostics.ts -var unwrittenDiagnostics = []; -var unwrittenDefaultLanguageDiagnostics = []; -var diagnosticCounter = 0; -function makeDiagnostic(id, name, data = void 0) { - return { - ...data, - timestamp: data?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(), - source: { ...data?.source, id, name } - }; + return changes; } -function addDiagnostic(config, language, diagnostic) { - const logger = getActionsLogger(); - const databasePath = language ? getCodeQLDatabasePath(config, language) : config.dbLocation; - if ((0, import_fs.existsSync)(databasePath)) { - writeDiagnostic(config, language, diagnostic); - } else { +async function getDiffRangeFilePaths(sourceRoot, logger) { + const jsonFilePath = getDiffRangesJsonFilePath(); + if (!fs4.existsSync(jsonFilePath)) { logger.debug( - `Writing a diagnostic for ${language}, but the database at ${databasePath} does not exist yet.` + `No diff ranges JSON file found at ${jsonFilePath}; skipping.` ); - unwrittenDiagnostics.push({ diagnostic, language }); + return []; } -} -function addNoLanguageDiagnostic(config, diagnostic) { - if (config !== void 0) { - addDiagnostic( - config, - // Arbitrarily choose the first language. We could also choose all languages, but that - // increases the risk of misinterpreting the data. - config.languages[0], - diagnostic + let contents; + try { + contents = await fs4.promises.readFile(jsonFilePath, "utf8"); + } catch (e) { + logger.warning( + `Failed to read diff ranges JSON file at ${jsonFilePath}: ${e}` ); - } else { - unwrittenDefaultLanguageDiagnostics.push(diagnostic); + return []; } -} -function writeDiagnostic(config, language, diagnostic) { - const logger = getActionsLogger(); - const databasePath = language ? getCodeQLDatabasePath(config, language) : config.dbLocation; - const diagnosticsPath = import_path.default.resolve( - databasePath, - "diagnostic", - "codeql-action" - ); + let diffRanges; try { - (0, import_fs.mkdirSync)(diagnosticsPath, { recursive: true }); - const uniqueSuffix = (diagnosticCounter++).toString(); - const sanitizedTimestamp = diagnostic.timestamp.replace( - /[^a-zA-Z0-9.-]/g, - "" + diffRanges = JSON.parse(contents); + } catch (e) { + logger.warning( + `Failed to parse diff ranges JSON file at ${jsonFilePath}: ${e}` ); - const jsonPath = import_path.default.resolve( - diagnosticsPath, - `codeql-action-${sanitizedTimestamp}-${uniqueSuffix}.json` + return []; + } + logger.debug( + `Read ${diffRanges.length} diff range(s) from ${jsonFilePath} for overlay changes.` + ); + const repoRoot = await getGitRoot(sourceRoot); + if (repoRoot === void 0) { + if (getOptionalInput("source-root")) { + throw new Error( + "Cannot determine git root to convert diff range paths relative to source-root. Failing to avoid omitting files from the analysis." + ); + } + logger.warning( + "Cannot determine git root; returning diff range paths as-is." ); - (0, import_fs.writeFileSync)(jsonPath, JSON.stringify(diagnostic)); - } catch (err) { - logger.warning(`Unable to write diagnostic message to database: ${err}`); - logger.debug(JSON.stringify(diagnostic)); + return [...new Set(diffRanges.map((r) => r.path))]; } + const relativePaths = diffRanges.map( + (r) => path4.relative(sourceRoot, path4.join(repoRoot, r.path)).replaceAll(path4.sep, "/") + ).filter((rel) => !rel.startsWith("..")); + return [...new Set(relativePaths)]; } -// src/diff-informed-analysis-utils.ts -var fs6 = __toESM(require("fs")); - -// src/feature-flags.ts -var fs5 = __toESM(require("fs")); -var path6 = __toESM(require("path")); -var semver5 = __toESM(require_semver2()); - -// src/defaults.json -var bundleVersion = "codeql-bundle-v2.25.4"; -var cliVersion = "2.25.4"; - -// src/overlay/index.ts -var fs4 = __toESM(require("fs")); -var path5 = __toESM(require("path")); - -// src/git-utils.ts -var fs3 = __toESM(require("fs")); -var path4 = __toESM(require("path")); -var core8 = __toESM(require_core()); -var toolrunner2 = __toESM(require_toolrunner()); -var io3 = __toESM(require_io()); -var semver3 = __toESM(require_semver2()); -var runGitCommand = async function(workingDirectory, args, customErrorMessage, options) { - let stdout = ""; - let stderr = ""; - core8.debug(`Running git command: git ${args.join(" ")}`); - try { - await new toolrunner2.ToolRunner(await io3.which("git", true), args, { - silent: true, - listeners: { - stdout: (data) => { - stdout += data.toString(); - }, - stderr: (data) => { - stderr += data.toString(); - } - }, - cwd: workingDirectory, - ...options - }).exec(); - return stdout; - } catch (error3) { - let reason = stderr; - if (stderr.includes("not a git repository")) { - reason = "The checkout path provided to the action does not appear to be a git repository."; - } - core8.info(`git call failed. ${customErrorMessage} Error: ${reason}`); - throw error3; - } -}; -var getCommitOid = async function(checkoutPath, ref = "HEAD") { - try { - const stdout = await runGitCommand( - checkoutPath, - ["rev-parse", ref], - "Continuing with commit SHA from user input or environment." - ); - return stdout.trim(); - } catch { - return getOptionalInput("sha") || getRequiredEnvParam("GITHUB_SHA"); - } -}; -var determineBaseBranchHeadCommitOid = async function(checkoutPathOverride) { - if (getWorkflowEventName() !== "pull_request") { - return void 0; - } - const mergeSha = getRequiredEnvParam("GITHUB_SHA"); - const checkoutPath = checkoutPathOverride ?? getOptionalInput("checkout_path"); - try { - let commitOid = ""; - let baseOid = ""; - let headOid = ""; - const stdout = await runGitCommand( - checkoutPath, - ["show", "-s", "--format=raw", mergeSha], - "Will calculate the base branch SHA on the server." - ); - for (const data of stdout.split("\n")) { - if (data.startsWith("commit ") && commitOid === "") { - commitOid = data.substring(7); - } else if (data.startsWith("parent ")) { - if (baseOid === "") { - baseOid = data.substring(7); - } else if (headOid === "") { - headOid = data.substring(7); - } - } - } - if (commitOid === mergeSha && headOid.length === 40 && baseOid.length === 40) { - return baseOid; - } - return void 0; - } catch { - return void 0; - } -}; -var decodeGitFilePath = function(filePath) { - if (filePath.startsWith('"') && filePath.endsWith('"')) { - filePath = filePath.substring(1, filePath.length - 1); - return filePath.replace( - /\\([abfnrtv\\"]|[0-7]{1,3})/g, - (_match, seq2) => { - switch (seq2[0]) { - case "a": - return "\x07"; - case "b": - return "\b"; - case "f": - return "\f"; - case "n": - return "\n"; - case "r": - return "\r"; - case "t": - return " "; - case "v": - return "\v"; - case "\\": - return "\\"; - case '"': - return '"'; - default: - return String.fromCharCode(parseInt(seq2, 8)); - } - } - ); - } - return filePath; -}; -var getGitRoot = async function(sourceRoot) { - try { - const stdout = await runGitCommand( - sourceRoot, - ["rev-parse", "--show-toplevel"], - `Cannot find Git repository root from the source root ${sourceRoot}.` - ); - return stdout.trim(); - } catch { - return void 0; - } -}; -function hasSubmodules(gitRoot) { - return fs3.existsSync(path4.join(gitRoot, ".gitmodules")); -} -var getFileOidsUnderPath = async function(basePath) { - const gitRoot = await getGitRoot(basePath); - const mayHaveSubmodules = gitRoot === void 0 ? true : hasSubmodules(gitRoot); - const args = mayHaveSubmodules ? ["ls-files", "--recurse-submodules", "--stage"] : ["ls-files", "--stage"]; - const stdout = await runGitCommand( - basePath, - args, - "Cannot list Git OIDs of tracked files." - ); - const fileOidMap = {}; - const regex = /^[0-9]+ ([0-9a-f]{40}) [0-9]+\t(.+)$/; - for (const line of stdout.split("\n")) { - if (line) { - const match = line.match(regex); - if (match) { - const oid = match[1]; - const filePath = decodeGitFilePath(match[2]); - fileOidMap[filePath] = oid; - } else { - throw new Error(`Unexpected "git ls-files" output: ${line}`); - } - } - } - return fileOidMap; -}; -function getRefFromEnv() { - let refEnv; - try { - refEnv = getRequiredEnvParam("GITHUB_REF"); - } catch (e) { - const maybeRef = process.env["CODE_SCANNING_REF"]; - if (maybeRef === void 0 || maybeRef.length === 0) { - throw e; - } - refEnv = maybeRef; - } - return refEnv; -} -async function getRef() { - const refInput = getOptionalInput("ref"); - const shaInput = getOptionalInput("sha"); - const checkoutPath = getOptionalInput("checkout_path") || getOptionalInput("source-root") || getRequiredEnvParam("GITHUB_WORKSPACE"); - const hasRefInput = !!refInput; - const hasShaInput = !!shaInput; - if ((hasRefInput || hasShaInput) && !(hasRefInput && hasShaInput)) { - throw new ConfigurationError( - "Both 'ref' and 'sha' are required if one of them is provided." - ); - } - const ref = refInput || getRefFromEnv(); - const sha = shaInput || getRequiredEnvParam("GITHUB_SHA"); - if (refInput) { - return refInput; - } - const pull_ref_regex = /refs\/pull\/(\d+)\/merge/; - if (!pull_ref_regex.test(ref)) { - return ref; - } - const head = await getCommitOid(checkoutPath, "HEAD"); - const hasChangedRef = sha !== head && await getCommitOid( - checkoutPath, - ref.replace(/^refs\/pull\//, "refs/remotes/pull/") - ) !== head; - if (hasChangedRef) { - const newRef = ref.replace(pull_ref_regex, "refs/pull/$1/head"); - core8.debug( - `No longer on merge commit, rewriting ref from ${ref} to ${newRef}.` - ); - return newRef; - } else { - return ref; - } -} -function removeRefsHeadsPrefix(ref) { - return ref.startsWith("refs/heads/") ? ref.slice("refs/heads/".length) : ref; -} -async function isAnalyzingDefaultBranch() { - if (process.env.CODE_SCANNING_IS_ANALYZING_DEFAULT_BRANCH === "true") { - return true; - } - let currentRef = await getRef(); - currentRef = removeRefsHeadsPrefix(currentRef); - const event = getWorkflowEvent(); - let defaultBranch = event?.repository?.default_branch; - if (getWorkflowEventName() === "schedule") { - defaultBranch = removeRefsHeadsPrefix(getRefFromEnv()); - } - return currentRef === defaultBranch; -} - -// src/overlay/index.ts -var CODEQL_OVERLAY_MINIMUM_VERSION = "2.23.8"; -var CODEQL_OVERLAY_MINIMUM_VERSION_CPP = "2.25.0"; -var CODEQL_OVERLAY_MINIMUM_VERSION_CSHARP = "2.24.1"; -var CODEQL_OVERLAY_MINIMUM_VERSION_GO = "2.24.2"; -var CODEQL_OVERLAY_MINIMUM_VERSION_JAVA = "2.23.8"; -var CODEQL_OVERLAY_MINIMUM_VERSION_JAVASCRIPT = "2.23.9"; -var CODEQL_OVERLAY_MINIMUM_VERSION_PYTHON = "2.23.9"; -var CODEQL_OVERLAY_MINIMUM_VERSION_RUBY = "2.23.9"; -async function writeBaseDatabaseOidsFile(config, sourceRoot) { - const gitFileOids = await getFileOidsUnderPath(sourceRoot); - const gitFileOidsJson = JSON.stringify(gitFileOids); - const baseDatabaseOidsFilePath = getBaseDatabaseOidsFilePath(config); - await fs4.promises.writeFile(baseDatabaseOidsFilePath, gitFileOidsJson); -} -async function readBaseDatabaseOidsFile(config, logger) { - const baseDatabaseOidsFilePath = getBaseDatabaseOidsFilePath(config); - try { - const contents = await fs4.promises.readFile( - baseDatabaseOidsFilePath, - "utf-8" - ); - return JSON.parse(contents); - } catch (e) { - logger.error( - `Failed to read overlay-base file OIDs from ${baseDatabaseOidsFilePath}: ${e.message || e}` - ); - throw e; - } -} -async function writeOverlayChangesFile(config, sourceRoot, logger) { - const baseFileOids = await readBaseDatabaseOidsFile(config, logger); - const overlayFileOids = await getFileOidsUnderPath(sourceRoot); - const oidChangedFiles = computeChangedFiles(baseFileOids, overlayFileOids); - logger.info( - `Found ${oidChangedFiles.length} changed file(s) under ${sourceRoot} from OID comparison.` - ); - const diffRangeFiles = await getDiffRangeFilePaths(sourceRoot, logger); - const changedFiles = [.../* @__PURE__ */ new Set([...oidChangedFiles, ...diffRangeFiles])]; - const changedFilesJson = JSON.stringify({ changes: changedFiles }); - const overlayChangesFile = path5.join( - getTemporaryDirectory(), - "overlay-changes.json" - ); - logger.debug( - `Writing overlay changed files to ${overlayChangesFile}: ${changedFilesJson}` - ); - await fs4.promises.writeFile(overlayChangesFile, changedFilesJson); - return overlayChangesFile; -} -function computeChangedFiles(baseFileOids, overlayFileOids) { - const changes = []; - for (const [file, oid] of Object.entries(overlayFileOids)) { - if (!(file in baseFileOids) || baseFileOids[file] !== oid) { - changes.push(file); - } - } - for (const file of Object.keys(baseFileOids)) { - if (!(file in overlayFileOids)) { - changes.push(file); - } - } - return changes; -} -async function getDiffRangeFilePaths(sourceRoot, logger) { - const jsonFilePath = getDiffRangesJsonFilePath(); - if (!fs4.existsSync(jsonFilePath)) { - logger.debug( - `No diff ranges JSON file found at ${jsonFilePath}; skipping.` - ); - return []; - } - let contents; - try { - contents = await fs4.promises.readFile(jsonFilePath, "utf8"); - } catch (e) { - logger.warning( - `Failed to read diff ranges JSON file at ${jsonFilePath}: ${e}` - ); - return []; - } - let diffRanges; - try { - diffRanges = JSON.parse(contents); - } catch (e) { - logger.warning( - `Failed to parse diff ranges JSON file at ${jsonFilePath}: ${e}` - ); - return []; - } - logger.debug( - `Read ${diffRanges.length} diff range(s) from ${jsonFilePath} for overlay changes.` - ); - const repoRoot = await getGitRoot(sourceRoot); - if (repoRoot === void 0) { - if (getOptionalInput("source-root")) { - throw new Error( - "Cannot determine git root to convert diff range paths relative to source-root. Failing to avoid omitting files from the analysis." - ); - } - logger.warning( - "Cannot determine git root; returning diff range paths as-is." - ); - return [...new Set(diffRanges.map((r) => r.path))]; - } - const relativePaths = diffRanges.map( - (r) => path5.relative(sourceRoot, path5.join(repoRoot, r.path)).replaceAll(path5.sep, "/") - ).filter((rel) => !rel.startsWith("..")); - return [...new Set(relativePaths)]; -} - -// src/tools-features.ts -var semver4 = __toESM(require_semver2()); -function isSupportedToolsFeature(versionInfo, feature) { - return !!versionInfo.features && versionInfo.features[feature]; -} +// src/tools-features.ts +var semver3 = __toESM(require_semver2()); +function isSupportedToolsFeature(versionInfo, feature) { + return !!versionInfo.features && versionInfo.features[feature]; +} // src/feature-flags.ts var DEFAULT_VERSION_FEATURE_FLAG_PREFIX = "default_codeql_version_"; var DEFAULT_VERSION_FEATURE_FLAG_SUFFIX = "_enabled"; var CODEQL_VERSION_ZSTD_BUNDLE = "2.19.0"; var featureConfig = { + ["allow_multiple_analysis_kinds" /* AllowMultipleAnalysisKinds */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_ALLOW_MULTIPLE_ANALYSIS_KINDS", + minimumVersion: void 0 + }, ["allow_toolcache_input" /* AllowToolcacheInput */]: { defaultValue: false, envVar: "CODEQL_ACTION_ALLOW_TOOLCACHE_INPUT", @@ -90332,297 +89856,776 @@ var OfflineFeatures = class { } return this.getDefaultValue(feature); } - /** - * Determines whether `feature` is enabled using the CLI and environment variables. - */ - async getOfflineValue(feature, codeql) { - const config = this.getFeatureConfig(feature); - if (!codeql && config.minimumVersion) { - throw new Error( - `Internal error: A minimum version is specified for feature ${feature}, but no instance of CodeQL was provided.` + /** + * Determines whether `feature` is enabled using the CLI and environment variables. + */ + async getOfflineValue(feature, codeql) { + const config = this.getFeatureConfig(feature); + if (!codeql && config.minimumVersion) { + throw new Error( + `Internal error: A minimum version is specified for feature ${feature}, but no instance of CodeQL was provided.` + ); + } + if (!codeql && config.toolsFeature) { + throw new Error( + `Internal error: A required tools feature is specified for feature ${feature}, but no instance of CodeQL was provided.` + ); + } + const envVar = (process.env[config.envVar] || "").toLocaleLowerCase(); + if (envVar === "false") { + this.logger.debug( + `Feature ${feature} is disabled via the environment variable ${config.envVar}.` + ); + return false; + } + const minimumVersion = config.minimumVersion; + if (codeql && minimumVersion) { + if (!await codeQlVersionAtLeast(codeql, minimumVersion)) { + this.logger.debug( + `Feature ${feature} is disabled because the CodeQL CLI version is older than the minimum version ${minimumVersion}.` + ); + return false; + } else { + this.logger.debug( + `CodeQL CLI version ${(await codeql.getVersion()).version} is newer than the minimum version ${minimumVersion} for feature ${feature}.` + ); + } + } + const toolsFeature = config.toolsFeature; + if (codeql && toolsFeature) { + if (!await codeql.supportsFeature(toolsFeature)) { + this.logger.debug( + `Feature ${feature} is disabled because the CodeQL CLI version does not support the required tools feature ${toolsFeature}.` + ); + return false; + } else { + this.logger.debug( + `CodeQL CLI version ${(await codeql.getVersion()).version} supports the required tools feature ${toolsFeature} for feature ${feature}.` + ); + } + } + if (envVar === "true") { + this.logger.debug( + `Feature ${feature} is enabled via the environment variable ${config.envVar}.` + ); + return true; + } + return void 0; + } + /** Gets the default value of `feature`. */ + async getDefaultValue(feature) { + const config = this.getFeatureConfig(feature); + const defaultValue = config.defaultValue; + this.logger.debug( + `Feature ${feature} is ${defaultValue ? "enabled" : "disabled"} due to its default value.` + ); + return defaultValue; + } +}; +var Features = class extends OfflineFeatures { + gitHubFeatureFlags; + constructor(repositoryNwo, tempDir, logger) { + super(logger); + this.gitHubFeatureFlags = new GitHubFeatureFlags( + repositoryNwo, + path5.join(tempDir, FEATURE_FLAGS_FILE_NAME), + logger + ); + } + async getDefaultCliVersion(variant) { + if (supportsFeatureFlags(variant)) { + return await this.gitHubFeatureFlags.getDefaultCliVersionFromFlags(); + } + return super.getDefaultCliVersion(variant); + } + /** + * + * @param feature The feature to check. + * @param codeql An optional CodeQL object. If provided, and a `minimumVersion` is specified for the + * feature, the version of the CodeQL CLI will be checked against the minimum version. + * If the version is less than the minimum version, the feature will be considered + * disabled. If not provided, and a `minimumVersion` is specified for the feature, then + * this function will throw. + * @returns true if the feature is enabled, false otherwise. + * + * @throws if a `minimumVersion` is specified for the feature, and `codeql` is not provided. + */ + async getValue(feature, codeql) { + const offlineValue = await this.getOfflineValue(feature, codeql); + if (offlineValue !== void 0) { + return offlineValue; + } + const apiValue = await this.gitHubFeatureFlags.getValue(feature); + if (apiValue !== void 0) { + this.logger.debug( + `Feature ${feature} is ${apiValue ? "enabled" : "disabled"} via the GitHub API.` + ); + return apiValue; + } + return this.getDefaultValue(feature); + } +}; +var GitHubFeatureFlags = class { + constructor(repositoryNwo, featureFlagsFile, logger) { + this.repositoryNwo = repositoryNwo; + this.featureFlagsFile = featureFlagsFile; + this.logger = logger; + this.hasAccessedRemoteFeatureFlags = false; + } + repositoryNwo; + featureFlagsFile; + logger; + cachedApiResponse; + // We cache whether the feature flags were accessed or not in order to accurately report whether flags were + // incorrectly configured vs. inaccessible in our telemetry. + hasAccessedRemoteFeatureFlags; + getCliVersionFromFeatureFlag(f) { + if (!f.startsWith(DEFAULT_VERSION_FEATURE_FLAG_PREFIX) || !f.endsWith(DEFAULT_VERSION_FEATURE_FLAG_SUFFIX)) { + return void 0; + } + const version = f.substring( + DEFAULT_VERSION_FEATURE_FLAG_PREFIX.length, + f.length - DEFAULT_VERSION_FEATURE_FLAG_SUFFIX.length + ).replace(/_/g, "."); + if (!semver4.valid(version)) { + this.logger.warning( + `Ignoring feature flag ${f} as it does not specify a valid CodeQL version.` + ); + return void 0; + } + return version; + } + async getDefaultCliVersionFromFlags() { + const response = await this.getAllFeatures(); + const enabledFeatureFlagCliVersions = Object.entries(response).map( + ([f, isEnabled]) => isEnabled ? this.getCliVersionFromFeatureFlag(f) : void 0 + ).filter((f) => f !== void 0); + if (enabledFeatureFlagCliVersions.length === 0) { + this.logger.warning( + `Feature flags do not specify a default CLI version. Falling back to the CLI version shipped with the Action. This is ${cliVersion}.` + ); + const result = { + cliVersion, + tagName: bundleVersion + }; + if (this.hasAccessedRemoteFeatureFlags) { + result.toolsFeatureFlagsValid = false; + } + return result; + } + const maxCliVersion = enabledFeatureFlagCliVersions.reduce( + (maxVersion, currentVersion) => currentVersion > maxVersion ? currentVersion : maxVersion, + enabledFeatureFlagCliVersions[0] + ); + this.logger.debug( + `Derived default CLI version of ${maxCliVersion} from feature flags.` + ); + return { + cliVersion: maxCliVersion, + tagName: `codeql-bundle-v${maxCliVersion}`, + toolsFeatureFlagsValid: true + }; + } + async getValue(feature) { + const response = await this.getAllFeatures(); + if (response === void 0) { + this.logger.debug(`No feature flags API response for ${feature}.`); + return void 0; + } + const features = response[feature]; + if (features === void 0) { + this.logger.debug(`Feature '${feature}' undefined in API response.`); + return void 0; + } + return !!features; + } + async getAllFeatures() { + if (this.cachedApiResponse !== void 0) { + return this.cachedApiResponse; + } + const fileFlags = await this.readLocalFlags(); + if (fileFlags !== void 0) { + this.cachedApiResponse = fileFlags; + return fileFlags; + } + let remoteFlags = await this.loadApiResponse(); + if (remoteFlags === void 0) { + remoteFlags = {}; + } + this.cachedApiResponse = remoteFlags; + await this.writeLocalFlags(remoteFlags); + return remoteFlags; + } + async readLocalFlags() { + try { + if (fs5.existsSync(this.featureFlagsFile)) { + this.logger.debug( + `Loading feature flags from ${this.featureFlagsFile}` + ); + return JSON.parse( + fs5.readFileSync(this.featureFlagsFile, "utf8") + ); + } + } catch (e) { + this.logger.warning( + `Error reading cached feature flags file ${this.featureFlagsFile}: ${e}. Requesting from GitHub instead.` ); } - if (!codeql && config.toolsFeature) { - throw new Error( - `Internal error: A required tools feature is specified for feature ${feature}, but no instance of CodeQL was provided.` + return void 0; + } + async writeLocalFlags(flags) { + try { + this.logger.debug(`Writing feature flags to ${this.featureFlagsFile}`); + fs5.writeFileSync(this.featureFlagsFile, JSON.stringify(flags)); + } catch (e) { + this.logger.warning( + `Error writing cached feature flags file ${this.featureFlagsFile}: ${e}.` ); } - const envVar = (process.env[config.envVar] || "").toLocaleLowerCase(); - if (envVar === "false") { + } + async loadApiResponse() { + try { + const featuresToRequest = Object.entries(featureConfig).filter( + ([, config]) => !config.legacyApi + ).map(([f]) => f); + const FEATURES_PER_REQUEST = 25; + const featureChunks = []; + while (featuresToRequest.length > 0) { + featureChunks.push(featuresToRequest.splice(0, FEATURES_PER_REQUEST)); + } + let remoteFlags = {}; + for (const chunk of featureChunks) { + const response = await getApiClient().request( + "GET /repos/:owner/:repo/code-scanning/codeql-action/features", + { + owner: this.repositoryNwo.owner, + repo: this.repositoryNwo.repo, + features: chunk.join(",") + } + ); + const chunkFlags = response.data; + remoteFlags = { ...remoteFlags, ...chunkFlags }; + } this.logger.debug( - `Feature ${feature} is disabled via the environment variable ${config.envVar}.` + "Loaded the following default values for the feature flags from the CodeQL Action API:" ); - return false; - } - const minimumVersion = config.minimumVersion; - if (codeql && minimumVersion) { - if (!await codeQlVersionAtLeast(codeql, minimumVersion)) { - this.logger.debug( - `Feature ${feature} is disabled because the CodeQL CLI version is older than the minimum version ${minimumVersion}.` - ); - return false; - } else { - this.logger.debug( - `CodeQL CLI version ${(await codeql.getVersion()).version} is newer than the minimum version ${minimumVersion} for feature ${feature}.` - ); + for (const [feature, value] of Object.entries(remoteFlags).sort( + ([nameA], [nameB]) => nameA.localeCompare(nameB) + )) { + this.logger.debug(` ${feature}: ${value}`); } - } - const toolsFeature = config.toolsFeature; - if (codeql && toolsFeature) { - if (!await codeql.supportsFeature(toolsFeature)) { - this.logger.debug( - `Feature ${feature} is disabled because the CodeQL CLI version does not support the required tools feature ${toolsFeature}.` + this.hasAccessedRemoteFeatureFlags = true; + return remoteFlags; + } catch (e) { + const httpError = asHTTPError(e); + if (httpError?.status === 403) { + this.logger.warning( + `This run of the CodeQL Action does not have permission to access the CodeQL Action API endpoints. As a result, it will not be opted into any experimental features. This could be because the Action is running on a pull request from a fork. If not, please ensure the workflow has at least the 'security-events: read' permission. Details: ${httpError.message}` ); - return false; + this.hasAccessedRemoteFeatureFlags = false; + return {}; } else { - this.logger.debug( - `CodeQL CLI version ${(await codeql.getVersion()).version} supports the required tools feature ${toolsFeature} for feature ${feature}.` + throw new Error( + `Encountered an error while trying to determine feature enablement: ${e}` ); } } - if (envVar === "true") { - this.logger.debug( - `Feature ${feature} is enabled via the environment variable ${config.envVar}.` - ); - return true; - } - return void 0; } - /** Gets the default value of `feature`. */ - async getDefaultValue(feature) { - const config = this.getFeatureConfig(feature); - const defaultValue = config.defaultValue; - this.logger.debug( - `Feature ${feature} is ${defaultValue ? "enabled" : "disabled"} due to its default value.` +}; +function supportsFeatureFlags(githubVariant) { + return githubVariant === "GitHub.com" /* DOTCOM */ || githubVariant === "GitHub Enterprise Cloud with data residency" /* GHEC_DR */; +} +function initFeatures(gitHubVersion, repositoryNwo, tempDir, logger) { + if (!supportsFeatureFlags(gitHubVersion.type)) { + logger.debug( + "Not running against github.com. Using default values for all features." ); - return defaultValue; + return new OfflineFeatures(logger); + } else { + return new Features(repositoryNwo, tempDir, logger); } +} + +// src/analyses.ts +var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { + AnalysisKind2["CodeScanning"] = "code-scanning"; + AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["RiskAssessment"] = "risk-assessment"; + return AnalysisKind2; +})(AnalysisKind || {}); +var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); +var codeQualityQueries = ["code-quality"]; +var CodeScanning = { + kind: "code-scanning" /* CodeScanning */, + name: "code scanning", + target: "PUT /repos/:owner/:repo/code-scanning/analysis" /* CODE_SCANNING */, + sarifExtension: ".sarif", + sarifPredicate: (name) => name.endsWith(CodeScanning.sarifExtension) && !CodeQuality.sarifPredicate(name) && !RiskAssessment.sarifPredicate(name), + fixCategory: (_, category) => category, + sentinelPrefix: "CODEQL_UPLOAD_SARIF_", + transformPayload: (payload) => payload }; -var Features = class extends OfflineFeatures { - gitHubFeatureFlags; - constructor(repositoryNwo, tempDir, logger) { - super(logger); - this.gitHubFeatureFlags = new GitHubFeatureFlags( - repositoryNwo, - path6.join(tempDir, FEATURE_FLAGS_FILE_NAME), - logger +var CodeQuality = { + kind: "code-quality" /* CodeQuality */, + name: "code quality", + target: "PUT /repos/:owner/:repo/code-quality/analysis" /* CODE_QUALITY */, + sarifExtension: ".quality.sarif", + sarifPredicate: (name) => name.endsWith(CodeQuality.sarifExtension), + fixCategory: fixCodeQualityCategory, + sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_", + transformPayload: (payload) => payload +}; +function addAssessmentId(payload) { + const rawAssessmentId = getRequiredEnvParam("CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */); + const assessmentId = parseInt(rawAssessmentId, 10); + if (Number.isNaN(assessmentId)) { + throw new Error( + `${"CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */} must not be NaN: ${rawAssessmentId}` ); } - async getDefaultCliVersion(variant) { - if (supportsFeatureFlags(variant)) { - return await this.gitHubFeatureFlags.getDefaultCliVersionFromFlags(); - } - return super.getDefaultCliVersion(variant); + if (assessmentId < 0) { + throw new Error( + `${"CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */} must not be negative: ${rawAssessmentId}` + ); } - /** - * - * @param feature The feature to check. - * @param codeql An optional CodeQL object. If provided, and a `minimumVersion` is specified for the - * feature, the version of the CodeQL CLI will be checked against the minimum version. - * If the version is less than the minimum version, the feature will be considered - * disabled. If not provided, and a `minimumVersion` is specified for the feature, then - * this function will throw. - * @returns true if the feature is enabled, false otherwise. - * - * @throws if a `minimumVersion` is specified for the feature, and `codeql` is not provided. - */ - async getValue(feature, codeql) { - const offlineValue = await this.getOfflineValue(feature, codeql); - if (offlineValue !== void 0) { - return offlineValue; - } - const apiValue = await this.gitHubFeatureFlags.getValue(feature); - if (apiValue !== void 0) { - this.logger.debug( - `Feature ${feature} is ${apiValue ? "enabled" : "disabled"} via the GitHub API.` + return { sarif: payload.sarif, assessment_id: assessmentId }; +} +var RiskAssessment = { + kind: "risk-assessment" /* RiskAssessment */, + name: "code scanning risk assessment", + target: "PUT /repos/:owner/:repo/code-scanning/risk-assessment" /* RISK_ASSESSMENT */, + sarifExtension: ".csra.sarif", + sarifPredicate: (name) => name.endsWith(RiskAssessment.sarifExtension), + fixCategory: (_, category) => category, + sentinelPrefix: "CODEQL_UPLOAD_CSRA_SARIF_", + transformPayload: addAssessmentId +}; +function getAnalysisConfig(kind) { + switch (kind) { + case "code-scanning" /* CodeScanning */: + return CodeScanning; + case "code-quality" /* CodeQuality */: + return CodeQuality; + case "risk-assessment" /* RiskAssessment */: + return RiskAssessment; + } +} +var SarifScanOrder = [ + RiskAssessment, + CodeQuality, + CodeScanning +]; + +// src/analyze.ts +var fs13 = __toESM(require("fs")); +var path12 = __toESM(require("path")); +var import_perf_hooks2 = require("perf_hooks"); +var io5 = __toESM(require_io()); + +// src/autobuild.ts +var core12 = __toESM(require_core()); + +// src/codeql.ts +var fs12 = __toESM(require("fs")); +var path11 = __toESM(require("path")); +var core11 = __toESM(require_core()); +var toolrunner3 = __toESM(require_toolrunner()); + +// src/cli-errors.ts +var SUPPORTED_PLATFORMS = [ + ["linux", "x64"], + ["win32", "x64"], + ["darwin", "x64"], + ["darwin", "arm64"] +]; +var CliError = class extends Error { + exitCode; + stderr; + constructor({ cmd, args, exitCode, stderr }) { + const prettyCommand = prettyPrintInvocation(cmd, args); + const fatalErrors = extractFatalErrors(stderr); + const autobuildErrors = extractAutobuildErrors(stderr); + let message; + if (fatalErrors) { + message = `Encountered a fatal error while running "${prettyCommand}". Exit code was ${exitCode} and error was: ${ensureEndsInPeriod( + fatalErrors.trim() + )} See the logs for more details.`; + } else if (autobuildErrors) { + message = `We were unable to automatically build your code. Please provide manual build steps. See ${"https://docs.github.com/en/code-security/code-scanning/troubleshooting-code-scanning/automatic-build-failed" /* AUTOMATIC_BUILD_FAILED */} for more information. Encountered the following error: ${autobuildErrors}`; + } else { + const lastLine = ensureEndsInPeriod( + stderr.trim().split("\n").pop()?.trim() || "n/a" ); - return apiValue; + message = `Encountered a fatal error while running "${prettyCommand}". Exit code was ${exitCode} and last log line was: ${lastLine} See the logs for more details.`; } - return this.getDefaultValue(feature); + super(message); + this.exitCode = exitCode; + this.stderr = stderr; } }; -var GitHubFeatureFlags = class { - constructor(repositoryNwo, featureFlagsFile, logger) { - this.repositoryNwo = repositoryNwo; - this.featureFlagsFile = featureFlagsFile; - this.logger = logger; - this.hasAccessedRemoteFeatureFlags = false; - } - repositoryNwo; - featureFlagsFile; - logger; - cachedApiResponse; - // We cache whether the feature flags were accessed or not in order to accurately report whether flags were - // incorrectly configured vs. inaccessible in our telemetry. - hasAccessedRemoteFeatureFlags; - getCliVersionFromFeatureFlag(f) { - if (!f.startsWith(DEFAULT_VERSION_FEATURE_FLAG_PREFIX) || !f.endsWith(DEFAULT_VERSION_FEATURE_FLAG_SUFFIX)) { - return void 0; - } - const version = f.substring( - DEFAULT_VERSION_FEATURE_FLAG_PREFIX.length, - f.length - DEFAULT_VERSION_FEATURE_FLAG_SUFFIX.length - ).replace(/_/g, "."); - if (!semver5.valid(version)) { - this.logger.warning( - `Ignoring feature flag ${f} as it does not specify a valid CodeQL version.` - ); - return void 0; - } - return version; - } - async getDefaultCliVersionFromFlags() { - const response = await this.getAllFeatures(); - const enabledFeatureFlagCliVersions = Object.entries(response).map( - ([f, isEnabled]) => isEnabled ? this.getCliVersionFromFeatureFlag(f) : void 0 - ).filter((f) => f !== void 0); - if (enabledFeatureFlagCliVersions.length === 0) { - this.logger.warning( - `Feature flags do not specify a default CLI version. Falling back to the CLI version shipped with the Action. This is ${cliVersion}.` - ); - const result = { - cliVersion, - tagName: bundleVersion - }; - if (this.hasAccessedRemoteFeatureFlags) { - result.toolsFeatureFlagsValid = false; - } - return result; +function extractFatalErrors(error3) { + const fatalErrorRegex = /.*fatal (internal )?error occurr?ed(. Details)?:/gi; + let fatalErrors = []; + let lastFatalErrorIndex; + let match; + while ((match = fatalErrorRegex.exec(error3)) !== null) { + if (lastFatalErrorIndex !== void 0) { + fatalErrors.push(error3.slice(lastFatalErrorIndex, match.index).trim()); } - const maxCliVersion = enabledFeatureFlagCliVersions.reduce( - (maxVersion, currentVersion) => currentVersion > maxVersion ? currentVersion : maxVersion, - enabledFeatureFlagCliVersions[0] - ); - this.logger.debug( - `Derived default CLI version of ${maxCliVersion} from feature flags.` - ); - return { - cliVersion: maxCliVersion, - tagName: `codeql-bundle-v${maxCliVersion}`, - toolsFeatureFlagsValid: true - }; + lastFatalErrorIndex = match.index; } - async getValue(feature) { - const response = await this.getAllFeatures(); - if (response === void 0) { - this.logger.debug(`No feature flags API response for ${feature}.`); - return void 0; + if (lastFatalErrorIndex !== void 0) { + const lastError = error3.slice(lastFatalErrorIndex).trim(); + if (fatalErrors.length === 0) { + return lastError; } - const features = response[feature]; - if (features === void 0) { - this.logger.debug(`Feature '${feature}' undefined in API response.`); - return void 0; + const isOneLiner = !fatalErrors.some((e) => e.includes("\n")); + if (isOneLiner) { + fatalErrors = fatalErrors.map(ensureEndsInPeriod); } - return !!features; + return [ + ensureEndsInPeriod(lastError), + "Context:", + ...fatalErrors.reverse() + ].join(isOneLiner ? " " : "\n"); } - async getAllFeatures() { - if (this.cachedApiResponse !== void 0) { - return this.cachedApiResponse; - } - const fileFlags = await this.readLocalFlags(); - if (fileFlags !== void 0) { - this.cachedApiResponse = fileFlags; - return fileFlags; - } - let remoteFlags = await this.loadApiResponse(); - if (remoteFlags === void 0) { - remoteFlags = {}; - } - this.cachedApiResponse = remoteFlags; - await this.writeLocalFlags(remoteFlags); - return remoteFlags; + return void 0; +} +function extractAutobuildErrors(error3) { + const pattern = /.*\[autobuild\] \[ERROR\] (.*)/gi; + let errorLines = [...error3.matchAll(pattern)].map((match) => match[1]); + if (errorLines.length > 10) { + errorLines = errorLines.slice(0, 10); + errorLines.push("(truncated)"); + } + return errorLines.join("\n") || void 0; +} +var cliErrorsConfig = { + ["AutobuildError" /* AutobuildError */]: { + cliErrorMessageCandidates: [ + new RegExp("We were unable to automatically build your code") + ] + }, + ["CouldNotCreateTempDir" /* CouldNotCreateTempDir */]: { + cliErrorMessageCandidates: [new RegExp("Could not create temp directory")] + }, + ["ExternalRepositoryCloneFailed" /* ExternalRepositoryCloneFailed */]: { + cliErrorMessageCandidates: [ + new RegExp("Failed to clone external Git repository") + ] + }, + ["GradleBuildFailed" /* GradleBuildFailed */]: { + cliErrorMessageCandidates: [ + new RegExp("\\[autobuild\\] FAILURE: Build failed with an exception.") + ] + }, + // Version of CodeQL CLI is incompatible with this version of the CodeQL Action + ["IncompatibleWithActionVersion" /* IncompatibleWithActionVersion */]: { + cliErrorMessageCandidates: [ + new RegExp("is not compatible with this CodeQL CLI") + ] + }, + ["InitCalledTwice" /* InitCalledTwice */]: { + cliErrorMessageCandidates: [ + new RegExp( + "Refusing to create databases .* but could not process any of it" + ) + ], + additionalErrorMessageToAppend: `Is the "init" action called twice in the same job?` + }, + ["InvalidConfigFile" /* InvalidConfigFile */]: { + cliErrorMessageCandidates: [ + new RegExp("Config file .* is not valid"), + new RegExp("The supplied config file is empty") + ] + }, + ["InvalidExternalRepoSpecifier" /* InvalidExternalRepoSpecifier */]: { + cliErrorMessageCandidates: [ + new RegExp("Specifier for external repository is invalid") + ] + }, + // Expected source location for database creation does not exist + ["InvalidSourceRoot" /* InvalidSourceRoot */]: { + cliErrorMessageCandidates: [new RegExp("Invalid source root")] + }, + ["MavenBuildFailed" /* MavenBuildFailed */]: { + cliErrorMessageCandidates: [ + new RegExp("\\[autobuild\\] \\[ERROR\\] Failed to execute goal") + ] + }, + ["NoBuildCommandAutodetected" /* NoBuildCommandAutodetected */]: { + cliErrorMessageCandidates: [ + new RegExp("Could not auto-detect a suitable build method") + ] + }, + ["NoBuildMethodAutodetected" /* NoBuildMethodAutodetected */]: { + cliErrorMessageCandidates: [ + new RegExp( + "Could not detect a suitable build command for the source checkout" + ) + ] + }, + // Usually when a manual build script has failed, or if an autodetected language + // was unintended to have CodeQL analysis run on it. + ["NoSourceCodeSeen" /* NoSourceCodeSeen */]: { + exitCode: 32, + cliErrorMessageCandidates: [ + new RegExp( + "CodeQL detected code written in .* but could not process any of it" + ), + new RegExp( + "CodeQL did not detect any code written in languages supported by CodeQL" + ) + ] + }, + ["NoSupportedBuildCommandSucceeded" /* NoSupportedBuildCommandSucceeded */]: { + cliErrorMessageCandidates: [ + new RegExp("No supported build command succeeded") + ] + }, + ["NoSupportedBuildSystemDetected" /* NoSupportedBuildSystemDetected */]: { + cliErrorMessageCandidates: [ + new RegExp("No supported build system detected") + ] + }, + ["OutOfMemoryOrDisk" /* OutOfMemoryOrDisk */]: { + cliErrorMessageCandidates: [ + new RegExp("CodeQL is out of memory."), + new RegExp("out of disk"), + new RegExp("No space left on device") + ], + additionalErrorMessageToAppend: "For more information, see https://gh.io/troubleshooting-code-scanning/out-of-disk-or-memory" + }, + ["PackCannotBeFound" /* PackCannotBeFound */]: { + cliErrorMessageCandidates: [ + new RegExp( + "Query pack .* cannot be found\\. Check the spelling of the pack\\." + ), + new RegExp( + "is not a .ql file, .qls file, a directory, or a query pack specification." + ) + ] + }, + ["PackMissingAuth" /* PackMissingAuth */]: { + cliErrorMessageCandidates: [ + new RegExp("GitHub Container registry .* 403 Forbidden"), + new RegExp( + "Do you need to specify a token to authenticate to the registry?" + ) + ] + }, + ["SwiftBuildFailed" /* SwiftBuildFailed */]: { + cliErrorMessageCandidates: [ + new RegExp( + "\\[autobuilder/build\\] \\[build-command-failed\\] `autobuild` failed to run the build command" + ) + ] + }, + ["SwiftIncompatibleOs" /* SwiftIncompatibleOs */]: { + cliErrorMessageCandidates: [ + new RegExp("\\[incompatible-os\\]"), + new RegExp("Swift analysis is only supported on macOS") + ] + }, + ["UnsupportedBuildMode" /* UnsupportedBuildMode */]: { + cliErrorMessageCandidates: [ + new RegExp( + "does not support the .* build mode. Please try using one of the following build modes instead" + ) + ] + }, + ["NotFoundInRegistry" /* NotFoundInRegistry */]: { + cliErrorMessageCandidates: [ + new RegExp("'.*' not found in the registry '.*'") + ] } - async readLocalFlags() { - try { - if (fs5.existsSync(this.featureFlagsFile)) { - this.logger.debug( - `Loading feature flags from ${this.featureFlagsFile}` - ); - return JSON.parse( - fs5.readFileSync(this.featureFlagsFile, "utf8") - ); +}; +function getCliConfigCategoryIfExists(cliError) { + for (const [category, configuration] of Object.entries(cliErrorsConfig)) { + if (cliError.exitCode !== void 0 && configuration.exitCode !== void 0 && cliError.exitCode === configuration.exitCode) { + return category; + } + for (const e of configuration.cliErrorMessageCandidates) { + if (cliError.message.match(e) || cliError.stderr.match(e)) { + return category; } - } catch (e) { - this.logger.warning( - `Error reading cached feature flags file ${this.featureFlagsFile}: ${e}. Requesting from GitHub instead.` - ); } - return void 0; } - async writeLocalFlags(flags) { - try { - this.logger.debug(`Writing feature flags to ${this.featureFlagsFile}`); - fs5.writeFileSync(this.featureFlagsFile, JSON.stringify(flags)); - } catch (e) { - this.logger.warning( - `Error writing cached feature flags file ${this.featureFlagsFile}: ${e}.` - ); - } + return void 0; +} +function isUnsupportedPlatform() { + return !SUPPORTED_PLATFORMS.some( + ([platform2, arch2]) => platform2 === process.platform && arch2 === process.arch + ); +} +function getUnsupportedPlatformError(cliError) { + return new ConfigurationError( + `The CodeQL CLI does not support the platform/architecture combination of ${process.platform}/${process.arch} (see ${"https://codeql.github.com/docs/codeql-overview/system-requirements/" /* SYSTEM_REQUIREMENTS */}). The underlying error was: ${cliError.message}` + ); +} +function wrapCliConfigurationError(cliError) { + if (isUnsupportedPlatform()) { + return getUnsupportedPlatformError(cliError); } - async loadApiResponse() { - try { - const featuresToRequest = Object.entries(featureConfig).filter( - ([, config]) => !config.legacyApi - ).map(([f]) => f); - const FEATURES_PER_REQUEST = 25; - const featureChunks = []; - while (featuresToRequest.length > 0) { - featureChunks.push(featuresToRequest.splice(0, FEATURES_PER_REQUEST)); - } - let remoteFlags = {}; - for (const chunk of featureChunks) { - const response = await getApiClient().request( - "GET /repos/:owner/:repo/code-scanning/codeql-action/features", - { - owner: this.repositoryNwo.owner, - repo: this.repositoryNwo.repo, - features: chunk.join(",") - } - ); - const chunkFlags = response.data; - remoteFlags = { ...remoteFlags, ...chunkFlags }; - } - this.logger.debug( - "Loaded the following default values for the feature flags from the CodeQL Action API:" - ); - for (const [feature, value] of Object.entries(remoteFlags).sort( - ([nameA], [nameB]) => nameA.localeCompare(nameB) - )) { - this.logger.debug(` ${feature}: ${value}`); - } - this.hasAccessedRemoteFeatureFlags = true; - return remoteFlags; - } catch (e) { - const httpError = asHTTPError(e); - if (httpError?.status === 403) { - this.logger.warning( - `This run of the CodeQL Action does not have permission to access the CodeQL Action API endpoints. As a result, it will not be opted into any experimental features. This could be because the Action is running on a pull request from a fork. If not, please ensure the workflow has at least the 'security-events: read' permission. Details: ${httpError.message}` - ); - this.hasAccessedRemoteFeatureFlags = false; - return {}; - } else { - throw new Error( - `Encountered an error while trying to determine feature enablement: ${e}` - ); - } - } + const cliConfigErrorCategory = getCliConfigCategoryIfExists(cliError); + if (cliConfigErrorCategory === void 0) { + return cliError; } -}; -function supportsFeatureFlags(githubVariant) { - return githubVariant === "GitHub.com" /* DOTCOM */ || githubVariant === "GitHub Enterprise Cloud with data residency" /* GHEC_DR */; + let errorMessageBuilder = cliError.message; + const additionalErrorMessageToAppend = cliErrorsConfig[cliConfigErrorCategory].additionalErrorMessageToAppend; + if (additionalErrorMessageToAppend !== void 0) { + errorMessageBuilder = `${errorMessageBuilder} ${additionalErrorMessageToAppend}`; + } + return new ConfigurationError(errorMessageBuilder); } -function initFeatures(gitHubVersion, repositoryNwo, tempDir, logger) { - if (!supportsFeatureFlags(gitHubVersion.type)) { + +// src/config-utils.ts +var fs7 = __toESM(require("fs")); +var path7 = __toESM(require("path")); +var core9 = __toESM(require_core()); + +// src/caching-utils.ts +var crypto2 = __toESM(require("crypto")); +var core7 = __toESM(require_core()); +async function getTotalCacheSize(paths, logger, quiet = false) { + const sizes = await Promise.all( + paths.map((cacheDir) => tryGetFolderBytes(cacheDir, logger, quiet)) + ); + return sizes.map((a) => a || 0).reduce((a, b) => a + b, 0); +} +function shouldStoreCache(kind) { + return kind === "full" /* Full */ || kind === "store" /* Store */; +} +var cacheKeyHashLength = 16; +function createCacheKeyHash(components) { + const componentsJson = JSON.stringify(components); + return crypto2.createHash("sha256").update(componentsJson).digest("hex").substring(0, cacheKeyHashLength); +} + +// src/config/db-config.ts +var jsonschema = __toESM(require_lib2()); +var semver5 = __toESM(require_semver2()); + +// src/feature-flags/properties.ts +var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => { + RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay"; + RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries"; + RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs"; + return RepositoryPropertyName2; +})(RepositoryPropertyName || {}); +var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set( + Object.values(RepositoryPropertyName) +); + +// src/config/db-config.ts +var PACK_IDENTIFIER_PATTERN = (function() { + const alphaNumeric = "[a-z0-9]"; + const alphaNumericDash = "[a-z0-9-]"; + const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`; + return new RegExp(`^${component}/${component}$`); +})(); + +// src/diagnostics.ts +var import_fs = require("fs"); +var import_path = __toESM(require("path")); + +// src/logging.ts +var core8 = __toESM(require_core()); +function getActionsLogger() { + return { + debug: core8.debug, + info: core8.info, + warning: core8.warning, + error: core8.error, + isDebug: core8.isDebug, + startGroup: core8.startGroup, + endGroup: core8.endGroup + }; +} +async function withGroupAsync(groupName, f) { + core8.startGroup(groupName); + try { + return await f(); + } finally { + core8.endGroup(); + } +} +function formatDuration(durationMs) { + if (durationMs < 1e3) { + return `${durationMs}ms`; + } + if (durationMs < 60 * 1e3) { + return `${(durationMs / 1e3).toFixed(1)}s`; + } + const minutes = Math.floor(durationMs / (60 * 1e3)); + const seconds = Math.floor(durationMs % (60 * 1e3) / 1e3); + return `${minutes}m${seconds}s`; +} + +// src/diagnostics.ts +var unwrittenDiagnostics = []; +var unwrittenDefaultLanguageDiagnostics = []; +var diagnosticCounter = 0; +function makeDiagnostic(id, name, data = void 0) { + return { + ...data, + timestamp: data?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(), + source: { ...data?.source, id, name } + }; +} +function addDiagnostic(config, language, diagnostic) { + const logger = getActionsLogger(); + const databasePath = language ? getCodeQLDatabasePath(config, language) : config.dbLocation; + if ((0, import_fs.existsSync)(databasePath)) { + writeDiagnostic(config, language, diagnostic); + } else { logger.debug( - "Not running against github.com. Using default values for all features." + `Writing a diagnostic for ${language}, but the database at ${databasePath} does not exist yet.` + ); + unwrittenDiagnostics.push({ diagnostic, language }); + } +} +function addNoLanguageDiagnostic(config, diagnostic) { + if (config !== void 0) { + addDiagnostic( + config, + // Arbitrarily choose the first language. We could also choose all languages, but that + // increases the risk of misinterpreting the data. + config.languages[0], + diagnostic ); - return new OfflineFeatures(logger); } else { - return new Features(repositoryNwo, tempDir, logger); + unwrittenDefaultLanguageDiagnostics.push(diagnostic); + } +} +function writeDiagnostic(config, language, diagnostic) { + const logger = getActionsLogger(); + const databasePath = language ? getCodeQLDatabasePath(config, language) : config.dbLocation; + const diagnosticsPath = import_path.default.resolve( + databasePath, + "diagnostic", + "codeql-action" + ); + try { + (0, import_fs.mkdirSync)(diagnosticsPath, { recursive: true }); + const uniqueSuffix = (diagnosticCounter++).toString(); + const sanitizedTimestamp = diagnostic.timestamp.replace( + /[^a-zA-Z0-9.-]/g, + "" + ); + const jsonPath = import_path.default.resolve( + diagnosticsPath, + `codeql-action-${sanitizedTimestamp}-${uniqueSuffix}.json` + ); + (0, import_fs.writeFileSync)(jsonPath, JSON.stringify(diagnostic)); + } catch (err) { + logger.warning(`Unable to write diagnostic message to database: ${err}`); + logger.debug(JSON.stringify(diagnostic)); } } // src/diff-informed-analysis-utils.ts +var fs6 = __toESM(require("fs")); function readDiffRangesJsonFile(logger) { const jsonFilePath = getDiffRangesJsonFilePath(); if (!fs6.existsSync(jsonFilePath)) { diff --git a/lib/autobuild-action.js b/lib/autobuild-action.js index be61bdeabf..642dd5ffef 100644 --- a/lib/autobuild-action.js +++ b/lib/autobuild-action.js @@ -86171,59 +86171,10 @@ var fs5 = __toESM(require("fs")); var path6 = __toESM(require("path")); var core9 = __toESM(require_core()); -// src/analyses.ts -var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { - AnalysisKind2["CodeScanning"] = "code-scanning"; - AnalysisKind2["CodeQuality"] = "code-quality"; - AnalysisKind2["RiskAssessment"] = "risk-assessment"; - return AnalysisKind2; -})(AnalysisKind || {}); -var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); - -// src/caching-utils.ts -var core6 = __toESM(require_core()); - -// src/config/db-config.ts -var jsonschema = __toESM(require_lib2()); -var semver2 = __toESM(require_semver2()); - -// src/feature-flags/properties.ts -var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => { - RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay"; - RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries"; - RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs"; - return RepositoryPropertyName2; -})(RepositoryPropertyName || {}); -var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set( - Object.values(RepositoryPropertyName) -); - -// src/config/db-config.ts -var PACK_IDENTIFIER_PATTERN = (function() { - const alphaNumeric = "[a-z0-9]"; - const alphaNumericDash = "[a-z0-9-]"; - const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`; - return new RegExp(`^${component}/${component}$`); -})(); - -// src/logging.ts -var core7 = __toESM(require_core()); -function getActionsLogger() { - return { - debug: core7.debug, - info: core7.info, - warning: core7.warning, - error: core7.error, - isDebug: core7.isDebug, - startGroup: core7.startGroup, - endGroup: core7.endGroup - }; -} - // src/feature-flags.ts var fs4 = __toESM(require("fs")); var path5 = __toESM(require("path")); -var semver5 = __toESM(require_semver2()); +var semver4 = __toESM(require_semver2()); // src/defaults.json var bundleVersion = "codeql-bundle-v2.25.4"; @@ -86236,14 +86187,14 @@ var path4 = __toESM(require("path")); // src/git-utils.ts var fs2 = __toESM(require("fs")); var path3 = __toESM(require("path")); -var core8 = __toESM(require_core()); +var core6 = __toESM(require_core()); var toolrunner2 = __toESM(require_toolrunner()); var io3 = __toESM(require_io()); -var semver3 = __toESM(require_semver2()); +var semver2 = __toESM(require_semver2()); var runGitCommand = async function(workingDirectory, args, customErrorMessage, options) { let stdout = ""; let stderr = ""; - core8.debug(`Running git command: git ${args.join(" ")}`); + core6.debug(`Running git command: git ${args.join(" ")}`); try { await new toolrunner2.ToolRunner(await io3.which("git", true), args, { silent: true, @@ -86264,7 +86215,7 @@ var runGitCommand = async function(workingDirectory, args, customErrorMessage, o if (stderr.includes("not a git repository")) { reason = "The checkout path provided to the action does not appear to be a git repository."; } - core8.info(`git call failed. ${customErrorMessage} Error: ${reason}`); + core6.info(`git call failed. ${customErrorMessage} Error: ${reason}`); throw error3; } }; @@ -86393,7 +86344,7 @@ async function getRef() { ) !== head; if (hasChangedRef) { const newRef = ref.replace(pull_ref_regex, "refs/pull/$1/head"); - core8.debug( + core6.debug( `No longer on merge commit, rewriting ref from ${ref} to ${newRef}.` ); return newRef; @@ -86530,7 +86481,7 @@ async function getDiffRangeFilePaths(sourceRoot, logger) { } // src/tools-features.ts -var semver4 = __toESM(require_semver2()); +var semver3 = __toESM(require_semver2()); function isSupportedToolsFeature(versionInfo, feature) { return !!versionInfo.features && versionInfo.features[feature]; } @@ -86539,6 +86490,11 @@ function isSupportedToolsFeature(versionInfo, feature) { var DEFAULT_VERSION_FEATURE_FLAG_PREFIX = "default_codeql_version_"; var DEFAULT_VERSION_FEATURE_FLAG_SUFFIX = "_enabled"; var featureConfig = { + ["allow_multiple_analysis_kinds" /* AllowMultipleAnalysisKinds */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_ALLOW_MULTIPLE_ANALYSIS_KINDS", + minimumVersion: void 0 + }, ["allow_toolcache_input" /* AllowToolcacheInput */]: { defaultValue: false, envVar: "CODEQL_ACTION_ALLOW_TOOLCACHE_INPUT", @@ -86915,7 +86871,7 @@ var GitHubFeatureFlags = class { DEFAULT_VERSION_FEATURE_FLAG_PREFIX.length, f.length - DEFAULT_VERSION_FEATURE_FLAG_SUFFIX.length ).replace(/_/g, "."); - if (!semver5.valid(version)) { + if (!semver4.valid(version)) { this.logger.warning( `Ignoring feature flag ${f} as it does not specify a valid CodeQL version.` ); @@ -87074,6 +87030,55 @@ function initFeatures(gitHubVersion, repositoryNwo, tempDir, logger) { } } +// src/analyses.ts +var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { + AnalysisKind2["CodeScanning"] = "code-scanning"; + AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["RiskAssessment"] = "risk-assessment"; + return AnalysisKind2; +})(AnalysisKind || {}); +var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); + +// src/caching-utils.ts +var core7 = __toESM(require_core()); + +// src/config/db-config.ts +var jsonschema = __toESM(require_lib2()); +var semver5 = __toESM(require_semver2()); + +// src/feature-flags/properties.ts +var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => { + RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay"; + RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries"; + RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs"; + return RepositoryPropertyName2; +})(RepositoryPropertyName || {}); +var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set( + Object.values(RepositoryPropertyName) +); + +// src/config/db-config.ts +var PACK_IDENTIFIER_PATTERN = (function() { + const alphaNumeric = "[a-z0-9]"; + const alphaNumericDash = "[a-z0-9-]"; + const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`; + return new RegExp(`^${component}/${component}$`); +})(); + +// src/logging.ts +var core8 = __toESM(require_core()); +function getActionsLogger() { + return { + debug: core8.debug, + info: core8.info, + warning: core8.warning, + error: core8.error, + isDebug: core8.isDebug, + startGroup: core8.startGroup, + endGroup: core8.endGroup + }; +} + // src/languages/builtin.json var builtin_default = { languages: [ diff --git a/lib/init-action-post.js b/lib/init-action-post.js index b972b1ece8..dc71c1c383 100644 --- a/lib/init-action-post.js +++ b/lib/init-action-post.js @@ -130716,189 +130716,10 @@ var fs8 = __toESM(require("fs")); var path8 = __toESM(require("path")); var core9 = __toESM(require_core()); -// src/analyses.ts -var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { - AnalysisKind2["CodeScanning"] = "code-scanning"; - AnalysisKind2["CodeQuality"] = "code-quality"; - AnalysisKind2["RiskAssessment"] = "risk-assessment"; - return AnalysisKind2; -})(AnalysisKind || {}); -var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); -var CodeScanning = { - kind: "code-scanning" /* CodeScanning */, - name: "code scanning", - target: "PUT /repos/:owner/:repo/code-scanning/analysis" /* CODE_SCANNING */, - sarifExtension: ".sarif", - sarifPredicate: (name) => name.endsWith(CodeScanning.sarifExtension) && !CodeQuality.sarifPredicate(name) && !RiskAssessment.sarifPredicate(name), - fixCategory: (_2, category) => category, - sentinelPrefix: "CODEQL_UPLOAD_SARIF_", - transformPayload: (payload) => payload -}; -var CodeQuality = { - kind: "code-quality" /* CodeQuality */, - name: "code quality", - target: "PUT /repos/:owner/:repo/code-quality/analysis" /* CODE_QUALITY */, - sarifExtension: ".quality.sarif", - sarifPredicate: (name) => name.endsWith(CodeQuality.sarifExtension), - fixCategory: fixCodeQualityCategory, - sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_", - transformPayload: (payload) => payload -}; -function addAssessmentId(payload) { - const rawAssessmentId = getRequiredEnvParam("CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */); - const assessmentId = parseInt(rawAssessmentId, 10); - if (Number.isNaN(assessmentId)) { - throw new Error( - `${"CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */} must not be NaN: ${rawAssessmentId}` - ); - } - if (assessmentId < 0) { - throw new Error( - `${"CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */} must not be negative: ${rawAssessmentId}` - ); - } - return { sarif: payload.sarif, assessment_id: assessmentId }; -} -var RiskAssessment = { - kind: "risk-assessment" /* RiskAssessment */, - name: "code scanning risk assessment", - target: "PUT /repos/:owner/:repo/code-scanning/risk-assessment" /* RISK_ASSESSMENT */, - sarifExtension: ".csra.sarif", - sarifPredicate: (name) => name.endsWith(RiskAssessment.sarifExtension), - fixCategory: (_2, category) => category, - sentinelPrefix: "CODEQL_UPLOAD_CSRA_SARIF_", - transformPayload: addAssessmentId -}; - -// src/config/db-config.ts -var jsonschema = __toESM(require_lib2()); -var semver2 = __toESM(require_semver2()); - -// src/feature-flags/properties.ts -var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => { - RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay"; - RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries"; - RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs"; - return RepositoryPropertyName2; -})(RepositoryPropertyName || {}); -var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set( - Object.values(RepositoryPropertyName) -); - -// src/config/db-config.ts -var PACK_IDENTIFIER_PATTERN = (function() { - const alphaNumeric = "[a-z0-9]"; - const alphaNumericDash = "[a-z0-9-]"; - const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`; - return new RegExp(`^${component}/${component}$`); -})(); - -// src/diagnostics.ts -var import_fs = require("fs"); -var import_path = __toESM(require("path")); - -// src/logging.ts -var core7 = __toESM(require_core()); -function getActionsLogger() { - return { - debug: core7.debug, - info: core7.info, - warning: core7.warning, - error: core7.error, - isDebug: core7.isDebug, - startGroup: core7.startGroup, - endGroup: core7.endGroup - }; -} -function withGroup(groupName, f) { - core7.startGroup(groupName); - try { - return f(); - } finally { - core7.endGroup(); - } -} -function formatDuration(durationMs) { - if (durationMs < 1e3) { - return `${durationMs}ms`; - } - if (durationMs < 60 * 1e3) { - return `${(durationMs / 1e3).toFixed(1)}s`; - } - const minutes = Math.floor(durationMs / (60 * 1e3)); - const seconds = Math.floor(durationMs % (60 * 1e3) / 1e3); - return `${minutes}m${seconds}s`; -} - -// src/diagnostics.ts -var unwrittenDiagnostics = []; -var unwrittenDefaultLanguageDiagnostics = []; -var diagnosticCounter = 0; -function makeDiagnostic(id, name, data = void 0) { - return { - ...data, - timestamp: data?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(), - source: { ...data?.source, id, name } - }; -} -function addDiagnostic(config, language, diagnostic) { - const logger = getActionsLogger(); - const databasePath = language ? getCodeQLDatabasePath(config, language) : config.dbLocation; - if ((0, import_fs.existsSync)(databasePath)) { - writeDiagnostic(config, language, diagnostic); - } else { - logger.debug( - `Writing a diagnostic for ${language}, but the database at ${databasePath} does not exist yet.` - ); - unwrittenDiagnostics.push({ diagnostic, language }); - } -} -function addNoLanguageDiagnostic(config, diagnostic) { - if (config !== void 0) { - addDiagnostic( - config, - // Arbitrarily choose the first language. We could also choose all languages, but that - // increases the risk of misinterpreting the data. - config.languages[0], - diagnostic - ); - } else { - unwrittenDefaultLanguageDiagnostics.push(diagnostic); - } -} -function writeDiagnostic(config, language, diagnostic) { - const logger = getActionsLogger(); - const databasePath = language ? getCodeQLDatabasePath(config, language) : config.dbLocation; - const diagnosticsPath = import_path.default.resolve( - databasePath, - "diagnostic", - "codeql-action" - ); - try { - (0, import_fs.mkdirSync)(diagnosticsPath, { recursive: true }); - const uniqueSuffix = (diagnosticCounter++).toString(); - const sanitizedTimestamp = diagnostic.timestamp.replace( - /[^a-zA-Z0-9.-]/g, - "" - ); - const jsonPath = import_path.default.resolve( - diagnosticsPath, - `codeql-action-${sanitizedTimestamp}-${uniqueSuffix}.json` - ); - (0, import_fs.writeFileSync)(jsonPath, JSON.stringify(diagnostic)); - } catch (err) { - logger.warning(`Unable to write diagnostic message to database: ${err}`); - logger.debug(JSON.stringify(diagnostic)); - } -} - -// src/diff-informed-analysis-utils.ts -var fs6 = __toESM(require("fs")); - // src/feature-flags.ts var fs5 = __toESM(require("fs")); -var path6 = __toESM(require("path")); -var semver5 = __toESM(require_semver2()); +var path5 = __toESM(require("path")); +var semver4 = __toESM(require_semver2()); // src/defaults.json var bundleVersion = "codeql-bundle-v2.25.4"; @@ -130906,19 +130727,19 @@ var cliVersion = "2.25.4"; // src/overlay/index.ts var fs4 = __toESM(require("fs")); -var path5 = __toESM(require("path")); +var path4 = __toESM(require("path")); // src/git-utils.ts var fs3 = __toESM(require("fs")); -var path4 = __toESM(require("path")); -var core8 = __toESM(require_core()); +var path3 = __toESM(require("path")); +var core7 = __toESM(require_core()); var toolrunner2 = __toESM(require_toolrunner()); var io3 = __toESM(require_io()); -var semver3 = __toESM(require_semver2()); +var semver2 = __toESM(require_semver2()); var runGitCommand = async function(workingDirectory, args, customErrorMessage, options) { let stdout = ""; let stderr = ""; - core8.debug(`Running git command: git ${args.join(" ")}`); + core7.debug(`Running git command: git ${args.join(" ")}`); try { await new toolrunner2.ToolRunner(await io3.which("git", true), args, { silent: true, @@ -130939,7 +130760,7 @@ var runGitCommand = async function(workingDirectory, args, customErrorMessage, o if (stderr.includes("not a git repository")) { reason = "The checkout path provided to the action does not appear to be a git repository."; } - core8.info(`git call failed. ${customErrorMessage} Error: ${reason}`); + core7.info(`git call failed. ${customErrorMessage} Error: ${reason}`); throw error3; } }; @@ -131035,7 +130856,7 @@ var getGitRoot = async function(sourceRoot) { } }; function hasSubmodules(gitRoot) { - return fs3.existsSync(path4.join(gitRoot, ".gitmodules")); + return fs3.existsSync(path3.join(gitRoot, ".gitmodules")); } var getFileOidsUnderPath = async function(basePath) { const gitRoot = await getGitRoot(basePath); @@ -131102,7 +130923,7 @@ async function getRef() { ) !== head; if (hasChangedRef) { const newRef = ref.replace(pull_ref_regex, "refs/pull/$1/head"); - core8.debug( + core7.debug( `No longer on merge commit, rewriting ref from ${ref} to ${newRef}.` ); return newRef; @@ -131167,7 +130988,7 @@ async function writeOverlayChangesFile(config, sourceRoot, logger) { const diffRangeFiles = await getDiffRangeFilePaths(sourceRoot, logger); const changedFiles = [.../* @__PURE__ */ new Set([...oidChangedFiles, ...diffRangeFiles])]; const changedFilesJson = JSON.stringify({ changes: changedFiles }); - const overlayChangesFile = path5.join( + const overlayChangesFile = path4.join( getTemporaryDirectory(), "overlay-changes.json" ); @@ -131233,19 +131054,19 @@ async function getDiffRangeFilePaths(sourceRoot, logger) { return [...new Set(diffRanges.map((r) => r.path))]; } const relativePaths = diffRanges.map( - (r) => path5.relative(sourceRoot, path5.join(repoRoot, r.path)).replaceAll(path5.sep, "/") + (r) => path4.relative(sourceRoot, path4.join(repoRoot, r.path)).replaceAll(path4.sep, "/") ).filter((rel) => !rel.startsWith("..")); return [...new Set(relativePaths)]; } // src/tools-features.ts -var semver4 = __toESM(require_semver2()); +var semver3 = __toESM(require_semver2()); function isSupportedToolsFeature(versionInfo, feature) { return !!versionInfo.features && versionInfo.features[feature]; } var SafeArtifactUploadVersion = "2.20.3"; function isSafeArtifactUpload(codeQlVersion) { - return !codeQlVersion ? true : semver4.gte(codeQlVersion, SafeArtifactUploadVersion); + return !codeQlVersion ? true : semver3.gte(codeQlVersion, SafeArtifactUploadVersion); } // src/feature-flags.ts @@ -131253,6 +131074,11 @@ var DEFAULT_VERSION_FEATURE_FLAG_PREFIX = "default_codeql_version_"; var DEFAULT_VERSION_FEATURE_FLAG_SUFFIX = "_enabled"; var CODEQL_VERSION_ZSTD_BUNDLE = "2.19.0"; var featureConfig = { + ["allow_multiple_analysis_kinds" /* AllowMultipleAnalysisKinds */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_ALLOW_MULTIPLE_ANALYSIS_KINDS", + minimumVersion: void 0 + }, ["allow_toolcache_input" /* AllowToolcacheInput */]: { defaultValue: false, envVar: "CODEQL_ACTION_ALLOW_TOOLCACHE_INPUT", @@ -131570,7 +131396,7 @@ var Features = class extends OfflineFeatures { super(logger); this.gitHubFeatureFlags = new GitHubFeatureFlags( repositoryNwo, - path6.join(tempDir, FEATURE_FLAGS_FILE_NAME), + path5.join(tempDir, FEATURE_FLAGS_FILE_NAME), logger ); } @@ -131629,7 +131455,7 @@ var GitHubFeatureFlags = class { DEFAULT_VERSION_FEATURE_FLAG_PREFIX.length, f.length - DEFAULT_VERSION_FEATURE_FLAG_SUFFIX.length ).replace(/_/g, "."); - if (!semver5.valid(version)) { + if (!semver4.valid(version)) { this.logger.warning( `Ignoring feature flag ${f} as it does not specify a valid CodeQL version.` ); @@ -131788,7 +131614,184 @@ function initFeatures(gitHubVersion, repositoryNwo, tempDir, logger) { } } +// src/analyses.ts +var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { + AnalysisKind2["CodeScanning"] = "code-scanning"; + AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["RiskAssessment"] = "risk-assessment"; + return AnalysisKind2; +})(AnalysisKind || {}); +var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); +var CodeScanning = { + kind: "code-scanning" /* CodeScanning */, + name: "code scanning", + target: "PUT /repos/:owner/:repo/code-scanning/analysis" /* CODE_SCANNING */, + sarifExtension: ".sarif", + sarifPredicate: (name) => name.endsWith(CodeScanning.sarifExtension) && !CodeQuality.sarifPredicate(name) && !RiskAssessment.sarifPredicate(name), + fixCategory: (_2, category) => category, + sentinelPrefix: "CODEQL_UPLOAD_SARIF_", + transformPayload: (payload) => payload +}; +var CodeQuality = { + kind: "code-quality" /* CodeQuality */, + name: "code quality", + target: "PUT /repos/:owner/:repo/code-quality/analysis" /* CODE_QUALITY */, + sarifExtension: ".quality.sarif", + sarifPredicate: (name) => name.endsWith(CodeQuality.sarifExtension), + fixCategory: fixCodeQualityCategory, + sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_", + transformPayload: (payload) => payload +}; +function addAssessmentId(payload) { + const rawAssessmentId = getRequiredEnvParam("CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */); + const assessmentId = parseInt(rawAssessmentId, 10); + if (Number.isNaN(assessmentId)) { + throw new Error( + `${"CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */} must not be NaN: ${rawAssessmentId}` + ); + } + if (assessmentId < 0) { + throw new Error( + `${"CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */} must not be negative: ${rawAssessmentId}` + ); + } + return { sarif: payload.sarif, assessment_id: assessmentId }; +} +var RiskAssessment = { + kind: "risk-assessment" /* RiskAssessment */, + name: "code scanning risk assessment", + target: "PUT /repos/:owner/:repo/code-scanning/risk-assessment" /* RISK_ASSESSMENT */, + sarifExtension: ".csra.sarif", + sarifPredicate: (name) => name.endsWith(RiskAssessment.sarifExtension), + fixCategory: (_2, category) => category, + sentinelPrefix: "CODEQL_UPLOAD_CSRA_SARIF_", + transformPayload: addAssessmentId +}; + +// src/config/db-config.ts +var jsonschema = __toESM(require_lib2()); +var semver5 = __toESM(require_semver2()); + +// src/feature-flags/properties.ts +var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => { + RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay"; + RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries"; + RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs"; + return RepositoryPropertyName2; +})(RepositoryPropertyName || {}); +var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set( + Object.values(RepositoryPropertyName) +); + +// src/config/db-config.ts +var PACK_IDENTIFIER_PATTERN = (function() { + const alphaNumeric = "[a-z0-9]"; + const alphaNumericDash = "[a-z0-9-]"; + const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`; + return new RegExp(`^${component}/${component}$`); +})(); + +// src/diagnostics.ts +var import_fs = require("fs"); +var import_path = __toESM(require("path")); + +// src/logging.ts +var core8 = __toESM(require_core()); +function getActionsLogger() { + return { + debug: core8.debug, + info: core8.info, + warning: core8.warning, + error: core8.error, + isDebug: core8.isDebug, + startGroup: core8.startGroup, + endGroup: core8.endGroup + }; +} +function withGroup(groupName, f) { + core8.startGroup(groupName); + try { + return f(); + } finally { + core8.endGroup(); + } +} +function formatDuration(durationMs) { + if (durationMs < 1e3) { + return `${durationMs}ms`; + } + if (durationMs < 60 * 1e3) { + return `${(durationMs / 1e3).toFixed(1)}s`; + } + const minutes = Math.floor(durationMs / (60 * 1e3)); + const seconds = Math.floor(durationMs % (60 * 1e3) / 1e3); + return `${minutes}m${seconds}s`; +} + +// src/diagnostics.ts +var unwrittenDiagnostics = []; +var unwrittenDefaultLanguageDiagnostics = []; +var diagnosticCounter = 0; +function makeDiagnostic(id, name, data = void 0) { + return { + ...data, + timestamp: data?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(), + source: { ...data?.source, id, name } + }; +} +function addDiagnostic(config, language, diagnostic) { + const logger = getActionsLogger(); + const databasePath = language ? getCodeQLDatabasePath(config, language) : config.dbLocation; + if ((0, import_fs.existsSync)(databasePath)) { + writeDiagnostic(config, language, diagnostic); + } else { + logger.debug( + `Writing a diagnostic for ${language}, but the database at ${databasePath} does not exist yet.` + ); + unwrittenDiagnostics.push({ diagnostic, language }); + } +} +function addNoLanguageDiagnostic(config, diagnostic) { + if (config !== void 0) { + addDiagnostic( + config, + // Arbitrarily choose the first language. We could also choose all languages, but that + // increases the risk of misinterpreting the data. + config.languages[0], + diagnostic + ); + } else { + unwrittenDefaultLanguageDiagnostics.push(diagnostic); + } +} +function writeDiagnostic(config, language, diagnostic) { + const logger = getActionsLogger(); + const databasePath = language ? getCodeQLDatabasePath(config, language) : config.dbLocation; + const diagnosticsPath = import_path.default.resolve( + databasePath, + "diagnostic", + "codeql-action" + ); + try { + (0, import_fs.mkdirSync)(diagnosticsPath, { recursive: true }); + const uniqueSuffix = (diagnosticCounter++).toString(); + const sanitizedTimestamp = diagnostic.timestamp.replace( + /[^a-zA-Z0-9.-]/g, + "" + ); + const jsonPath = import_path.default.resolve( + diagnosticsPath, + `codeql-action-${sanitizedTimestamp}-${uniqueSuffix}.json` + ); + (0, import_fs.writeFileSync)(jsonPath, JSON.stringify(diagnostic)); + } catch (err) { + logger.warning(`Unable to write diagnostic message to database: ${err}`); + logger.debug(JSON.stringify(diagnostic)); + } +} + // src/diff-informed-analysis-utils.ts +var fs6 = __toESM(require("fs")); function readDiffRangesJsonFile(logger) { const jsonFilePath = getDiffRangesJsonFilePath(); if (!fs6.existsSync(jsonFilePath)) { diff --git a/lib/init-action.js b/lib/init-action.js index b7cdc23b79..c6f67eec45 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -86357,66 +86357,10 @@ function isAnalyzingPullRequest() { return getPullRequestBranches() !== void 0; } -// src/analyses.ts -var AnalysisKind = /* @__PURE__ */ ((AnalysisKind3) => { - AnalysisKind3["CodeScanning"] = "code-scanning"; - AnalysisKind3["CodeQuality"] = "code-quality"; - AnalysisKind3["RiskAssessment"] = "risk-assessment"; - return AnalysisKind3; -})(AnalysisKind || {}); -var compatibilityMatrix = { - ["code-scanning" /* CodeScanning */]: /* @__PURE__ */ new Set(["code-quality" /* CodeQuality */]), - ["code-quality" /* CodeQuality */]: /* @__PURE__ */ new Set(["code-scanning" /* CodeScanning */]), - ["risk-assessment" /* RiskAssessment */]: /* @__PURE__ */ new Set() -}; -var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); -async function parseAnalysisKinds(input) { - const components = input.split(","); - if (components.length < 1) { - throw new ConfigurationError( - "At least one analysis kind must be configured." - ); - } - for (const component of components) { - if (!supportedAnalysisKinds.has(component)) { - throw new ConfigurationError(`Unknown analysis kind: ${component}`); - } - } - return Array.from( - new Set(components.map((component) => component)) - ); -} -var cachedAnalysisKinds; -async function getAnalysisKinds(logger, skipCache = false) { - if (!skipCache && cachedAnalysisKinds !== void 0) { - return cachedAnalysisKinds; - } - const analysisKinds = await parseAnalysisKinds( - getRequiredInput("analysis-kinds") - ); - const qualityQueriesInput = getOptionalInput("quality-queries"); - if (qualityQueriesInput !== void 0) { - logger.warning( - "The `quality-queries` input is deprecated and will be removed in a future version of the CodeQL Action. Use the `analysis-kinds` input to configure different analysis kinds instead." - ); - } - if (!analysisKinds.includes("code-quality" /* CodeQuality */) && qualityQueriesInput !== void 0) { - analysisKinds.push("code-quality" /* CodeQuality */); - } - for (const analysisKind of analysisKinds) { - for (const otherAnalysisKind of analysisKinds) { - if (analysisKind === otherAnalysisKind) continue; - if (!compatibilityMatrix[analysisKind].has(otherAnalysisKind)) { - throw new ConfigurationError( - `${analysisKind} and ${otherAnalysisKind} cannot be enabled at the same time` - ); - } - } - } - cachedAnalysisKinds = analysisKinds; - return cachedAnalysisKinds; -} -var codeQualityQueries = ["code-quality"]; +// src/feature-flags.ts +var fs5 = __toESM(require("fs")); +var path5 = __toESM(require("path")); +var semver4 = __toESM(require_semver2()); // src/api-client.ts var core5 = __toESM(require_core()); @@ -86682,959 +86626,363 @@ function wrapApiConfigurationError(e) { return e; } -// src/caching-utils.ts -var crypto2 = __toESM(require("crypto")); -var core6 = __toESM(require_core()); -async function getTotalCacheSize(paths, logger, quiet = false) { - const sizes = await Promise.all( - paths.map((cacheDir) => tryGetFolderBytes(cacheDir, logger, quiet)) - ); - return sizes.map((a) => a || 0).reduce((a, b) => a + b, 0); -} -function shouldRestoreCache(kind) { - return kind === "full" /* Full */ || kind === "restore" /* Restore */; -} -function getCachingKind(input) { - switch (input) { - case void 0: - case "none": - case "off": - case "false": - return "none" /* None */; - case "full": - case "on": - case "true": - return "full" /* Full */; - case "store": - return "store" /* Store */; - case "restore": - return "restore" /* Restore */; - default: - core6.warning( - `Unrecognized 'dependency-caching' input: ${input}. Defaulting to 'none'.` - ); - return "none" /* None */; - } -} -var cacheKeyHashLength = 16; -function createCacheKeyHash(components) { - const componentsJson = JSON.stringify(components); - return crypto2.createHash("sha256").update(componentsJson).digest("hex").substring(0, cacheKeyHashLength); -} -function getDependencyCachingEnabled() { - const dependencyCaching = getOptionalInput("dependency-caching") || process.env["CODEQL_ACTION_DEPENDENCY_CACHING" /* DEPENDENCY_CACHING */]; - if (dependencyCaching !== void 0) return getCachingKind(dependencyCaching); - if (!isHostedRunner()) return "none" /* None */; - if (!isDefaultSetup()) return "none" /* None */; - return "none" /* None */; -} +// src/defaults.json +var bundleVersion = "codeql-bundle-v2.25.4"; +var cliVersion = "2.25.4"; -// src/config-utils.ts -var fs9 = __toESM(require("fs")); -var path10 = __toESM(require("path")); -var import_perf_hooks = require("perf_hooks"); -var core9 = __toESM(require_core()); +// src/overlay/index.ts +var fs4 = __toESM(require("fs")); +var path4 = __toESM(require("path")); -// src/config/db-config.ts +// src/git-utils.ts +var fs3 = __toESM(require("fs")); +var os2 = __toESM(require("os")); var path3 = __toESM(require("path")); -var jsonschema = __toESM(require_lib2()); +var core6 = __toESM(require_core()); +var toolrunner2 = __toESM(require_toolrunner()); +var io3 = __toESM(require_io()); var semver2 = __toESM(require_semver2()); - -// src/error-messages.ts -var PACKS_PROPERTY = "packs"; -function getConfigFileOutsideWorkspaceErrorMessage(configFile) { - return `The configuration file "${configFile}" is outside of the workspace`; -} -function getConfigFileDoesNotExistErrorMessage(configFile) { - return `The configuration file "${configFile}" does not exist`; -} -function getConfigFileParseErrorMessage(configFile, message) { - return `Cannot parse "${configFile}": ${message}`; -} -function getInvalidConfigFileMessage(configFile, messages) { - const andMore = messages.length > 10 ? `, and ${messages.length - 10} more.` : "."; - return `The configuration file "${configFile}" is invalid: ${messages.slice(0, 10).join(", ")}${andMore}`; -} -function getConfigFileRepoFormatInvalidMessage(configFile) { - let error3 = `The configuration file "${configFile}" is not a supported remote file reference.`; - error3 += " Expected format //@"; - return error3; -} -function getConfigFileFormatInvalidMessage(configFile) { - return `The configuration file "${configFile}" could not be read`; -} -function getConfigFileDirectoryGivenMessage(configFile) { - return `The configuration file "${configFile}" looks like a directory, not a file`; -} -function getEmptyCombinesError() { - return `A '+' was used to specify that you want to add extra arguments to the configuration, but no extra arguments were specified. Please either remove the '+' or specify some extra arguments.`; -} -function getConfigFilePropertyError(configFile, property, error3) { - if (configFile === void 0) { - return `The workflow property "${property}" is invalid: ${error3}`; - } else { - return `The configuration file "${configFile}" is invalid: property "${property}" ${error3}`; +var GIT_MINIMUM_VERSION_FOR_OVERLAY_WITH_SUBMODULES = "2.36.0"; +var GitVersionInfo = class { + constructor(truncatedVersion, fullVersion) { + this.truncatedVersion = truncatedVersion; + this.fullVersion = fullVersion; + } + truncatedVersion; + fullVersion; + isAtLeast(minVersion) { + return semver2.gte(this.truncatedVersion, minVersion); } -} -function getRepoPropertyError(propertyName, error3) { - return `The repository property "${propertyName}" is invalid: ${error3}`; -} -function getPacksStrInvalid(packStr, configFile) { - return configFile ? getConfigFilePropertyError( - configFile, - PACKS_PROPERTY, - `"${packStr}" is not a valid pack` - ) : `"${packStr}" is not a valid pack`; -} -function getNoLanguagesError() { - return "Did not detect any languages to analyze. Please update input in workflow or check that GitHub detects the correct languages in your repository."; -} -function getUnknownLanguagesError(languages) { - return `Did not recognize the following languages: ${languages.join(", ")}`; -} - -// src/feature-flags/properties.ts -var GITHUB_CODEQL_PROPERTY_PREFIX = "github-codeql-"; -var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => { - RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay"; - RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries"; - RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs"; - return RepositoryPropertyName2; -})(RepositoryPropertyName || {}); -function isString2(value) { - return typeof value === "string"; -} -var stringProperty = { - validate: isString2, - parse: parseStringRepositoryProperty -}; -var booleanProperty = { - // The value from the API should come as a string, which we then parse into a boolean. - validate: isString2, - parse: parseBooleanRepositoryProperty -}; -var repositoryPropertyParsers = { - ["github-codeql-disable-overlay" /* DISABLE_OVERLAY */]: booleanProperty, - ["github-codeql-extra-queries" /* EXTRA_QUERIES */]: stringProperty, - ["github-codeql-file-coverage-on-prs" /* FILE_COVERAGE_ON_PRS */]: booleanProperty }; -async function loadPropertiesFromApi(logger, repositoryNwo) { +async function getGitVersionOrThrow() { + const stdout = await runGitCommand( + void 0, + ["--version"], + "Failed to get git version." + ); + const match = stdout.trim().match(/^git version ((\d+\.\d+\.\d+).*)$/); + if (match?.[1] && match?.[2]) { + return new GitVersionInfo(match[2], match[1]); + } + throw new Error(`Could not parse Git version from output: ${stdout.trim()}`); +} +var runGitCommand = async function(workingDirectory, args, customErrorMessage, options) { + let stdout = ""; + let stderr = ""; + core6.debug(`Running git command: git ${args.join(" ")}`); try { - const response = await getRepositoryProperties(repositoryNwo); - const remoteProperties = response.data; - if (!Array.isArray(remoteProperties)) { - throw new Error( - `Expected repository properties API to return an array, but got: ${JSON.stringify(response.data)}` - ); + await new toolrunner2.ToolRunner(await io3.which("git", true), args, { + silent: true, + listeners: { + stdout: (data) => { + stdout += data.toString(); + }, + stderr: (data) => { + stderr += data.toString(); + } + }, + cwd: workingDirectory, + ...options + }).exec(); + return stdout; + } catch (error3) { + let reason = stderr; + if (stderr.includes("not a git repository")) { + reason = "The checkout path provided to the action does not appear to be a git repository."; } - logger.debug( - `Retrieved ${remoteProperties.length} repository properties: ${remoteProperties.map((p) => p.property_name).join(", ")}` - ); - const properties = {}; - const unrecognisedProperties = []; - for (const property of remoteProperties) { - if (property.property_name === void 0) { - throw new Error( - `Expected repository property object to have a 'property_name', but got: ${JSON.stringify(property)}` - ); - } - if (isKnownPropertyName(property.property_name)) { - setProperty2(properties, property.property_name, property.value, logger); - } else if (property.property_name.startsWith(GITHUB_CODEQL_PROPERTY_PREFIX) && !isDynamicWorkflow()) { - unrecognisedProperties.push(property.property_name); - } - } - if (Object.keys(properties).length === 0) { - logger.debug("No known repository properties were found."); - } else { - logger.debug( - "Loaded the following values for the repository properties:" - ); - for (const [property, value] of Object.entries(properties).sort( - ([nameA], [nameB]) => nameA.localeCompare(nameB) - )) { - logger.debug(` ${property}: ${value}`); - } - } - if (unrecognisedProperties.length > 0) { - const unrecognisedPropertyList = unrecognisedProperties.map((name) => `'${name}'`).join(", "); - logger.warning( - `Found repository properties (${unrecognisedPropertyList}), which look like CodeQL Action repository properties, but which are not understood by this version of the CodeQL Action. Do you need to update to a newer version?` - ); - } - return properties; - } catch (e) { - throw new Error( - `Encountered an error while trying to determine repository properties: ${e}` + core6.info(`git call failed. ${customErrorMessage} Error: ${reason}`); + throw error3; + } +}; +var getCommitOid = async function(checkoutPath, ref = "HEAD") { + try { + const stdout = await runGitCommand( + checkoutPath, + ["rev-parse", ref], + "Continuing with commit SHA from user input or environment." ); + return stdout.trim(); + } catch { + return getOptionalInput("sha") || getRequiredEnvParam("GITHUB_SHA"); } -} -function setProperty2(properties, name, value, logger) { - const propertyOptions = repositoryPropertyParsers[name]; - if (propertyOptions.validate(value)) { - properties[name] = propertyOptions.parse(name, value, logger); - } else { - throw new Error( - `Unexpected value for repository property '${name}' (${typeof value}), got: ${JSON.stringify(value)}` +}; +var decodeGitFilePath = function(filePath) { + if (filePath.startsWith('"') && filePath.endsWith('"')) { + filePath = filePath.substring(1, filePath.length - 1); + return filePath.replace( + /\\([abfnrtv\\"]|[0-7]{1,3})/g, + (_match, seq2) => { + switch (seq2[0]) { + case "a": + return "\x07"; + case "b": + return "\b"; + case "f": + return "\f"; + case "n": + return "\n"; + case "r": + return "\r"; + case "t": + return " "; + case "v": + return "\v"; + case "\\": + return "\\"; + case '"': + return '"'; + default: + return String.fromCharCode(parseInt(seq2, 8)); + } + } ); } -} -function parseBooleanRepositoryProperty(name, value, logger) { - if (value !== "true" && value !== "false") { - logger.warning( - `Repository property '${name}' has unexpected value '${value}'. Expected 'true' or 'false'. Defaulting to false.` + return filePath; +}; +var getGitRoot = async function(sourceRoot) { + try { + const stdout = await runGitCommand( + sourceRoot, + ["rev-parse", "--show-toplevel"], + `Cannot find Git repository root from the source root ${sourceRoot}.` ); + return stdout.trim(); + } catch { + return void 0; } - return value === "true"; -} -function parseStringRepositoryProperty(_name, value) { - return value; -} -var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set( - Object.values(RepositoryPropertyName) -); -function isKnownPropertyName(name) { - return KNOWN_REPOSITORY_PROPERTY_NAMES.has(name); -} - -// src/config/db-config.ts -function shouldCombine(inputValue) { - return !!inputValue?.trim().startsWith("+"); +}; +function hasSubmodules(gitRoot) { + return fs3.existsSync(path3.join(gitRoot, ".gitmodules")); } -var PACK_IDENTIFIER_PATTERN = (function() { - const alphaNumeric = "[a-z0-9]"; - const alphaNumericDash = "[a-z0-9-]"; - const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`; - return new RegExp(`^${component}/${component}$`); -})(); -function parsePacksSpecification(packStr) { - if (typeof packStr !== "string") { - throw new ConfigurationError(getPacksStrInvalid(packStr)); - } - packStr = packStr.trim(); - const atIndex = packStr.indexOf("@"); - const colonIndex = packStr.indexOf(":", atIndex); - const packStart = 0; - const versionStart = atIndex + 1 || void 0; - const pathStart = colonIndex + 1 || void 0; - const packEnd = Math.min( - atIndex > 0 ? atIndex : Infinity, - colonIndex > 0 ? colonIndex : Infinity, - packStr.length +var getFileOidsUnderPath = async function(basePath) { + const gitRoot = await getGitRoot(basePath); + const mayHaveSubmodules = gitRoot === void 0 ? true : hasSubmodules(gitRoot); + const args = mayHaveSubmodules ? ["ls-files", "--recurse-submodules", "--stage"] : ["ls-files", "--stage"]; + const stdout = await runGitCommand( + basePath, + args, + "Cannot list Git OIDs of tracked files." ); - const versionEnd = versionStart ? Math.min(colonIndex > 0 ? colonIndex : Infinity, packStr.length) : void 0; - const pathEnd = pathStart ? packStr.length : void 0; - const packName = packStr.slice(packStart, packEnd).trim(); - const version = versionStart ? packStr.slice(versionStart, versionEnd).trim() : void 0; - const packPath = pathStart ? packStr.slice(pathStart, pathEnd).trim() : void 0; - if (!PACK_IDENTIFIER_PATTERN.test(packName)) { - throw new ConfigurationError(getPacksStrInvalid(packStr)); - } - if (version) { - try { - new semver2.Range(version); - } catch { - throw new ConfigurationError(getPacksStrInvalid(packStr)); + const fileOidMap = {}; + const regex = /^[0-9]+ ([0-9a-f]{40}) [0-9]+\t(.+)$/; + for (const line of stdout.split("\n")) { + if (line) { + const match = line.match(regex); + if (match) { + const oid = match[1]; + const filePath = decodeGitFilePath(match[2]); + fileOidMap[filePath] = oid; + } else { + throw new Error(`Unexpected "git ls-files" output: ${line}`); + } } } - if (packPath && (path3.isAbsolute(packPath) || // Permit using "/" instead of "\" on Windows - // Use `x.split(y).join(z)` as a polyfill for `x.replaceAll(y, z)` since - // if we used a regex we'd need to escape the path separator on Windows - // which seems more awkward. - path3.normalize(packPath).split(path3.sep).join("/") !== packPath.split(path3.sep).join("/"))) { - throw new ConfigurationError(getPacksStrInvalid(packStr)); - } - if (!packPath && pathStart) { - throw new ConfigurationError(getPacksStrInvalid(packStr)); + return fileOidMap; +}; +function getRefFromEnv() { + let refEnv; + try { + refEnv = getRequiredEnvParam("GITHUB_REF"); + } catch (e) { + const maybeRef = process.env["CODE_SCANNING_REF"]; + if (maybeRef === void 0 || maybeRef.length === 0) { + throw e; + } + refEnv = maybeRef; } - return { - name: packName, - version, - path: packPath - }; -} -function validatePackSpecification(pack) { - return prettyPrintPack(parsePacksSpecification(pack)); + return refEnv; } -function parsePacksFromInput(rawPacksInput, languages, packsInputCombines) { - if (!rawPacksInput?.trim()) { - return void 0; - } - if (languages.length > 1) { - throw new ConfigurationError( - "Cannot specify a 'packs' input in a multi-language analysis. Use a codeql-config.yml file instead and specify packs by language." - ); - } else if (languages.length === 0) { +async function getRef() { + const refInput = getOptionalInput("ref"); + const shaInput = getOptionalInput("sha"); + const checkoutPath = getOptionalInput("checkout_path") || getOptionalInput("source-root") || getRequiredEnvParam("GITHUB_WORKSPACE"); + const hasRefInput = !!refInput; + const hasShaInput = !!shaInput; + if ((hasRefInput || hasShaInput) && !(hasRefInput && hasShaInput)) { throw new ConfigurationError( - "No languages specified. Cannot process the packs input." + "Both 'ref' and 'sha' are required if one of them is provided." ); } - rawPacksInput = rawPacksInput.trim(); - if (packsInputCombines) { - rawPacksInput = rawPacksInput.trim().substring(1).trim(); - if (!rawPacksInput) { - throw new ConfigurationError( - getConfigFilePropertyError( - void 0, - "packs", - "A '+' was used in the 'packs' input to specify that you wished to add some packs to your CodeQL analysis. However, no packs were specified. Please either remove the '+' or specify some packs." - ) - ); - } + const ref = refInput || getRefFromEnv(); + const sha = shaInput || getRequiredEnvParam("GITHUB_SHA"); + if (refInput) { + return refInput; + } + const pull_ref_regex = /refs\/pull\/(\d+)\/merge/; + if (!pull_ref_regex.test(ref)) { + return ref; + } + const head = await getCommitOid(checkoutPath, "HEAD"); + const hasChangedRef = sha !== head && await getCommitOid( + checkoutPath, + ref.replace(/^refs\/pull\//, "refs/remotes/pull/") + ) !== head; + if (hasChangedRef) { + const newRef = ref.replace(pull_ref_regex, "refs/pull/$1/head"); + core6.debug( + `No longer on merge commit, rewriting ref from ${ref} to ${newRef}.` + ); + return newRef; + } else { + return ref; } - return { - [languages[0]]: rawPacksInput.split(",").reduce((packs, pack) => { - packs.push(validatePackSpecification(pack)); - return packs; - }, []) - }; } -async function calculateAugmentation(rawPacksInput, rawQueriesInput, repositoryProperties, languages) { - const packsInputCombines = shouldCombine(rawPacksInput); - const packsInput = parsePacksFromInput( - rawPacksInput, - languages, - packsInputCombines - ); - const queriesInputCombines = shouldCombine(rawQueriesInput); - const queriesInput = parseQueriesFromInput( - rawQueriesInput, - queriesInputCombines - ); - const repoExtraQueries = repositoryProperties["github-codeql-extra-queries" /* EXTRA_QUERIES */]; - const repoExtraQueriesCombines = shouldCombine(repoExtraQueries); - const repoPropertyQueries = { - combines: repoExtraQueriesCombines, - input: parseQueriesFromInput( - repoExtraQueries, - repoExtraQueriesCombines, - new ConfigurationError( - getRepoPropertyError( - "github-codeql-extra-queries" /* EXTRA_QUERIES */, - getEmptyCombinesError() - ) - ) - ) - }; - return { - packsInputCombines, - packsInput: packsInput?.[languages[0]], - queriesInput, - queriesInputCombines, - repoPropertyQueries - }; +function removeRefsHeadsPrefix(ref) { + return ref.startsWith("refs/heads/") ? ref.slice("refs/heads/".length) : ref; } -function parseQueriesFromInput(rawQueriesInput, queriesInputCombines, errorToThrow) { - if (!rawQueriesInput) { - return void 0; +async function isAnalyzingDefaultBranch() { + if (process.env.CODE_SCANNING_IS_ANALYZING_DEFAULT_BRANCH === "true") { + return true; } - const trimmedInput = queriesInputCombines ? rawQueriesInput.trim().slice(1).trim() : rawQueriesInput?.trim() ?? ""; - if (queriesInputCombines && trimmedInput.length === 0) { - if (errorToThrow) { - throw errorToThrow; - } - throw new ConfigurationError( - getConfigFilePropertyError( - void 0, - "queries", - "A '+' was used in the 'queries' input to specify that you wished to add some packs to your CodeQL analysis. However, no packs were specified. Please either remove the '+' or specify some packs." - ) - ); + let currentRef = await getRef(); + currentRef = removeRefsHeadsPrefix(currentRef); + const event = getWorkflowEvent(); + let defaultBranch = event?.repository?.default_branch; + if (getWorkflowEventName() === "schedule") { + defaultBranch = removeRefsHeadsPrefix(getRefFromEnv()); } - return trimmedInput.split(",").map((query) => ({ uses: query.trim() })); + return currentRef === defaultBranch; } -function combineQueries(logger, config, augmentationProperties) { - const result = []; - if (augmentationProperties.repoPropertyQueries?.input) { - logger.info( - `Found query configuration in the repository properties (${"github-codeql-extra-queries" /* EXTRA_QUERIES */}): ${augmentationProperties.repoPropertyQueries.input.map((q) => q.uses).join(", ")}` - ); - if (!augmentationProperties.repoPropertyQueries.combines) { - logger.info( - `The queries configured in the repository properties don't allow combining with other query settings. Any queries configured elsewhere will be ignored.` - ); - return augmentationProperties.repoPropertyQueries.input; - } else { - result.push(...augmentationProperties.repoPropertyQueries.input); - } - } - if (augmentationProperties.queriesInput) { - if (!augmentationProperties.queriesInputCombines) { - return result.concat(augmentationProperties.queriesInput); - } else { - result.push(...augmentationProperties.queriesInput); +async function listFiles(workingDirectory) { + const stdout = await runGitCommand( + workingDirectory, + ["ls-files"], + "Unable to list tracked files." + ); + return stdout.split(os2.EOL).filter((line) => line.trim().length > 0); +} +async function getGeneratedFiles(workingDirectory) { + const files = await listFiles(workingDirectory); + const stdout = await runGitCommand( + workingDirectory, + ["check-attr", "linguist-generated", "--stdin"], + "Unable to check attributes of files.", + { input: Buffer.from(files.join(os2.EOL)) } + ); + const generatedFiles = []; + const regex = /^([^:]+): linguist-generated: true$/; + for (const result of stdout.split(os2.EOL)) { + const match = result.match(regex); + if (match && match[1].trim().length > 0) { + generatedFiles.push(match[1].trim()); } } - if (config.queries) { - result.push(...config.queries); + return generatedFiles; +} + +// src/overlay/index.ts +var CODEQL_OVERLAY_MINIMUM_VERSION = "2.23.8"; +var CODEQL_OVERLAY_MINIMUM_VERSION_CPP = "2.25.0"; +var CODEQL_OVERLAY_MINIMUM_VERSION_CSHARP = "2.24.1"; +var CODEQL_OVERLAY_MINIMUM_VERSION_GO = "2.24.2"; +var CODEQL_OVERLAY_MINIMUM_VERSION_JAVA = "2.23.8"; +var CODEQL_OVERLAY_MINIMUM_VERSION_JAVASCRIPT = "2.23.9"; +var CODEQL_OVERLAY_MINIMUM_VERSION_PYTHON = "2.23.9"; +var CODEQL_OVERLAY_MINIMUM_VERSION_RUBY = "2.23.9"; +async function writeBaseDatabaseOidsFile(config, sourceRoot) { + const gitFileOids = await getFileOidsUnderPath(sourceRoot); + const gitFileOidsJson = JSON.stringify(gitFileOids); + const baseDatabaseOidsFilePath = getBaseDatabaseOidsFilePath(config); + await fs4.promises.writeFile(baseDatabaseOidsFilePath, gitFileOidsJson); +} +async function readBaseDatabaseOidsFile(config, logger) { + const baseDatabaseOidsFilePath = getBaseDatabaseOidsFilePath(config); + try { + const contents = await fs4.promises.readFile( + baseDatabaseOidsFilePath, + "utf-8" + ); + return JSON.parse(contents); + } catch (e) { + logger.error( + `Failed to read overlay-base file OIDs from ${baseDatabaseOidsFilePath}: ${e.message || e}` + ); + throw e; } - return result; } -function generateCodeScanningConfig(logger, originalUserInput, augmentationProperties) { - const augmentedConfig = cloneObject(originalUserInput); - augmentedConfig.queries = combineQueries( - logger, - augmentedConfig, - augmentationProperties +async function writeOverlayChangesFile(config, sourceRoot, logger) { + const baseFileOids = await readBaseDatabaseOidsFile(config, logger); + const overlayFileOids = await getFileOidsUnderPath(sourceRoot); + const oidChangedFiles = computeChangedFiles(baseFileOids, overlayFileOids); + logger.info( + `Found ${oidChangedFiles.length} changed file(s) under ${sourceRoot} from OID comparison.` + ); + const diffRangeFiles = await getDiffRangeFilePaths(sourceRoot, logger); + const changedFiles = [.../* @__PURE__ */ new Set([...oidChangedFiles, ...diffRangeFiles])]; + const changedFilesJson = JSON.stringify({ changes: changedFiles }); + const overlayChangesFile = path4.join( + getTemporaryDirectory(), + "overlay-changes.json" ); logger.debug( - `Combined queries: ${augmentedConfig.queries?.map((q) => q.uses).join(",")}` + `Writing overlay changed files to ${overlayChangesFile}: ${changedFilesJson}` ); - if (augmentedConfig.queries?.length === 0) { - delete augmentedConfig.queries; - } - if (augmentationProperties.packsInput) { - if (augmentationProperties.packsInputCombines) { - if (Array.isArray(augmentedConfig.packs)) { - augmentedConfig.packs = (augmentedConfig.packs || []).concat( - augmentationProperties.packsInput - ); - } else if (!augmentedConfig.packs) { - augmentedConfig.packs = augmentationProperties.packsInput; - } else { - const language = Object.keys(augmentedConfig.packs)[0]; - augmentedConfig.packs[language] = augmentedConfig.packs[language].concat(augmentationProperties.packsInput); - } - } else { - augmentedConfig.packs = augmentationProperties.packsInput; + await fs4.promises.writeFile(overlayChangesFile, changedFilesJson); + return overlayChangesFile; +} +function computeChangedFiles(baseFileOids, overlayFileOids) { + const changes = []; + for (const [file, oid] of Object.entries(overlayFileOids)) { + if (!(file in baseFileOids) || baseFileOids[file] !== oid) { + changes.push(file); } } - if (Array.isArray(augmentedConfig.packs) && !augmentedConfig.packs.length) { - delete augmentedConfig.packs; + for (const file of Object.keys(baseFileOids)) { + if (!(file in overlayFileOids)) { + changes.push(file); + } } - return augmentedConfig; + return changes; } -function parseUserConfig(logger, pathInput, contents, validateConfig) { +async function getDiffRangeFilePaths(sourceRoot, logger) { + const jsonFilePath = getDiffRangesJsonFilePath(); + if (!fs4.existsSync(jsonFilePath)) { + logger.debug( + `No diff ranges JSON file found at ${jsonFilePath}; skipping.` + ); + return []; + } + let contents; try { - const schema2 = ( - // eslint-disable-next-line @typescript-eslint/no-require-imports - require_db_config_schema() + contents = await fs4.promises.readFile(jsonFilePath, "utf8"); + } catch (e) { + logger.warning( + `Failed to read diff ranges JSON file at ${jsonFilePath}: ${e}` ); - const doc = load(contents); - if (validateConfig) { - const result = new jsonschema.Validator().validate(doc, schema2); - if (result.errors.length > 0) { - for (const error3 of result.errors) { - logger.error(error3.stack); - } - throw new ConfigurationError( - getInvalidConfigFileMessage( - pathInput, - result.errors.map((e) => e.stack) - ) - ); - } - } - return doc; - } catch (error3) { - if (error3 instanceof YAMLException) { - throw new ConfigurationError( - getConfigFileParseErrorMessage(pathInput, error3.message) + return []; + } + let diffRanges; + try { + diffRanges = JSON.parse(contents); + } catch (e) { + logger.warning( + `Failed to parse diff ranges JSON file at ${jsonFilePath}: ${e}` + ); + return []; + } + logger.debug( + `Read ${diffRanges.length} diff range(s) from ${jsonFilePath} for overlay changes.` + ); + const repoRoot = await getGitRoot(sourceRoot); + if (repoRoot === void 0) { + if (getOptionalInput("source-root")) { + throw new Error( + "Cannot determine git root to convert diff range paths relative to source-root. Failing to avoid omitting files from the analysis." ); } - throw error3; + logger.warning( + "Cannot determine git root; returning diff range paths as-is." + ); + return [...new Set(diffRanges.map((r) => r.path))]; } -} - -// src/diagnostics.ts -var import_fs = require("fs"); -var import_path = __toESM(require("path")); - -// src/logging.ts -var core7 = __toESM(require_core()); -function getActionsLogger() { - return { - debug: core7.debug, - info: core7.info, - warning: core7.warning, - error: core7.error, - isDebug: core7.isDebug, - startGroup: core7.startGroup, - endGroup: core7.endGroup - }; -} -async function withGroupAsync(groupName, f) { - core7.startGroup(groupName); - try { - return await f(); - } finally { - core7.endGroup(); - } -} -function formatDuration(durationMs) { - if (durationMs < 1e3) { - return `${durationMs}ms`; - } - if (durationMs < 60 * 1e3) { - return `${(durationMs / 1e3).toFixed(1)}s`; - } - const minutes = Math.floor(durationMs / (60 * 1e3)); - const seconds = Math.floor(durationMs % (60 * 1e3) / 1e3); - return `${minutes}m${seconds}s`; -} - -// src/diagnostics.ts -var unwrittenDiagnostics = []; -var unwrittenDefaultLanguageDiagnostics = []; -var diagnosticCounter = 0; -function makeDiagnostic(id, name, data = void 0) { - return { - ...data, - timestamp: data?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(), - source: { ...data?.source, id, name } - }; -} -function addDiagnostic(config, language, diagnostic) { - const logger = getActionsLogger(); - const databasePath = language ? getCodeQLDatabasePath(config, language) : config.dbLocation; - if ((0, import_fs.existsSync)(databasePath)) { - writeDiagnostic(config, language, diagnostic); - } else { - logger.debug( - `Writing a diagnostic for ${language}, but the database at ${databasePath} does not exist yet.` - ); - unwrittenDiagnostics.push({ diagnostic, language }); - } -} -function addNoLanguageDiagnostic(config, diagnostic) { - if (config !== void 0) { - addDiagnostic( - config, - // Arbitrarily choose the first language. We could also choose all languages, but that - // increases the risk of misinterpreting the data. - config.languages[0], - diagnostic - ); - } else { - unwrittenDefaultLanguageDiagnostics.push(diagnostic); - } -} -function writeDiagnostic(config, language, diagnostic) { - const logger = getActionsLogger(); - const databasePath = language ? getCodeQLDatabasePath(config, language) : config.dbLocation; - const diagnosticsPath = import_path.default.resolve( - databasePath, - "diagnostic", - "codeql-action" - ); - try { - (0, import_fs.mkdirSync)(diagnosticsPath, { recursive: true }); - const uniqueSuffix = (diagnosticCounter++).toString(); - const sanitizedTimestamp = diagnostic.timestamp.replace( - /[^a-zA-Z0-9.-]/g, - "" - ); - const jsonPath = import_path.default.resolve( - diagnosticsPath, - `codeql-action-${sanitizedTimestamp}-${uniqueSuffix}.json` - ); - (0, import_fs.writeFileSync)(jsonPath, JSON.stringify(diagnostic)); - } catch (err) { - logger.warning(`Unable to write diagnostic message to database: ${err}`); - logger.debug(JSON.stringify(diagnostic)); - } -} -function logUnwrittenDiagnostics() { - const logger = getActionsLogger(); - const num = unwrittenDiagnostics.length; - if (num > 0) { - logger.warning( - `${num} diagnostic(s) could not be written to the database and will not appear on the Tool Status Page.` - ); - for (const unwritten of unwrittenDiagnostics) { - logger.debug(JSON.stringify(unwritten.diagnostic)); - } - } -} -function flushDiagnostics(config) { - const logger = getActionsLogger(); - const diagnosticsCount = unwrittenDiagnostics.length + unwrittenDefaultLanguageDiagnostics.length; - logger.debug(`Writing ${diagnosticsCount} diagnostic(s) to database.`); - for (const unwritten of unwrittenDiagnostics) { - writeDiagnostic(config, unwritten.language, unwritten.diagnostic); - } - for (const unwritten of unwrittenDefaultLanguageDiagnostics) { - addNoLanguageDiagnostic(config, unwritten); - } - unwrittenDiagnostics = []; - unwrittenDefaultLanguageDiagnostics = []; -} -function makeTelemetryDiagnostic(id, name, attributes) { - return makeDiagnostic(id, name, { - attributes, - visibility: { - cliSummaryTable: false, - statusPage: false, - telemetry: true - } - }); -} - -// src/diff-informed-analysis-utils.ts -var fs6 = __toESM(require("fs")); - -// src/feature-flags.ts -var fs5 = __toESM(require("fs")); -var path7 = __toESM(require("path")); -var semver5 = __toESM(require_semver2()); - -// src/defaults.json -var bundleVersion = "codeql-bundle-v2.25.4"; -var cliVersion = "2.25.4"; - -// src/overlay/index.ts -var fs4 = __toESM(require("fs")); -var path6 = __toESM(require("path")); - -// src/git-utils.ts -var fs3 = __toESM(require("fs")); -var os2 = __toESM(require("os")); -var path5 = __toESM(require("path")); -var core8 = __toESM(require_core()); -var toolrunner2 = __toESM(require_toolrunner()); -var io3 = __toESM(require_io()); -var semver3 = __toESM(require_semver2()); -var GIT_MINIMUM_VERSION_FOR_OVERLAY_WITH_SUBMODULES = "2.36.0"; -var GitVersionInfo = class { - constructor(truncatedVersion, fullVersion) { - this.truncatedVersion = truncatedVersion; - this.fullVersion = fullVersion; - } - truncatedVersion; - fullVersion; - isAtLeast(minVersion) { - return semver3.gte(this.truncatedVersion, minVersion); - } -}; -async function getGitVersionOrThrow() { - const stdout = await runGitCommand( - void 0, - ["--version"], - "Failed to get git version." - ); - const match = stdout.trim().match(/^git version ((\d+\.\d+\.\d+).*)$/); - if (match?.[1] && match?.[2]) { - return new GitVersionInfo(match[2], match[1]); - } - throw new Error(`Could not parse Git version from output: ${stdout.trim()}`); -} -var runGitCommand = async function(workingDirectory, args, customErrorMessage, options) { - let stdout = ""; - let stderr = ""; - core8.debug(`Running git command: git ${args.join(" ")}`); - try { - await new toolrunner2.ToolRunner(await io3.which("git", true), args, { - silent: true, - listeners: { - stdout: (data) => { - stdout += data.toString(); - }, - stderr: (data) => { - stderr += data.toString(); - } - }, - cwd: workingDirectory, - ...options - }).exec(); - return stdout; - } catch (error3) { - let reason = stderr; - if (stderr.includes("not a git repository")) { - reason = "The checkout path provided to the action does not appear to be a git repository."; - } - core8.info(`git call failed. ${customErrorMessage} Error: ${reason}`); - throw error3; - } -}; -var getCommitOid = async function(checkoutPath, ref = "HEAD") { - try { - const stdout = await runGitCommand( - checkoutPath, - ["rev-parse", ref], - "Continuing with commit SHA from user input or environment." - ); - return stdout.trim(); - } catch { - return getOptionalInput("sha") || getRequiredEnvParam("GITHUB_SHA"); - } -}; -var decodeGitFilePath = function(filePath) { - if (filePath.startsWith('"') && filePath.endsWith('"')) { - filePath = filePath.substring(1, filePath.length - 1); - return filePath.replace( - /\\([abfnrtv\\"]|[0-7]{1,3})/g, - (_match, seq2) => { - switch (seq2[0]) { - case "a": - return "\x07"; - case "b": - return "\b"; - case "f": - return "\f"; - case "n": - return "\n"; - case "r": - return "\r"; - case "t": - return " "; - case "v": - return "\v"; - case "\\": - return "\\"; - case '"': - return '"'; - default: - return String.fromCharCode(parseInt(seq2, 8)); - } - } - ); - } - return filePath; -}; -var getGitRoot = async function(sourceRoot) { - try { - const stdout = await runGitCommand( - sourceRoot, - ["rev-parse", "--show-toplevel"], - `Cannot find Git repository root from the source root ${sourceRoot}.` - ); - return stdout.trim(); - } catch { - return void 0; - } -}; -function hasSubmodules(gitRoot) { - return fs3.existsSync(path5.join(gitRoot, ".gitmodules")); -} -var getFileOidsUnderPath = async function(basePath) { - const gitRoot = await getGitRoot(basePath); - const mayHaveSubmodules = gitRoot === void 0 ? true : hasSubmodules(gitRoot); - const args = mayHaveSubmodules ? ["ls-files", "--recurse-submodules", "--stage"] : ["ls-files", "--stage"]; - const stdout = await runGitCommand( - basePath, - args, - "Cannot list Git OIDs of tracked files." - ); - const fileOidMap = {}; - const regex = /^[0-9]+ ([0-9a-f]{40}) [0-9]+\t(.+)$/; - for (const line of stdout.split("\n")) { - if (line) { - const match = line.match(regex); - if (match) { - const oid = match[1]; - const filePath = decodeGitFilePath(match[2]); - fileOidMap[filePath] = oid; - } else { - throw new Error(`Unexpected "git ls-files" output: ${line}`); - } - } - } - return fileOidMap; -}; -function getRefFromEnv() { - let refEnv; - try { - refEnv = getRequiredEnvParam("GITHUB_REF"); - } catch (e) { - const maybeRef = process.env["CODE_SCANNING_REF"]; - if (maybeRef === void 0 || maybeRef.length === 0) { - throw e; - } - refEnv = maybeRef; - } - return refEnv; -} -async function getRef() { - const refInput = getOptionalInput("ref"); - const shaInput = getOptionalInput("sha"); - const checkoutPath = getOptionalInput("checkout_path") || getOptionalInput("source-root") || getRequiredEnvParam("GITHUB_WORKSPACE"); - const hasRefInput = !!refInput; - const hasShaInput = !!shaInput; - if ((hasRefInput || hasShaInput) && !(hasRefInput && hasShaInput)) { - throw new ConfigurationError( - "Both 'ref' and 'sha' are required if one of them is provided." - ); - } - const ref = refInput || getRefFromEnv(); - const sha = shaInput || getRequiredEnvParam("GITHUB_SHA"); - if (refInput) { - return refInput; - } - const pull_ref_regex = /refs\/pull\/(\d+)\/merge/; - if (!pull_ref_regex.test(ref)) { - return ref; - } - const head = await getCommitOid(checkoutPath, "HEAD"); - const hasChangedRef = sha !== head && await getCommitOid( - checkoutPath, - ref.replace(/^refs\/pull\//, "refs/remotes/pull/") - ) !== head; - if (hasChangedRef) { - const newRef = ref.replace(pull_ref_regex, "refs/pull/$1/head"); - core8.debug( - `No longer on merge commit, rewriting ref from ${ref} to ${newRef}.` - ); - return newRef; - } else { - return ref; - } -} -function removeRefsHeadsPrefix(ref) { - return ref.startsWith("refs/heads/") ? ref.slice("refs/heads/".length) : ref; -} -async function isAnalyzingDefaultBranch() { - if (process.env.CODE_SCANNING_IS_ANALYZING_DEFAULT_BRANCH === "true") { - return true; - } - let currentRef = await getRef(); - currentRef = removeRefsHeadsPrefix(currentRef); - const event = getWorkflowEvent(); - let defaultBranch = event?.repository?.default_branch; - if (getWorkflowEventName() === "schedule") { - defaultBranch = removeRefsHeadsPrefix(getRefFromEnv()); - } - return currentRef === defaultBranch; -} -async function listFiles(workingDirectory) { - const stdout = await runGitCommand( - workingDirectory, - ["ls-files"], - "Unable to list tracked files." - ); - return stdout.split(os2.EOL).filter((line) => line.trim().length > 0); -} -async function getGeneratedFiles(workingDirectory) { - const files = await listFiles(workingDirectory); - const stdout = await runGitCommand( - workingDirectory, - ["check-attr", "linguist-generated", "--stdin"], - "Unable to check attributes of files.", - { input: Buffer.from(files.join(os2.EOL)) } - ); - const generatedFiles = []; - const regex = /^([^:]+): linguist-generated: true$/; - for (const result of stdout.split(os2.EOL)) { - const match = result.match(regex); - if (match && match[1].trim().length > 0) { - generatedFiles.push(match[1].trim()); - } - } - return generatedFiles; -} - -// src/overlay/index.ts -var CODEQL_OVERLAY_MINIMUM_VERSION = "2.23.8"; -var CODEQL_OVERLAY_MINIMUM_VERSION_CPP = "2.25.0"; -var CODEQL_OVERLAY_MINIMUM_VERSION_CSHARP = "2.24.1"; -var CODEQL_OVERLAY_MINIMUM_VERSION_GO = "2.24.2"; -var CODEQL_OVERLAY_MINIMUM_VERSION_JAVA = "2.23.8"; -var CODEQL_OVERLAY_MINIMUM_VERSION_JAVASCRIPT = "2.23.9"; -var CODEQL_OVERLAY_MINIMUM_VERSION_PYTHON = "2.23.9"; -var CODEQL_OVERLAY_MINIMUM_VERSION_RUBY = "2.23.9"; -async function writeBaseDatabaseOidsFile(config, sourceRoot) { - const gitFileOids = await getFileOidsUnderPath(sourceRoot); - const gitFileOidsJson = JSON.stringify(gitFileOids); - const baseDatabaseOidsFilePath = getBaseDatabaseOidsFilePath(config); - await fs4.promises.writeFile(baseDatabaseOidsFilePath, gitFileOidsJson); -} -async function readBaseDatabaseOidsFile(config, logger) { - const baseDatabaseOidsFilePath = getBaseDatabaseOidsFilePath(config); - try { - const contents = await fs4.promises.readFile( - baseDatabaseOidsFilePath, - "utf-8" - ); - return JSON.parse(contents); - } catch (e) { - logger.error( - `Failed to read overlay-base file OIDs from ${baseDatabaseOidsFilePath}: ${e.message || e}` - ); - throw e; - } -} -async function writeOverlayChangesFile(config, sourceRoot, logger) { - const baseFileOids = await readBaseDatabaseOidsFile(config, logger); - const overlayFileOids = await getFileOidsUnderPath(sourceRoot); - const oidChangedFiles = computeChangedFiles(baseFileOids, overlayFileOids); - logger.info( - `Found ${oidChangedFiles.length} changed file(s) under ${sourceRoot} from OID comparison.` - ); - const diffRangeFiles = await getDiffRangeFilePaths(sourceRoot, logger); - const changedFiles = [.../* @__PURE__ */ new Set([...oidChangedFiles, ...diffRangeFiles])]; - const changedFilesJson = JSON.stringify({ changes: changedFiles }); - const overlayChangesFile = path6.join( - getTemporaryDirectory(), - "overlay-changes.json" - ); - logger.debug( - `Writing overlay changed files to ${overlayChangesFile}: ${changedFilesJson}` - ); - await fs4.promises.writeFile(overlayChangesFile, changedFilesJson); - return overlayChangesFile; -} -function computeChangedFiles(baseFileOids, overlayFileOids) { - const changes = []; - for (const [file, oid] of Object.entries(overlayFileOids)) { - if (!(file in baseFileOids) || baseFileOids[file] !== oid) { - changes.push(file); - } - } - for (const file of Object.keys(baseFileOids)) { - if (!(file in overlayFileOids)) { - changes.push(file); - } - } - return changes; -} -async function getDiffRangeFilePaths(sourceRoot, logger) { - const jsonFilePath = getDiffRangesJsonFilePath(); - if (!fs4.existsSync(jsonFilePath)) { - logger.debug( - `No diff ranges JSON file found at ${jsonFilePath}; skipping.` - ); - return []; - } - let contents; - try { - contents = await fs4.promises.readFile(jsonFilePath, "utf8"); - } catch (e) { - logger.warning( - `Failed to read diff ranges JSON file at ${jsonFilePath}: ${e}` - ); - return []; - } - let diffRanges; - try { - diffRanges = JSON.parse(contents); - } catch (e) { - logger.warning( - `Failed to parse diff ranges JSON file at ${jsonFilePath}: ${e}` - ); - return []; - } - logger.debug( - `Read ${diffRanges.length} diff range(s) from ${jsonFilePath} for overlay changes.` - ); - const repoRoot = await getGitRoot(sourceRoot); - if (repoRoot === void 0) { - if (getOptionalInput("source-root")) { - throw new Error( - "Cannot determine git root to convert diff range paths relative to source-root. Failing to avoid omitting files from the analysis." - ); - } - logger.warning( - "Cannot determine git root; returning diff range paths as-is." - ); - return [...new Set(diffRanges.map((r) => r.path))]; - } - const relativePaths = diffRanges.map( - (r) => path6.relative(sourceRoot, path6.join(repoRoot, r.path)).replaceAll(path6.sep, "/") - ).filter((rel) => !rel.startsWith("..")); - return [...new Set(relativePaths)]; + const relativePaths = diffRanges.map( + (r) => path4.relative(sourceRoot, path4.join(repoRoot, r.path)).replaceAll(path4.sep, "/") + ).filter((rel) => !rel.startsWith("..")); + return [...new Set(relativePaths)]; } // src/tools-features.ts -var semver4 = __toESM(require_semver2()); +var semver3 = __toESM(require_semver2()); function isSupportedToolsFeature(versionInfo, feature) { return !!versionInfo.features && versionInfo.features[feature]; } @@ -87644,6 +86992,11 @@ var DEFAULT_VERSION_FEATURE_FLAG_PREFIX = "default_codeql_version_"; var DEFAULT_VERSION_FEATURE_FLAG_SUFFIX = "_enabled"; var CODEQL_VERSION_ZSTD_BUNDLE = "2.19.0"; var featureConfig = { + ["allow_multiple_analysis_kinds" /* AllowMultipleAnalysisKinds */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_ALLOW_MULTIPLE_ANALYSIS_KINDS", + minimumVersion: void 0 + }, ["allow_toolcache_input" /* AllowToolcacheInput */]: { defaultValue: false, envVar: "CODEQL_ACTION_ALLOW_TOOLCACHE_INPUT", @@ -87856,330 +87209,985 @@ var OfflineFeatures = class { constructor(logger) { this.logger = logger; } - logger; - async getDefaultCliVersion(_variant) { + logger; + async getDefaultCliVersion(_variant) { + return { + cliVersion, + tagName: bundleVersion + }; + } + /** + * Gets the `FeatureConfig` for `feature`. + */ + getFeatureConfig(feature) { + return featureConfig[feature]; + } + /** + * Determines whether `feature` is enabled without consulting the GitHub API. + * + * @param feature The feature to check. + * @param codeql An optional CodeQL object. If provided, and a `minimumVersion` is specified for the + * feature, the version of the CodeQL CLI will be checked against the minimum version. + * If the version is less than the minimum version, the feature will be considered + * disabled. If not provided, and a `minimumVersion` is specified for the feature, then + * this function will throw. + * @returns true if the feature is enabled, false otherwise. + * + * @throws if a `minimumVersion` is specified for the feature, and `codeql` is not provided. + */ + async getValue(feature, codeql) { + const offlineValue = await this.getOfflineValue(feature, codeql); + if (offlineValue !== void 0) { + return offlineValue; + } + return this.getDefaultValue(feature); + } + /** + * Determines whether `feature` is enabled using the CLI and environment variables. + */ + async getOfflineValue(feature, codeql) { + const config = this.getFeatureConfig(feature); + if (!codeql && config.minimumVersion) { + throw new Error( + `Internal error: A minimum version is specified for feature ${feature}, but no instance of CodeQL was provided.` + ); + } + if (!codeql && config.toolsFeature) { + throw new Error( + `Internal error: A required tools feature is specified for feature ${feature}, but no instance of CodeQL was provided.` + ); + } + const envVar = (process.env[config.envVar] || "").toLocaleLowerCase(); + if (envVar === "false") { + this.logger.debug( + `Feature ${feature} is disabled via the environment variable ${config.envVar}.` + ); + return false; + } + const minimumVersion2 = config.minimumVersion; + if (codeql && minimumVersion2) { + if (!await codeQlVersionAtLeast(codeql, minimumVersion2)) { + this.logger.debug( + `Feature ${feature} is disabled because the CodeQL CLI version is older than the minimum version ${minimumVersion2}.` + ); + return false; + } else { + this.logger.debug( + `CodeQL CLI version ${(await codeql.getVersion()).version} is newer than the minimum version ${minimumVersion2} for feature ${feature}.` + ); + } + } + const toolsFeature = config.toolsFeature; + if (codeql && toolsFeature) { + if (!await codeql.supportsFeature(toolsFeature)) { + this.logger.debug( + `Feature ${feature} is disabled because the CodeQL CLI version does not support the required tools feature ${toolsFeature}.` + ); + return false; + } else { + this.logger.debug( + `CodeQL CLI version ${(await codeql.getVersion()).version} supports the required tools feature ${toolsFeature} for feature ${feature}.` + ); + } + } + if (envVar === "true") { + this.logger.debug( + `Feature ${feature} is enabled via the environment variable ${config.envVar}.` + ); + return true; + } + return void 0; + } + /** Gets the default value of `feature`. */ + async getDefaultValue(feature) { + const config = this.getFeatureConfig(feature); + const defaultValue = config.defaultValue; + this.logger.debug( + `Feature ${feature} is ${defaultValue ? "enabled" : "disabled"} due to its default value.` + ); + return defaultValue; + } +}; +var Features = class extends OfflineFeatures { + gitHubFeatureFlags; + constructor(repositoryNwo, tempDir, logger) { + super(logger); + this.gitHubFeatureFlags = new GitHubFeatureFlags( + repositoryNwo, + path5.join(tempDir, FEATURE_FLAGS_FILE_NAME), + logger + ); + } + async getDefaultCliVersion(variant) { + if (supportsFeatureFlags(variant)) { + return await this.gitHubFeatureFlags.getDefaultCliVersionFromFlags(); + } + return super.getDefaultCliVersion(variant); + } + /** + * + * @param feature The feature to check. + * @param codeql An optional CodeQL object. If provided, and a `minimumVersion` is specified for the + * feature, the version of the CodeQL CLI will be checked against the minimum version. + * If the version is less than the minimum version, the feature will be considered + * disabled. If not provided, and a `minimumVersion` is specified for the feature, then + * this function will throw. + * @returns true if the feature is enabled, false otherwise. + * + * @throws if a `minimumVersion` is specified for the feature, and `codeql` is not provided. + */ + async getValue(feature, codeql) { + const offlineValue = await this.getOfflineValue(feature, codeql); + if (offlineValue !== void 0) { + return offlineValue; + } + const apiValue = await this.gitHubFeatureFlags.getValue(feature); + if (apiValue !== void 0) { + this.logger.debug( + `Feature ${feature} is ${apiValue ? "enabled" : "disabled"} via the GitHub API.` + ); + return apiValue; + } + return this.getDefaultValue(feature); + } +}; +var GitHubFeatureFlags = class { + constructor(repositoryNwo, featureFlagsFile, logger) { + this.repositoryNwo = repositoryNwo; + this.featureFlagsFile = featureFlagsFile; + this.logger = logger; + this.hasAccessedRemoteFeatureFlags = false; + } + repositoryNwo; + featureFlagsFile; + logger; + cachedApiResponse; + // We cache whether the feature flags were accessed or not in order to accurately report whether flags were + // incorrectly configured vs. inaccessible in our telemetry. + hasAccessedRemoteFeatureFlags; + getCliVersionFromFeatureFlag(f) { + if (!f.startsWith(DEFAULT_VERSION_FEATURE_FLAG_PREFIX) || !f.endsWith(DEFAULT_VERSION_FEATURE_FLAG_SUFFIX)) { + return void 0; + } + const version = f.substring( + DEFAULT_VERSION_FEATURE_FLAG_PREFIX.length, + f.length - DEFAULT_VERSION_FEATURE_FLAG_SUFFIX.length + ).replace(/_/g, "."); + if (!semver4.valid(version)) { + this.logger.warning( + `Ignoring feature flag ${f} as it does not specify a valid CodeQL version.` + ); + return void 0; + } + return version; + } + async getDefaultCliVersionFromFlags() { + const response = await this.getAllFeatures(); + const enabledFeatureFlagCliVersions = Object.entries(response).map( + ([f, isEnabled]) => isEnabled ? this.getCliVersionFromFeatureFlag(f) : void 0 + ).filter((f) => f !== void 0); + if (enabledFeatureFlagCliVersions.length === 0) { + this.logger.warning( + `Feature flags do not specify a default CLI version. Falling back to the CLI version shipped with the Action. This is ${cliVersion}.` + ); + const result = { + cliVersion, + tagName: bundleVersion + }; + if (this.hasAccessedRemoteFeatureFlags) { + result.toolsFeatureFlagsValid = false; + } + return result; + } + const maxCliVersion = enabledFeatureFlagCliVersions.reduce( + (maxVersion, currentVersion) => currentVersion > maxVersion ? currentVersion : maxVersion, + enabledFeatureFlagCliVersions[0] + ); + this.logger.debug( + `Derived default CLI version of ${maxCliVersion} from feature flags.` + ); return { - cliVersion, - tagName: bundleVersion + cliVersion: maxCliVersion, + tagName: `codeql-bundle-v${maxCliVersion}`, + toolsFeatureFlagsValid: true }; } - /** - * Gets the `FeatureConfig` for `feature`. - */ - getFeatureConfig(feature) { - return featureConfig[feature]; + async getValue(feature) { + const response = await this.getAllFeatures(); + if (response === void 0) { + this.logger.debug(`No feature flags API response for ${feature}.`); + return void 0; + } + const features = response[feature]; + if (features === void 0) { + this.logger.debug(`Feature '${feature}' undefined in API response.`); + return void 0; + } + return !!features; + } + async getAllFeatures() { + if (this.cachedApiResponse !== void 0) { + return this.cachedApiResponse; + } + const fileFlags = await this.readLocalFlags(); + if (fileFlags !== void 0) { + this.cachedApiResponse = fileFlags; + return fileFlags; + } + let remoteFlags = await this.loadApiResponse(); + if (remoteFlags === void 0) { + remoteFlags = {}; + } + this.cachedApiResponse = remoteFlags; + await this.writeLocalFlags(remoteFlags); + return remoteFlags; + } + async readLocalFlags() { + try { + if (fs5.existsSync(this.featureFlagsFile)) { + this.logger.debug( + `Loading feature flags from ${this.featureFlagsFile}` + ); + return JSON.parse( + fs5.readFileSync(this.featureFlagsFile, "utf8") + ); + } + } catch (e) { + this.logger.warning( + `Error reading cached feature flags file ${this.featureFlagsFile}: ${e}. Requesting from GitHub instead.` + ); + } + return void 0; + } + async writeLocalFlags(flags) { + try { + this.logger.debug(`Writing feature flags to ${this.featureFlagsFile}`); + fs5.writeFileSync(this.featureFlagsFile, JSON.stringify(flags)); + } catch (e) { + this.logger.warning( + `Error writing cached feature flags file ${this.featureFlagsFile}: ${e}.` + ); + } + } + async loadApiResponse() { + try { + const featuresToRequest = Object.entries(featureConfig).filter( + ([, config]) => !config.legacyApi + ).map(([f]) => f); + const FEATURES_PER_REQUEST = 25; + const featureChunks = []; + while (featuresToRequest.length > 0) { + featureChunks.push(featuresToRequest.splice(0, FEATURES_PER_REQUEST)); + } + let remoteFlags = {}; + for (const chunk of featureChunks) { + const response = await getApiClient().request( + "GET /repos/:owner/:repo/code-scanning/codeql-action/features", + { + owner: this.repositoryNwo.owner, + repo: this.repositoryNwo.repo, + features: chunk.join(",") + } + ); + const chunkFlags = response.data; + remoteFlags = { ...remoteFlags, ...chunkFlags }; + } + this.logger.debug( + "Loaded the following default values for the feature flags from the CodeQL Action API:" + ); + for (const [feature, value] of Object.entries(remoteFlags).sort( + ([nameA], [nameB]) => nameA.localeCompare(nameB) + )) { + this.logger.debug(` ${feature}: ${value}`); + } + this.hasAccessedRemoteFeatureFlags = true; + return remoteFlags; + } catch (e) { + const httpError = asHTTPError(e); + if (httpError?.status === 403) { + this.logger.warning( + `This run of the CodeQL Action does not have permission to access the CodeQL Action API endpoints. As a result, it will not be opted into any experimental features. This could be because the Action is running on a pull request from a fork. If not, please ensure the workflow has at least the 'security-events: read' permission. Details: ${httpError.message}` + ); + this.hasAccessedRemoteFeatureFlags = false; + return {}; + } else { + throw new Error( + `Encountered an error while trying to determine feature enablement: ${e}` + ); + } + } + } +}; +function supportsFeatureFlags(githubVariant) { + return githubVariant === "GitHub.com" /* DOTCOM */ || githubVariant === "GitHub Enterprise Cloud with data residency" /* GHEC_DR */; +} +function initFeatures(gitHubVersion, repositoryNwo, tempDir, logger) { + if (!supportsFeatureFlags(gitHubVersion.type)) { + logger.debug( + "Not running against github.com. Using default values for all features." + ); + return new OfflineFeatures(logger); + } else { + return new Features(repositoryNwo, tempDir, logger); + } +} + +// src/analyses.ts +var AnalysisKind = /* @__PURE__ */ ((AnalysisKind3) => { + AnalysisKind3["CodeScanning"] = "code-scanning"; + AnalysisKind3["CodeQuality"] = "code-quality"; + AnalysisKind3["RiskAssessment"] = "risk-assessment"; + return AnalysisKind3; +})(AnalysisKind || {}); +var compatibilityMatrix = { + ["code-scanning" /* CodeScanning */]: /* @__PURE__ */ new Set(["code-quality" /* CodeQuality */]), + ["code-quality" /* CodeQuality */]: /* @__PURE__ */ new Set(["code-scanning" /* CodeScanning */]), + ["risk-assessment" /* RiskAssessment */]: /* @__PURE__ */ new Set() +}; +var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); +async function parseAnalysisKinds(input) { + const components = input.split(","); + if (components.length < 1) { + throw new ConfigurationError( + "At least one analysis kind must be configured." + ); + } + for (const component of components) { + if (!supportedAnalysisKinds.has(component)) { + throw new ConfigurationError(`Unknown analysis kind: ${component}`); + } + } + return Array.from( + new Set(components.map((component) => component)) + ); +} +var cachedAnalysisKinds; +async function getAnalysisKinds(logger, features, skipCache = false) { + if (!skipCache && cachedAnalysisKinds !== void 0) { + return cachedAnalysisKinds; + } + const analysisKinds = await parseAnalysisKinds( + getRequiredInput("analysis-kinds") + ); + const qualityQueriesInput = getOptionalInput("quality-queries"); + if (qualityQueriesInput !== void 0) { + logger.warning( + "The `quality-queries` input is deprecated and will be removed in a future version of the CodeQL Action. Use the `analysis-kinds` input to configure different analysis kinds instead." + ); + } + if (!analysisKinds.includes("code-quality" /* CodeQuality */) && qualityQueriesInput !== void 0) { + analysisKinds.push("code-quality" /* CodeQuality */); + } + for (const analysisKind of analysisKinds) { + for (const otherAnalysisKind of analysisKinds) { + if (analysisKind === otherAnalysisKind) continue; + if (!compatibilityMatrix[analysisKind].has(otherAnalysisKind)) { + throw new ConfigurationError( + `${analysisKind} and ${otherAnalysisKind} cannot be enabled at the same time` + ); + } + } + } + if (!isInTestMode() && analysisKinds.length > 1 && !await features.getValue("allow_multiple_analysis_kinds" /* AllowMultipleAnalysisKinds */)) { + throw new ConfigurationError( + "The `analysis-kinds` input is experimental and for GitHub-internal use only. Its behaviour may change at any time or be removed entirely. Specifying multiple values as input is no longer supported." + ); + } + cachedAnalysisKinds = analysisKinds; + return cachedAnalysisKinds; +} +var codeQualityQueries = ["code-quality"]; + +// src/caching-utils.ts +var crypto2 = __toESM(require("crypto")); +var core7 = __toESM(require_core()); +async function getTotalCacheSize(paths, logger, quiet = false) { + const sizes = await Promise.all( + paths.map((cacheDir) => tryGetFolderBytes(cacheDir, logger, quiet)) + ); + return sizes.map((a) => a || 0).reduce((a, b) => a + b, 0); +} +function shouldRestoreCache(kind) { + return kind === "full" /* Full */ || kind === "restore" /* Restore */; +} +function getCachingKind(input) { + switch (input) { + case void 0: + case "none": + case "off": + case "false": + return "none" /* None */; + case "full": + case "on": + case "true": + return "full" /* Full */; + case "store": + return "store" /* Store */; + case "restore": + return "restore" /* Restore */; + default: + core7.warning( + `Unrecognized 'dependency-caching' input: ${input}. Defaulting to 'none'.` + ); + return "none" /* None */; } - /** - * Determines whether `feature` is enabled without consulting the GitHub API. - * - * @param feature The feature to check. - * @param codeql An optional CodeQL object. If provided, and a `minimumVersion` is specified for the - * feature, the version of the CodeQL CLI will be checked against the minimum version. - * If the version is less than the minimum version, the feature will be considered - * disabled. If not provided, and a `minimumVersion` is specified for the feature, then - * this function will throw. - * @returns true if the feature is enabled, false otherwise. - * - * @throws if a `minimumVersion` is specified for the feature, and `codeql` is not provided. - */ - async getValue(feature, codeql) { - const offlineValue = await this.getOfflineValue(feature, codeql); - if (offlineValue !== void 0) { - return offlineValue; - } - return this.getDefaultValue(feature); +} +var cacheKeyHashLength = 16; +function createCacheKeyHash(components) { + const componentsJson = JSON.stringify(components); + return crypto2.createHash("sha256").update(componentsJson).digest("hex").substring(0, cacheKeyHashLength); +} +function getDependencyCachingEnabled() { + const dependencyCaching = getOptionalInput("dependency-caching") || process.env["CODEQL_ACTION_DEPENDENCY_CACHING" /* DEPENDENCY_CACHING */]; + if (dependencyCaching !== void 0) return getCachingKind(dependencyCaching); + if (!isHostedRunner()) return "none" /* None */; + if (!isDefaultSetup()) return "none" /* None */; + return "none" /* None */; +} + +// src/config-utils.ts +var fs9 = __toESM(require("fs")); +var path10 = __toESM(require("path")); +var import_perf_hooks = require("perf_hooks"); +var core9 = __toESM(require_core()); + +// src/config/db-config.ts +var path6 = __toESM(require("path")); +var jsonschema = __toESM(require_lib2()); +var semver5 = __toESM(require_semver2()); + +// src/error-messages.ts +var PACKS_PROPERTY = "packs"; +function getConfigFileOutsideWorkspaceErrorMessage(configFile) { + return `The configuration file "${configFile}" is outside of the workspace`; +} +function getConfigFileDoesNotExistErrorMessage(configFile) { + return `The configuration file "${configFile}" does not exist`; +} +function getConfigFileParseErrorMessage(configFile, message) { + return `Cannot parse "${configFile}": ${message}`; +} +function getInvalidConfigFileMessage(configFile, messages) { + const andMore = messages.length > 10 ? `, and ${messages.length - 10} more.` : "."; + return `The configuration file "${configFile}" is invalid: ${messages.slice(0, 10).join(", ")}${andMore}`; +} +function getConfigFileRepoFormatInvalidMessage(configFile) { + let error3 = `The configuration file "${configFile}" is not a supported remote file reference.`; + error3 += " Expected format //@"; + return error3; +} +function getConfigFileFormatInvalidMessage(configFile) { + return `The configuration file "${configFile}" could not be read`; +} +function getConfigFileDirectoryGivenMessage(configFile) { + return `The configuration file "${configFile}" looks like a directory, not a file`; +} +function getEmptyCombinesError() { + return `A '+' was used to specify that you want to add extra arguments to the configuration, but no extra arguments were specified. Please either remove the '+' or specify some extra arguments.`; +} +function getConfigFilePropertyError(configFile, property, error3) { + if (configFile === void 0) { + return `The workflow property "${property}" is invalid: ${error3}`; + } else { + return `The configuration file "${configFile}" is invalid: property "${property}" ${error3}`; } - /** - * Determines whether `feature` is enabled using the CLI and environment variables. - */ - async getOfflineValue(feature, codeql) { - const config = this.getFeatureConfig(feature); - if (!codeql && config.minimumVersion) { - throw new Error( - `Internal error: A minimum version is specified for feature ${feature}, but no instance of CodeQL was provided.` - ); - } - if (!codeql && config.toolsFeature) { +} +function getRepoPropertyError(propertyName, error3) { + return `The repository property "${propertyName}" is invalid: ${error3}`; +} +function getPacksStrInvalid(packStr, configFile) { + return configFile ? getConfigFilePropertyError( + configFile, + PACKS_PROPERTY, + `"${packStr}" is not a valid pack` + ) : `"${packStr}" is not a valid pack`; +} +function getNoLanguagesError() { + return "Did not detect any languages to analyze. Please update input in workflow or check that GitHub detects the correct languages in your repository."; +} +function getUnknownLanguagesError(languages) { + return `Did not recognize the following languages: ${languages.join(", ")}`; +} + +// src/feature-flags/properties.ts +var GITHUB_CODEQL_PROPERTY_PREFIX = "github-codeql-"; +var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => { + RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay"; + RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries"; + RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs"; + return RepositoryPropertyName2; +})(RepositoryPropertyName || {}); +function isString2(value) { + return typeof value === "string"; +} +var stringProperty = { + validate: isString2, + parse: parseStringRepositoryProperty +}; +var booleanProperty = { + // The value from the API should come as a string, which we then parse into a boolean. + validate: isString2, + parse: parseBooleanRepositoryProperty +}; +var repositoryPropertyParsers = { + ["github-codeql-disable-overlay" /* DISABLE_OVERLAY */]: booleanProperty, + ["github-codeql-extra-queries" /* EXTRA_QUERIES */]: stringProperty, + ["github-codeql-file-coverage-on-prs" /* FILE_COVERAGE_ON_PRS */]: booleanProperty +}; +async function loadPropertiesFromApi(logger, repositoryNwo) { + try { + const response = await getRepositoryProperties(repositoryNwo); + const remoteProperties = response.data; + if (!Array.isArray(remoteProperties)) { throw new Error( - `Internal error: A required tools feature is specified for feature ${feature}, but no instance of CodeQL was provided.` - ); - } - const envVar = (process.env[config.envVar] || "").toLocaleLowerCase(); - if (envVar === "false") { - this.logger.debug( - `Feature ${feature} is disabled via the environment variable ${config.envVar}.` + `Expected repository properties API to return an array, but got: ${JSON.stringify(response.data)}` ); - return false; } - const minimumVersion2 = config.minimumVersion; - if (codeql && minimumVersion2) { - if (!await codeQlVersionAtLeast(codeql, minimumVersion2)) { - this.logger.debug( - `Feature ${feature} is disabled because the CodeQL CLI version is older than the minimum version ${minimumVersion2}.` - ); - return false; - } else { - this.logger.debug( - `CodeQL CLI version ${(await codeql.getVersion()).version} is newer than the minimum version ${minimumVersion2} for feature ${feature}.` + logger.debug( + `Retrieved ${remoteProperties.length} repository properties: ${remoteProperties.map((p) => p.property_name).join(", ")}` + ); + const properties = {}; + const unrecognisedProperties = []; + for (const property of remoteProperties) { + if (property.property_name === void 0) { + throw new Error( + `Expected repository property object to have a 'property_name', but got: ${JSON.stringify(property)}` ); } + if (isKnownPropertyName(property.property_name)) { + setProperty2(properties, property.property_name, property.value, logger); + } else if (property.property_name.startsWith(GITHUB_CODEQL_PROPERTY_PREFIX) && !isDynamicWorkflow()) { + unrecognisedProperties.push(property.property_name); + } } - const toolsFeature = config.toolsFeature; - if (codeql && toolsFeature) { - if (!await codeql.supportsFeature(toolsFeature)) { - this.logger.debug( - `Feature ${feature} is disabled because the CodeQL CLI version does not support the required tools feature ${toolsFeature}.` - ); - return false; - } else { - this.logger.debug( - `CodeQL CLI version ${(await codeql.getVersion()).version} supports the required tools feature ${toolsFeature} for feature ${feature}.` - ); + if (Object.keys(properties).length === 0) { + logger.debug("No known repository properties were found."); + } else { + logger.debug( + "Loaded the following values for the repository properties:" + ); + for (const [property, value] of Object.entries(properties).sort( + ([nameA], [nameB]) => nameA.localeCompare(nameB) + )) { + logger.debug(` ${property}: ${value}`); } } - if (envVar === "true") { - this.logger.debug( - `Feature ${feature} is enabled via the environment variable ${config.envVar}.` + if (unrecognisedProperties.length > 0) { + const unrecognisedPropertyList = unrecognisedProperties.map((name) => `'${name}'`).join(", "); + logger.warning( + `Found repository properties (${unrecognisedPropertyList}), which look like CodeQL Action repository properties, but which are not understood by this version of the CodeQL Action. Do you need to update to a newer version?` ); - return true; } + return properties; + } catch (e) { + throw new Error( + `Encountered an error while trying to determine repository properties: ${e}` + ); + } +} +function setProperty2(properties, name, value, logger) { + const propertyOptions = repositoryPropertyParsers[name]; + if (propertyOptions.validate(value)) { + properties[name] = propertyOptions.parse(name, value, logger); + } else { + throw new Error( + `Unexpected value for repository property '${name}' (${typeof value}), got: ${JSON.stringify(value)}` + ); + } +} +function parseBooleanRepositoryProperty(name, value, logger) { + if (value !== "true" && value !== "false") { + logger.warning( + `Repository property '${name}' has unexpected value '${value}'. Expected 'true' or 'false'. Defaulting to false.` + ); + } + return value === "true"; +} +function parseStringRepositoryProperty(_name, value) { + return value; +} +var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set( + Object.values(RepositoryPropertyName) +); +function isKnownPropertyName(name) { + return KNOWN_REPOSITORY_PROPERTY_NAMES.has(name); +} + +// src/config/db-config.ts +function shouldCombine(inputValue) { + return !!inputValue?.trim().startsWith("+"); +} +var PACK_IDENTIFIER_PATTERN = (function() { + const alphaNumeric = "[a-z0-9]"; + const alphaNumericDash = "[a-z0-9-]"; + const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`; + return new RegExp(`^${component}/${component}$`); +})(); +function parsePacksSpecification(packStr) { + if (typeof packStr !== "string") { + throw new ConfigurationError(getPacksStrInvalid(packStr)); + } + packStr = packStr.trim(); + const atIndex = packStr.indexOf("@"); + const colonIndex = packStr.indexOf(":", atIndex); + const packStart = 0; + const versionStart = atIndex + 1 || void 0; + const pathStart = colonIndex + 1 || void 0; + const packEnd = Math.min( + atIndex > 0 ? atIndex : Infinity, + colonIndex > 0 ? colonIndex : Infinity, + packStr.length + ); + const versionEnd = versionStart ? Math.min(colonIndex > 0 ? colonIndex : Infinity, packStr.length) : void 0; + const pathEnd = pathStart ? packStr.length : void 0; + const packName = packStr.slice(packStart, packEnd).trim(); + const version = versionStart ? packStr.slice(versionStart, versionEnd).trim() : void 0; + const packPath = pathStart ? packStr.slice(pathStart, pathEnd).trim() : void 0; + if (!PACK_IDENTIFIER_PATTERN.test(packName)) { + throw new ConfigurationError(getPacksStrInvalid(packStr)); + } + if (version) { + try { + new semver5.Range(version); + } catch { + throw new ConfigurationError(getPacksStrInvalid(packStr)); + } + } + if (packPath && (path6.isAbsolute(packPath) || // Permit using "/" instead of "\" on Windows + // Use `x.split(y).join(z)` as a polyfill for `x.replaceAll(y, z)` since + // if we used a regex we'd need to escape the path separator on Windows + // which seems more awkward. + path6.normalize(packPath).split(path6.sep).join("/") !== packPath.split(path6.sep).join("/"))) { + throw new ConfigurationError(getPacksStrInvalid(packStr)); + } + if (!packPath && pathStart) { + throw new ConfigurationError(getPacksStrInvalid(packStr)); + } + return { + name: packName, + version, + path: packPath + }; +} +function validatePackSpecification(pack) { + return prettyPrintPack(parsePacksSpecification(pack)); +} +function parsePacksFromInput(rawPacksInput, languages, packsInputCombines) { + if (!rawPacksInput?.trim()) { return void 0; } - /** Gets the default value of `feature`. */ - async getDefaultValue(feature) { - const config = this.getFeatureConfig(feature); - const defaultValue = config.defaultValue; - this.logger.debug( - `Feature ${feature} is ${defaultValue ? "enabled" : "disabled"} due to its default value.` + if (languages.length > 1) { + throw new ConfigurationError( + "Cannot specify a 'packs' input in a multi-language analysis. Use a codeql-config.yml file instead and specify packs by language." ); - return defaultValue; - } -}; -var Features = class extends OfflineFeatures { - gitHubFeatureFlags; - constructor(repositoryNwo, tempDir, logger) { - super(logger); - this.gitHubFeatureFlags = new GitHubFeatureFlags( - repositoryNwo, - path7.join(tempDir, FEATURE_FLAGS_FILE_NAME), - logger + } else if (languages.length === 0) { + throw new ConfigurationError( + "No languages specified. Cannot process the packs input." ); } - async getDefaultCliVersion(variant) { - if (supportsFeatureFlags(variant)) { - return await this.gitHubFeatureFlags.getDefaultCliVersionFromFlags(); - } - return super.getDefaultCliVersion(variant); - } - /** - * - * @param feature The feature to check. - * @param codeql An optional CodeQL object. If provided, and a `minimumVersion` is specified for the - * feature, the version of the CodeQL CLI will be checked against the minimum version. - * If the version is less than the minimum version, the feature will be considered - * disabled. If not provided, and a `minimumVersion` is specified for the feature, then - * this function will throw. - * @returns true if the feature is enabled, false otherwise. - * - * @throws if a `minimumVersion` is specified for the feature, and `codeql` is not provided. - */ - async getValue(feature, codeql) { - const offlineValue = await this.getOfflineValue(feature, codeql); - if (offlineValue !== void 0) { - return offlineValue; - } - const apiValue = await this.gitHubFeatureFlags.getValue(feature); - if (apiValue !== void 0) { - this.logger.debug( - `Feature ${feature} is ${apiValue ? "enabled" : "disabled"} via the GitHub API.` + rawPacksInput = rawPacksInput.trim(); + if (packsInputCombines) { + rawPacksInput = rawPacksInput.trim().substring(1).trim(); + if (!rawPacksInput) { + throw new ConfigurationError( + getConfigFilePropertyError( + void 0, + "packs", + "A '+' was used in the 'packs' input to specify that you wished to add some packs to your CodeQL analysis. However, no packs were specified. Please either remove the '+' or specify some packs." + ) ); - return apiValue; } - return this.getDefaultValue(feature); - } -}; -var GitHubFeatureFlags = class { - constructor(repositoryNwo, featureFlagsFile, logger) { - this.repositoryNwo = repositoryNwo; - this.featureFlagsFile = featureFlagsFile; - this.logger = logger; - this.hasAccessedRemoteFeatureFlags = false; } - repositoryNwo; - featureFlagsFile; - logger; - cachedApiResponse; - // We cache whether the feature flags were accessed or not in order to accurately report whether flags were - // incorrectly configured vs. inaccessible in our telemetry. - hasAccessedRemoteFeatureFlags; - getCliVersionFromFeatureFlag(f) { - if (!f.startsWith(DEFAULT_VERSION_FEATURE_FLAG_PREFIX) || !f.endsWith(DEFAULT_VERSION_FEATURE_FLAG_SUFFIX)) { - return void 0; - } - const version = f.substring( - DEFAULT_VERSION_FEATURE_FLAG_PREFIX.length, - f.length - DEFAULT_VERSION_FEATURE_FLAG_SUFFIX.length - ).replace(/_/g, "."); - if (!semver5.valid(version)) { - this.logger.warning( - `Ignoring feature flag ${f} as it does not specify a valid CodeQL version.` - ); - return void 0; - } - return version; + return { + [languages[0]]: rawPacksInput.split(",").reduce((packs, pack) => { + packs.push(validatePackSpecification(pack)); + return packs; + }, []) + }; +} +async function calculateAugmentation(rawPacksInput, rawQueriesInput, repositoryProperties, languages) { + const packsInputCombines = shouldCombine(rawPacksInput); + const packsInput = parsePacksFromInput( + rawPacksInput, + languages, + packsInputCombines + ); + const queriesInputCombines = shouldCombine(rawQueriesInput); + const queriesInput = parseQueriesFromInput( + rawQueriesInput, + queriesInputCombines + ); + const repoExtraQueries = repositoryProperties["github-codeql-extra-queries" /* EXTRA_QUERIES */]; + const repoExtraQueriesCombines = shouldCombine(repoExtraQueries); + const repoPropertyQueries = { + combines: repoExtraQueriesCombines, + input: parseQueriesFromInput( + repoExtraQueries, + repoExtraQueriesCombines, + new ConfigurationError( + getRepoPropertyError( + "github-codeql-extra-queries" /* EXTRA_QUERIES */, + getEmptyCombinesError() + ) + ) + ) + }; + return { + packsInputCombines, + packsInput: packsInput?.[languages[0]], + queriesInput, + queriesInputCombines, + repoPropertyQueries + }; +} +function parseQueriesFromInput(rawQueriesInput, queriesInputCombines, errorToThrow) { + if (!rawQueriesInput) { + return void 0; } - async getDefaultCliVersionFromFlags() { - const response = await this.getAllFeatures(); - const enabledFeatureFlagCliVersions = Object.entries(response).map( - ([f, isEnabled]) => isEnabled ? this.getCliVersionFromFeatureFlag(f) : void 0 - ).filter((f) => f !== void 0); - if (enabledFeatureFlagCliVersions.length === 0) { - this.logger.warning( - `Feature flags do not specify a default CLI version. Falling back to the CLI version shipped with the Action. This is ${cliVersion}.` - ); - const result = { - cliVersion, - tagName: bundleVersion - }; - if (this.hasAccessedRemoteFeatureFlags) { - result.toolsFeatureFlagsValid = false; - } - return result; + const trimmedInput = queriesInputCombines ? rawQueriesInput.trim().slice(1).trim() : rawQueriesInput?.trim() ?? ""; + if (queriesInputCombines && trimmedInput.length === 0) { + if (errorToThrow) { + throw errorToThrow; } - const maxCliVersion = enabledFeatureFlagCliVersions.reduce( - (maxVersion, currentVersion) => currentVersion > maxVersion ? currentVersion : maxVersion, - enabledFeatureFlagCliVersions[0] - ); - this.logger.debug( - `Derived default CLI version of ${maxCliVersion} from feature flags.` + throw new ConfigurationError( + getConfigFilePropertyError( + void 0, + "queries", + "A '+' was used in the 'queries' input to specify that you wished to add some packs to your CodeQL analysis. However, no packs were specified. Please either remove the '+' or specify some packs." + ) ); - return { - cliVersion: maxCliVersion, - tagName: `codeql-bundle-v${maxCliVersion}`, - toolsFeatureFlagsValid: true - }; } - async getValue(feature) { - const response = await this.getAllFeatures(); - if (response === void 0) { - this.logger.debug(`No feature flags API response for ${feature}.`); - return void 0; - } - const features = response[feature]; - if (features === void 0) { - this.logger.debug(`Feature '${feature}' undefined in API response.`); - return void 0; + return trimmedInput.split(",").map((query) => ({ uses: query.trim() })); +} +function combineQueries(logger, config, augmentationProperties) { + const result = []; + if (augmentationProperties.repoPropertyQueries?.input) { + logger.info( + `Found query configuration in the repository properties (${"github-codeql-extra-queries" /* EXTRA_QUERIES */}): ${augmentationProperties.repoPropertyQueries.input.map((q) => q.uses).join(", ")}` + ); + if (!augmentationProperties.repoPropertyQueries.combines) { + logger.info( + `The queries configured in the repository properties don't allow combining with other query settings. Any queries configured elsewhere will be ignored.` + ); + return augmentationProperties.repoPropertyQueries.input; + } else { + result.push(...augmentationProperties.repoPropertyQueries.input); } - return !!features; } - async getAllFeatures() { - if (this.cachedApiResponse !== void 0) { - return this.cachedApiResponse; - } - const fileFlags = await this.readLocalFlags(); - if (fileFlags !== void 0) { - this.cachedApiResponse = fileFlags; - return fileFlags; - } - let remoteFlags = await this.loadApiResponse(); - if (remoteFlags === void 0) { - remoteFlags = {}; + if (augmentationProperties.queriesInput) { + if (!augmentationProperties.queriesInputCombines) { + return result.concat(augmentationProperties.queriesInput); + } else { + result.push(...augmentationProperties.queriesInput); } - this.cachedApiResponse = remoteFlags; - await this.writeLocalFlags(remoteFlags); - return remoteFlags; } - async readLocalFlags() { - try { - if (fs5.existsSync(this.featureFlagsFile)) { - this.logger.debug( - `Loading feature flags from ${this.featureFlagsFile}` - ); - return JSON.parse( - fs5.readFileSync(this.featureFlagsFile, "utf8") + if (config.queries) { + result.push(...config.queries); + } + return result; +} +function generateCodeScanningConfig(logger, originalUserInput, augmentationProperties) { + const augmentedConfig = cloneObject(originalUserInput); + augmentedConfig.queries = combineQueries( + logger, + augmentedConfig, + augmentationProperties + ); + logger.debug( + `Combined queries: ${augmentedConfig.queries?.map((q) => q.uses).join(",")}` + ); + if (augmentedConfig.queries?.length === 0) { + delete augmentedConfig.queries; + } + if (augmentationProperties.packsInput) { + if (augmentationProperties.packsInputCombines) { + if (Array.isArray(augmentedConfig.packs)) { + augmentedConfig.packs = (augmentedConfig.packs || []).concat( + augmentationProperties.packsInput ); + } else if (!augmentedConfig.packs) { + augmentedConfig.packs = augmentationProperties.packsInput; + } else { + const language = Object.keys(augmentedConfig.packs)[0]; + augmentedConfig.packs[language] = augmentedConfig.packs[language].concat(augmentationProperties.packsInput); } - } catch (e) { - this.logger.warning( - `Error reading cached feature flags file ${this.featureFlagsFile}: ${e}. Requesting from GitHub instead.` - ); + } else { + augmentedConfig.packs = augmentationProperties.packsInput; } - return void 0; } - async writeLocalFlags(flags) { - try { - this.logger.debug(`Writing feature flags to ${this.featureFlagsFile}`); - fs5.writeFileSync(this.featureFlagsFile, JSON.stringify(flags)); - } catch (e) { - this.logger.warning( - `Error writing cached feature flags file ${this.featureFlagsFile}: ${e}.` - ); - } + if (Array.isArray(augmentedConfig.packs) && !augmentedConfig.packs.length) { + delete augmentedConfig.packs; } - async loadApiResponse() { - try { - const featuresToRequest = Object.entries(featureConfig).filter( - ([, config]) => !config.legacyApi - ).map(([f]) => f); - const FEATURES_PER_REQUEST = 25; - const featureChunks = []; - while (featuresToRequest.length > 0) { - featureChunks.push(featuresToRequest.splice(0, FEATURES_PER_REQUEST)); - } - let remoteFlags = {}; - for (const chunk of featureChunks) { - const response = await getApiClient().request( - "GET /repos/:owner/:repo/code-scanning/codeql-action/features", - { - owner: this.repositoryNwo.owner, - repo: this.repositoryNwo.repo, - features: chunk.join(",") - } + return augmentedConfig; +} +function parseUserConfig(logger, pathInput, contents, validateConfig) { + try { + const schema2 = ( + // eslint-disable-next-line @typescript-eslint/no-require-imports + require_db_config_schema() + ); + const doc = load(contents); + if (validateConfig) { + const result = new jsonschema.Validator().validate(doc, schema2); + if (result.errors.length > 0) { + for (const error3 of result.errors) { + logger.error(error3.stack); + } + throw new ConfigurationError( + getInvalidConfigFileMessage( + pathInput, + result.errors.map((e) => e.stack) + ) ); - const chunkFlags = response.data; - remoteFlags = { ...remoteFlags, ...chunkFlags }; } - this.logger.debug( - "Loaded the following default values for the feature flags from the CodeQL Action API:" + } + return doc; + } catch (error3) { + if (error3 instanceof YAMLException) { + throw new ConfigurationError( + getConfigFileParseErrorMessage(pathInput, error3.message) ); - for (const [feature, value] of Object.entries(remoteFlags).sort( - ([nameA], [nameB]) => nameA.localeCompare(nameB) - )) { - this.logger.debug(` ${feature}: ${value}`); - } - this.hasAccessedRemoteFeatureFlags = true; - return remoteFlags; - } catch (e) { - const httpError = asHTTPError(e); - if (httpError?.status === 403) { - this.logger.warning( - `This run of the CodeQL Action does not have permission to access the CodeQL Action API endpoints. As a result, it will not be opted into any experimental features. This could be because the Action is running on a pull request from a fork. If not, please ensure the workflow has at least the 'security-events: read' permission. Details: ${httpError.message}` - ); - this.hasAccessedRemoteFeatureFlags = false; - return {}; - } else { - throw new Error( - `Encountered an error while trying to determine feature enablement: ${e}` - ); - } } + throw error3; } -}; -function supportsFeatureFlags(githubVariant) { - return githubVariant === "GitHub.com" /* DOTCOM */ || githubVariant === "GitHub Enterprise Cloud with data residency" /* GHEC_DR */; } -function initFeatures(gitHubVersion, repositoryNwo, tempDir, logger) { - if (!supportsFeatureFlags(gitHubVersion.type)) { + +// src/diagnostics.ts +var import_fs = require("fs"); +var import_path = __toESM(require("path")); + +// src/logging.ts +var core8 = __toESM(require_core()); +function getActionsLogger() { + return { + debug: core8.debug, + info: core8.info, + warning: core8.warning, + error: core8.error, + isDebug: core8.isDebug, + startGroup: core8.startGroup, + endGroup: core8.endGroup + }; +} +async function withGroupAsync(groupName, f) { + core8.startGroup(groupName); + try { + return await f(); + } finally { + core8.endGroup(); + } +} +function formatDuration(durationMs) { + if (durationMs < 1e3) { + return `${durationMs}ms`; + } + if (durationMs < 60 * 1e3) { + return `${(durationMs / 1e3).toFixed(1)}s`; + } + const minutes = Math.floor(durationMs / (60 * 1e3)); + const seconds = Math.floor(durationMs % (60 * 1e3) / 1e3); + return `${minutes}m${seconds}s`; +} + +// src/diagnostics.ts +var unwrittenDiagnostics = []; +var unwrittenDefaultLanguageDiagnostics = []; +var diagnosticCounter = 0; +function makeDiagnostic(id, name, data = void 0) { + return { + ...data, + timestamp: data?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(), + source: { ...data?.source, id, name } + }; +} +function addDiagnostic(config, language, diagnostic) { + const logger = getActionsLogger(); + const databasePath = language ? getCodeQLDatabasePath(config, language) : config.dbLocation; + if ((0, import_fs.existsSync)(databasePath)) { + writeDiagnostic(config, language, diagnostic); + } else { logger.debug( - "Not running against github.com. Using default values for all features." + `Writing a diagnostic for ${language}, but the database at ${databasePath} does not exist yet.` + ); + unwrittenDiagnostics.push({ diagnostic, language }); + } +} +function addNoLanguageDiagnostic(config, diagnostic) { + if (config !== void 0) { + addDiagnostic( + config, + // Arbitrarily choose the first language. We could also choose all languages, but that + // increases the risk of misinterpreting the data. + config.languages[0], + diagnostic ); - return new OfflineFeatures(logger); } else { - return new Features(repositoryNwo, tempDir, logger); + unwrittenDefaultLanguageDiagnostics.push(diagnostic); + } +} +function writeDiagnostic(config, language, diagnostic) { + const logger = getActionsLogger(); + const databasePath = language ? getCodeQLDatabasePath(config, language) : config.dbLocation; + const diagnosticsPath = import_path.default.resolve( + databasePath, + "diagnostic", + "codeql-action" + ); + try { + (0, import_fs.mkdirSync)(diagnosticsPath, { recursive: true }); + const uniqueSuffix = (diagnosticCounter++).toString(); + const sanitizedTimestamp = diagnostic.timestamp.replace( + /[^a-zA-Z0-9.-]/g, + "" + ); + const jsonPath = import_path.default.resolve( + diagnosticsPath, + `codeql-action-${sanitizedTimestamp}-${uniqueSuffix}.json` + ); + (0, import_fs.writeFileSync)(jsonPath, JSON.stringify(diagnostic)); + } catch (err) { + logger.warning(`Unable to write diagnostic message to database: ${err}`); + logger.debug(JSON.stringify(diagnostic)); + } +} +function logUnwrittenDiagnostics() { + const logger = getActionsLogger(); + const num = unwrittenDiagnostics.length; + if (num > 0) { + logger.warning( + `${num} diagnostic(s) could not be written to the database and will not appear on the Tool Status Page.` + ); + for (const unwritten of unwrittenDiagnostics) { + logger.debug(JSON.stringify(unwritten.diagnostic)); + } + } +} +function flushDiagnostics(config) { + const logger = getActionsLogger(); + const diagnosticsCount = unwrittenDiagnostics.length + unwrittenDefaultLanguageDiagnostics.length; + logger.debug(`Writing ${diagnosticsCount} diagnostic(s) to database.`); + for (const unwritten of unwrittenDiagnostics) { + writeDiagnostic(config, unwritten.language, unwritten.diagnostic); } + for (const unwritten of unwrittenDefaultLanguageDiagnostics) { + addNoLanguageDiagnostic(config, unwritten); + } + unwrittenDiagnostics = []; + unwrittenDefaultLanguageDiagnostics = []; +} +function makeTelemetryDiagnostic(id, name, attributes) { + return makeDiagnostic(id, name, { + attributes, + visibility: { + cliSummaryTable: false, + statusPage: false, + telemetry: true + } + }); } // src/diff-informed-analysis-utils.ts +var fs6 = __toESM(require("fs")); async function shouldPerformDiffInformedAnalysis(codeql, features, logger) { return await getDiffInformedAnalysisBranches(codeql, features, logger) !== void 0; } @@ -92342,7 +92350,7 @@ async function run(startedAt) { ); let analysisKinds; try { - analysisKinds = await getAnalysisKinds(logger); + analysisKinds = await getAnalysisKinds(logger, features); } catch (err) { logger.debug( `Failed to parse analysis kinds for 'starting' status report: ${getErrorMessage(err)}` @@ -92391,7 +92399,7 @@ async function run(startedAt) { logger.info("Experimental Rust analysis enabled"); } } - analysisKinds = await getAnalysisKinds(logger); + analysisKinds = await getAnalysisKinds(logger, features); const debugMode = getOptionalInput("debug") === "true" || core15.isDebug(); const repositoryProperties = repositoryPropertiesResult.orElse({}); const fileCoverageResult = await getFileCoverageInformationEnabled( diff --git a/lib/resolve-environment-action.js b/lib/resolve-environment-action.js index e1fa46a537..c0322b31ae 100644 --- a/lib/resolve-environment-action.js +++ b/lib/resolve-environment-action.js @@ -86170,57 +86170,8 @@ var fs4 = __toESM(require("fs")); var path5 = __toESM(require("path")); var core9 = __toESM(require_core()); -// src/analyses.ts -var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { - AnalysisKind2["CodeScanning"] = "code-scanning"; - AnalysisKind2["CodeQuality"] = "code-quality"; - AnalysisKind2["RiskAssessment"] = "risk-assessment"; - return AnalysisKind2; -})(AnalysisKind || {}); -var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); - -// src/caching-utils.ts -var core6 = __toESM(require_core()); - -// src/config/db-config.ts -var jsonschema = __toESM(require_lib2()); -var semver2 = __toESM(require_semver2()); - -// src/feature-flags/properties.ts -var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => { - RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay"; - RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries"; - RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs"; - return RepositoryPropertyName2; -})(RepositoryPropertyName || {}); -var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set( - Object.values(RepositoryPropertyName) -); - -// src/config/db-config.ts -var PACK_IDENTIFIER_PATTERN = (function() { - const alphaNumeric = "[a-z0-9]"; - const alphaNumericDash = "[a-z0-9-]"; - const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`; - return new RegExp(`^${component}/${component}$`); -})(); - -// src/logging.ts -var core7 = __toESM(require_core()); -function getActionsLogger() { - return { - debug: core7.debug, - info: core7.info, - warning: core7.warning, - error: core7.error, - isDebug: core7.isDebug, - startGroup: core7.startGroup, - endGroup: core7.endGroup - }; -} - // src/feature-flags.ts -var semver5 = __toESM(require_semver2()); +var semver4 = __toESM(require_semver2()); // src/overlay/index.ts var fs3 = __toESM(require("fs")); @@ -86229,14 +86180,14 @@ var path4 = __toESM(require("path")); // src/git-utils.ts var fs2 = __toESM(require("fs")); var path3 = __toESM(require("path")); -var core8 = __toESM(require_core()); +var core6 = __toESM(require_core()); var toolrunner2 = __toESM(require_toolrunner()); var io3 = __toESM(require_io()); -var semver3 = __toESM(require_semver2()); +var semver2 = __toESM(require_semver2()); var runGitCommand = async function(workingDirectory, args, customErrorMessage, options) { let stdout = ""; let stderr = ""; - core8.debug(`Running git command: git ${args.join(" ")}`); + core6.debug(`Running git command: git ${args.join(" ")}`); try { await new toolrunner2.ToolRunner(await io3.which("git", true), args, { silent: true, @@ -86257,7 +86208,7 @@ var runGitCommand = async function(workingDirectory, args, customErrorMessage, o if (stderr.includes("not a git repository")) { reason = "The checkout path provided to the action does not appear to be a git repository."; } - core8.info(`git call failed. ${customErrorMessage} Error: ${reason}`); + core6.info(`git call failed. ${customErrorMessage} Error: ${reason}`); throw error3; } }; @@ -86386,7 +86337,7 @@ async function getRef() { ) !== head; if (hasChangedRef) { const newRef = ref.replace(pull_ref_regex, "refs/pull/$1/head"); - core8.debug( + core6.debug( `No longer on merge commit, rewriting ref from ${ref} to ${newRef}.` ); return newRef; @@ -86523,13 +86474,18 @@ async function getDiffRangeFilePaths(sourceRoot, logger) { } // src/tools-features.ts -var semver4 = __toESM(require_semver2()); +var semver3 = __toESM(require_semver2()); function isSupportedToolsFeature(versionInfo, feature) { return !!versionInfo.features && versionInfo.features[feature]; } // src/feature-flags.ts var featureConfig = { + ["allow_multiple_analysis_kinds" /* AllowMultipleAnalysisKinds */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_ALLOW_MULTIPLE_ANALYSIS_KINDS", + minimumVersion: void 0 + }, ["allow_toolcache_input" /* AllowToolcacheInput */]: { defaultValue: false, envVar: "CODEQL_ACTION_ALLOW_TOOLCACHE_INPUT", @@ -86738,6 +86694,55 @@ var featureConfig = { } }; +// src/analyses.ts +var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { + AnalysisKind2["CodeScanning"] = "code-scanning"; + AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["RiskAssessment"] = "risk-assessment"; + return AnalysisKind2; +})(AnalysisKind || {}); +var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); + +// src/caching-utils.ts +var core7 = __toESM(require_core()); + +// src/config/db-config.ts +var jsonschema = __toESM(require_lib2()); +var semver5 = __toESM(require_semver2()); + +// src/feature-flags/properties.ts +var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => { + RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay"; + RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries"; + RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs"; + return RepositoryPropertyName2; +})(RepositoryPropertyName || {}); +var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set( + Object.values(RepositoryPropertyName) +); + +// src/config/db-config.ts +var PACK_IDENTIFIER_PATTERN = (function() { + const alphaNumeric = "[a-z0-9]"; + const alphaNumericDash = "[a-z0-9-]"; + const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`; + return new RegExp(`^${component}/${component}$`); +})(); + +// src/logging.ts +var core8 = __toESM(require_core()); +function getActionsLogger() { + return { + debug: core8.debug, + info: core8.info, + warning: core8.warning, + error: core8.error, + isDebug: core8.isDebug, + startGroup: core8.startGroup, + endGroup: core8.endGroup + }; +} + // src/languages/builtin.json var builtin_default = { languages: [ diff --git a/lib/setup-codeql-action.js b/lib/setup-codeql-action.js index e86bbb192a..1e9a8dc4eb 100644 --- a/lib/setup-codeql-action.js +++ b/lib/setup-codeql-action.js @@ -86381,6 +86381,11 @@ var DEFAULT_VERSION_FEATURE_FLAG_PREFIX = "default_codeql_version_"; var DEFAULT_VERSION_FEATURE_FLAG_SUFFIX = "_enabled"; var CODEQL_VERSION_ZSTD_BUNDLE = "2.19.0"; var featureConfig = { + ["allow_multiple_analysis_kinds" /* AllowMultipleAnalysisKinds */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_ALLOW_MULTIPLE_ANALYSIS_KINDS", + minimumVersion: void 0 + }, ["allow_toolcache_input" /* AllowToolcacheInput */]: { defaultValue: false, envVar: "CODEQL_ACTION_ALLOW_TOOLCACHE_INPUT", diff --git a/lib/start-proxy-action-post.js b/lib/start-proxy-action-post.js index 6f70d70937..8bda754c66 100644 --- a/lib/start-proxy-action-post.js +++ b/lib/start-proxy-action-post.js @@ -126977,63 +126977,14 @@ var fs = __toESM(require("fs")); var path = __toESM(require("path")); var core9 = __toESM(require_core()); -// src/analyses.ts -var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { - AnalysisKind2["CodeScanning"] = "code-scanning"; - AnalysisKind2["CodeQuality"] = "code-quality"; - AnalysisKind2["RiskAssessment"] = "risk-assessment"; - return AnalysisKind2; -})(AnalysisKind || {}); -var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); - -// src/caching-utils.ts -var core6 = __toESM(require_core()); - -// src/config/db-config.ts -var jsonschema = __toESM(require_lib2()); -var semver2 = __toESM(require_semver2()); - -// src/feature-flags/properties.ts -var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => { - RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay"; - RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries"; - RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs"; - return RepositoryPropertyName2; -})(RepositoryPropertyName || {}); -var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set( - Object.values(RepositoryPropertyName) -); - -// src/config/db-config.ts -var PACK_IDENTIFIER_PATTERN = (function() { - const alphaNumeric = "[a-z0-9]"; - const alphaNumericDash = "[a-z0-9-]"; - const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`; - return new RegExp(`^${component}/${component}$`); -})(); - -// src/logging.ts -var core7 = __toESM(require_core()); -function getActionsLogger() { - return { - debug: core7.debug, - info: core7.info, - warning: core7.warning, - error: core7.error, - isDebug: core7.isDebug, - startGroup: core7.startGroup, - endGroup: core7.endGroup - }; -} - // src/feature-flags.ts -var semver5 = __toESM(require_semver2()); +var semver4 = __toESM(require_semver2()); // src/git-utils.ts -var core8 = __toESM(require_core()); +var core6 = __toESM(require_core()); var toolrunner2 = __toESM(require_toolrunner()); var io3 = __toESM(require_io()); -var semver3 = __toESM(require_semver2()); +var semver2 = __toESM(require_semver2()); // src/overlay/index.ts var CODEQL_OVERLAY_MINIMUM_VERSION = "2.23.8"; @@ -127046,10 +126997,15 @@ var CODEQL_OVERLAY_MINIMUM_VERSION_PYTHON = "2.23.9"; var CODEQL_OVERLAY_MINIMUM_VERSION_RUBY = "2.23.9"; // src/tools-features.ts -var semver4 = __toESM(require_semver2()); +var semver3 = __toESM(require_semver2()); // src/feature-flags.ts var featureConfig = { + ["allow_multiple_analysis_kinds" /* AllowMultipleAnalysisKinds */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_ALLOW_MULTIPLE_ANALYSIS_KINDS", + minimumVersion: void 0 + }, ["allow_toolcache_input" /* AllowToolcacheInput */]: { defaultValue: false, envVar: "CODEQL_ACTION_ALLOW_TOOLCACHE_INPUT", @@ -127258,6 +127214,55 @@ var featureConfig = { } }; +// src/analyses.ts +var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { + AnalysisKind2["CodeScanning"] = "code-scanning"; + AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["RiskAssessment"] = "risk-assessment"; + return AnalysisKind2; +})(AnalysisKind || {}); +var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); + +// src/caching-utils.ts +var core7 = __toESM(require_core()); + +// src/config/db-config.ts +var jsonschema = __toESM(require_lib2()); +var semver5 = __toESM(require_semver2()); + +// src/feature-flags/properties.ts +var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => { + RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay"; + RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries"; + RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs"; + return RepositoryPropertyName2; +})(RepositoryPropertyName || {}); +var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set( + Object.values(RepositoryPropertyName) +); + +// src/config/db-config.ts +var PACK_IDENTIFIER_PATTERN = (function() { + const alphaNumeric = "[a-z0-9]"; + const alphaNumericDash = "[a-z0-9-]"; + const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`; + return new RegExp(`^${component}/${component}$`); +})(); + +// src/logging.ts +var core8 = __toESM(require_core()); +function getActionsLogger() { + return { + debug: core8.debug, + info: core8.info, + warning: core8.warning, + error: core8.error, + isDebug: core8.isDebug, + startGroup: core8.startGroup, + endGroup: core8.endGroup + }; +} + // src/languages/builtin.json var builtin_default = { languages: [ diff --git a/lib/start-proxy-action.js b/lib/start-proxy-action.js index 39fd56a80a..4d45f0a5fa 100644 --- a/lib/start-proxy-action.js +++ b/lib/start-proxy-action.js @@ -103178,6 +103178,11 @@ var semver3 = __toESM(require_semver2()); var DEFAULT_VERSION_FEATURE_FLAG_PREFIX = "default_codeql_version_"; var DEFAULT_VERSION_FEATURE_FLAG_SUFFIX = "_enabled"; var featureConfig = { + ["allow_multiple_analysis_kinds" /* AllowMultipleAnalysisKinds */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_ALLOW_MULTIPLE_ANALYSIS_KINDS", + minimumVersion: void 0 + }, ["allow_toolcache_input" /* AllowToolcacheInput */]: { defaultValue: false, envVar: "CODEQL_ACTION_ALLOW_TOOLCACHE_INPUT", diff --git a/lib/upload-lib.js b/lib/upload-lib.js index f1f90b4c2a..764989a01d 100644 --- a/lib/upload-lib.js +++ b/lib/upload-lib.js @@ -88655,64 +88655,8 @@ function fixCodeQualityCategory(logger, category) { return category; } -// src/analyses.ts -var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { - AnalysisKind2["CodeScanning"] = "code-scanning"; - AnalysisKind2["CodeQuality"] = "code-quality"; - AnalysisKind2["RiskAssessment"] = "risk-assessment"; - return AnalysisKind2; -})(AnalysisKind || {}); -var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); -var CodeScanning = { - kind: "code-scanning" /* CodeScanning */, - name: "code scanning", - target: "PUT /repos/:owner/:repo/code-scanning/analysis" /* CODE_SCANNING */, - sarifExtension: ".sarif", - sarifPredicate: (name) => name.endsWith(CodeScanning.sarifExtension) && !CodeQuality.sarifPredicate(name) && !RiskAssessment.sarifPredicate(name), - fixCategory: (_, category) => category, - sentinelPrefix: "CODEQL_UPLOAD_SARIF_", - transformPayload: (payload) => payload -}; -var CodeQuality = { - kind: "code-quality" /* CodeQuality */, - name: "code quality", - target: "PUT /repos/:owner/:repo/code-quality/analysis" /* CODE_QUALITY */, - sarifExtension: ".quality.sarif", - sarifPredicate: (name) => name.endsWith(CodeQuality.sarifExtension), - fixCategory: fixCodeQualityCategory, - sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_", - transformPayload: (payload) => payload -}; -function addAssessmentId(payload) { - const rawAssessmentId = getRequiredEnvParam("CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */); - const assessmentId = parseInt(rawAssessmentId, 10); - if (Number.isNaN(assessmentId)) { - throw new Error( - `${"CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */} must not be NaN: ${rawAssessmentId}` - ); - } - if (assessmentId < 0) { - throw new Error( - `${"CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */} must not be negative: ${rawAssessmentId}` - ); - } - return { sarif: payload.sarif, assessment_id: assessmentId }; -} -var RiskAssessment = { - kind: "risk-assessment" /* RiskAssessment */, - name: "code scanning risk assessment", - target: "PUT /repos/:owner/:repo/code-scanning/risk-assessment" /* RISK_ASSESSMENT */, - sarifExtension: ".csra.sarif", - sarifPredicate: (name) => name.endsWith(RiskAssessment.sarifExtension), - fixCategory: (_, category) => category, - sentinelPrefix: "CODEQL_UPLOAD_CSRA_SARIF_", - transformPayload: addAssessmentId -}; -var SarifScanOrder = [ - RiskAssessment, - CodeQuality, - CodeScanning -]; +// src/feature-flags.ts +var semver4 = __toESM(require_semver2()); // src/api-client.ts var core5 = __toESM(require_core()); @@ -88964,524 +88908,142 @@ function wrapApiConfigurationError(e) { return e; } -// src/codeql.ts -var fs10 = __toESM(require("fs")); -var path9 = __toESM(require("path")); -var core11 = __toESM(require_core()); -var toolrunner3 = __toESM(require_toolrunner()); +// src/defaults.json +var bundleVersion = "codeql-bundle-v2.25.4"; +var cliVersion = "2.25.4"; -// src/cli-errors.ts -var SUPPORTED_PLATFORMS = [ - ["linux", "x64"], - ["win32", "x64"], - ["darwin", "x64"], - ["darwin", "arm64"] -]; -var CliError = class extends Error { - exitCode; - stderr; - constructor({ cmd, args, exitCode, stderr }) { - const prettyCommand = prettyPrintInvocation(cmd, args); - const fatalErrors = extractFatalErrors(stderr); - const autobuildErrors = extractAutobuildErrors(stderr); - let message; - if (fatalErrors) { - message = `Encountered a fatal error while running "${prettyCommand}". Exit code was ${exitCode} and error was: ${ensureEndsInPeriod( - fatalErrors.trim() - )} See the logs for more details.`; - } else if (autobuildErrors) { - message = `We were unable to automatically build your code. Please provide manual build steps. See ${"https://docs.github.com/en/code-security/code-scanning/troubleshooting-code-scanning/automatic-build-failed" /* AUTOMATIC_BUILD_FAILED */} for more information. Encountered the following error: ${autobuildErrors}`; - } else { - const lastLine = ensureEndsInPeriod( - stderr.trim().split("\n").pop()?.trim() || "n/a" - ); - message = `Encountered a fatal error while running "${prettyCommand}". Exit code was ${exitCode} and last log line was: ${lastLine} See the logs for more details.`; +// src/overlay/index.ts +var fs4 = __toESM(require("fs")); +var path4 = __toESM(require("path")); + +// src/git-utils.ts +var fs3 = __toESM(require("fs")); +var path3 = __toESM(require("path")); +var core6 = __toESM(require_core()); +var toolrunner2 = __toESM(require_toolrunner()); +var io3 = __toESM(require_io()); +var semver2 = __toESM(require_semver2()); +var runGitCommand = async function(workingDirectory, args, customErrorMessage, options) { + let stdout = ""; + let stderr = ""; + core6.debug(`Running git command: git ${args.join(" ")}`); + try { + await new toolrunner2.ToolRunner(await io3.which("git", true), args, { + silent: true, + listeners: { + stdout: (data) => { + stdout += data.toString(); + }, + stderr: (data) => { + stderr += data.toString(); + } + }, + cwd: workingDirectory, + ...options + }).exec(); + return stdout; + } catch (error3) { + let reason = stderr; + if (stderr.includes("not a git repository")) { + reason = "The checkout path provided to the action does not appear to be a git repository."; } - super(message); - this.exitCode = exitCode; - this.stderr = stderr; + core6.info(`git call failed. ${customErrorMessage} Error: ${reason}`); + throw error3; } }; -function extractFatalErrors(error3) { - const fatalErrorRegex = /.*fatal (internal )?error occurr?ed(. Details)?:/gi; - let fatalErrors = []; - let lastFatalErrorIndex; - let match; - while ((match = fatalErrorRegex.exec(error3)) !== null) { - if (lastFatalErrorIndex !== void 0) { - fatalErrors.push(error3.slice(lastFatalErrorIndex, match.index).trim()); - } - lastFatalErrorIndex = match.index; +var getCommitOid = async function(checkoutPath, ref = "HEAD") { + try { + const stdout = await runGitCommand( + checkoutPath, + ["rev-parse", ref], + "Continuing with commit SHA from user input or environment." + ); + return stdout.trim(); + } catch { + return getOptionalInput("sha") || getRequiredEnvParam("GITHUB_SHA"); } - if (lastFatalErrorIndex !== void 0) { - const lastError = error3.slice(lastFatalErrorIndex).trim(); - if (fatalErrors.length === 0) { - return lastError; +}; +var determineBaseBranchHeadCommitOid = async function(checkoutPathOverride) { + if (getWorkflowEventName() !== "pull_request") { + return void 0; + } + const mergeSha = getRequiredEnvParam("GITHUB_SHA"); + const checkoutPath = checkoutPathOverride ?? getOptionalInput("checkout_path"); + try { + let commitOid = ""; + let baseOid = ""; + let headOid = ""; + const stdout = await runGitCommand( + checkoutPath, + ["show", "-s", "--format=raw", mergeSha], + "Will calculate the base branch SHA on the server." + ); + for (const data of stdout.split("\n")) { + if (data.startsWith("commit ") && commitOid === "") { + commitOid = data.substring(7); + } else if (data.startsWith("parent ")) { + if (baseOid === "") { + baseOid = data.substring(7); + } else if (headOid === "") { + headOid = data.substring(7); + } + } } - const isOneLiner = !fatalErrors.some((e) => e.includes("\n")); - if (isOneLiner) { - fatalErrors = fatalErrors.map(ensureEndsInPeriod); + if (commitOid === mergeSha && headOid.length === 40 && baseOid.length === 40) { + return baseOid; } - return [ - ensureEndsInPeriod(lastError), - "Context:", - ...fatalErrors.reverse() - ].join(isOneLiner ? " " : "\n"); + return void 0; + } catch { + return void 0; } - return void 0; -} -function extractAutobuildErrors(error3) { - const pattern = /.*\[autobuild\] \[ERROR\] (.*)/gi; - let errorLines = [...error3.matchAll(pattern)].map((match) => match[1]); - if (errorLines.length > 10) { - errorLines = errorLines.slice(0, 10); - errorLines.push("(truncated)"); +}; +var decodeGitFilePath = function(filePath) { + if (filePath.startsWith('"') && filePath.endsWith('"')) { + filePath = filePath.substring(1, filePath.length - 1); + return filePath.replace( + /\\([abfnrtv\\"]|[0-7]{1,3})/g, + (_match, seq2) => { + switch (seq2[0]) { + case "a": + return "\x07"; + case "b": + return "\b"; + case "f": + return "\f"; + case "n": + return "\n"; + case "r": + return "\r"; + case "t": + return " "; + case "v": + return "\v"; + case "\\": + return "\\"; + case '"': + return '"'; + default: + return String.fromCharCode(parseInt(seq2, 8)); + } + } + ); } - return errorLines.join("\n") || void 0; -} -var cliErrorsConfig = { - ["AutobuildError" /* AutobuildError */]: { - cliErrorMessageCandidates: [ - new RegExp("We were unable to automatically build your code") - ] - }, - ["CouldNotCreateTempDir" /* CouldNotCreateTempDir */]: { - cliErrorMessageCandidates: [new RegExp("Could not create temp directory")] - }, - ["ExternalRepositoryCloneFailed" /* ExternalRepositoryCloneFailed */]: { - cliErrorMessageCandidates: [ - new RegExp("Failed to clone external Git repository") - ] - }, - ["GradleBuildFailed" /* GradleBuildFailed */]: { - cliErrorMessageCandidates: [ - new RegExp("\\[autobuild\\] FAILURE: Build failed with an exception.") - ] - }, - // Version of CodeQL CLI is incompatible with this version of the CodeQL Action - ["IncompatibleWithActionVersion" /* IncompatibleWithActionVersion */]: { - cliErrorMessageCandidates: [ - new RegExp("is not compatible with this CodeQL CLI") - ] - }, - ["InitCalledTwice" /* InitCalledTwice */]: { - cliErrorMessageCandidates: [ - new RegExp( - "Refusing to create databases .* but could not process any of it" - ) - ], - additionalErrorMessageToAppend: `Is the "init" action called twice in the same job?` - }, - ["InvalidConfigFile" /* InvalidConfigFile */]: { - cliErrorMessageCandidates: [ - new RegExp("Config file .* is not valid"), - new RegExp("The supplied config file is empty") - ] - }, - ["InvalidExternalRepoSpecifier" /* InvalidExternalRepoSpecifier */]: { - cliErrorMessageCandidates: [ - new RegExp("Specifier for external repository is invalid") - ] - }, - // Expected source location for database creation does not exist - ["InvalidSourceRoot" /* InvalidSourceRoot */]: { - cliErrorMessageCandidates: [new RegExp("Invalid source root")] - }, - ["MavenBuildFailed" /* MavenBuildFailed */]: { - cliErrorMessageCandidates: [ - new RegExp("\\[autobuild\\] \\[ERROR\\] Failed to execute goal") - ] - }, - ["NoBuildCommandAutodetected" /* NoBuildCommandAutodetected */]: { - cliErrorMessageCandidates: [ - new RegExp("Could not auto-detect a suitable build method") - ] - }, - ["NoBuildMethodAutodetected" /* NoBuildMethodAutodetected */]: { - cliErrorMessageCandidates: [ - new RegExp( - "Could not detect a suitable build command for the source checkout" - ) - ] - }, - // Usually when a manual build script has failed, or if an autodetected language - // was unintended to have CodeQL analysis run on it. - ["NoSourceCodeSeen" /* NoSourceCodeSeen */]: { - exitCode: 32, - cliErrorMessageCandidates: [ - new RegExp( - "CodeQL detected code written in .* but could not process any of it" - ), - new RegExp( - "CodeQL did not detect any code written in languages supported by CodeQL" - ) - ] - }, - ["NoSupportedBuildCommandSucceeded" /* NoSupportedBuildCommandSucceeded */]: { - cliErrorMessageCandidates: [ - new RegExp("No supported build command succeeded") - ] - }, - ["NoSupportedBuildSystemDetected" /* NoSupportedBuildSystemDetected */]: { - cliErrorMessageCandidates: [ - new RegExp("No supported build system detected") - ] - }, - ["OutOfMemoryOrDisk" /* OutOfMemoryOrDisk */]: { - cliErrorMessageCandidates: [ - new RegExp("CodeQL is out of memory."), - new RegExp("out of disk"), - new RegExp("No space left on device") - ], - additionalErrorMessageToAppend: "For more information, see https://gh.io/troubleshooting-code-scanning/out-of-disk-or-memory" - }, - ["PackCannotBeFound" /* PackCannotBeFound */]: { - cliErrorMessageCandidates: [ - new RegExp( - "Query pack .* cannot be found\\. Check the spelling of the pack\\." - ), - new RegExp( - "is not a .ql file, .qls file, a directory, or a query pack specification." - ) - ] - }, - ["PackMissingAuth" /* PackMissingAuth */]: { - cliErrorMessageCandidates: [ - new RegExp("GitHub Container registry .* 403 Forbidden"), - new RegExp( - "Do you need to specify a token to authenticate to the registry?" - ) - ] - }, - ["SwiftBuildFailed" /* SwiftBuildFailed */]: { - cliErrorMessageCandidates: [ - new RegExp( - "\\[autobuilder/build\\] \\[build-command-failed\\] `autobuild` failed to run the build command" - ) - ] - }, - ["SwiftIncompatibleOs" /* SwiftIncompatibleOs */]: { - cliErrorMessageCandidates: [ - new RegExp("\\[incompatible-os\\]"), - new RegExp("Swift analysis is only supported on macOS") - ] - }, - ["UnsupportedBuildMode" /* UnsupportedBuildMode */]: { - cliErrorMessageCandidates: [ - new RegExp( - "does not support the .* build mode. Please try using one of the following build modes instead" - ) - ] - }, - ["NotFoundInRegistry" /* NotFoundInRegistry */]: { - cliErrorMessageCandidates: [ - new RegExp("'.*' not found in the registry '.*'") - ] - } -}; -function getCliConfigCategoryIfExists(cliError) { - for (const [category, configuration] of Object.entries(cliErrorsConfig)) { - if (cliError.exitCode !== void 0 && configuration.exitCode !== void 0 && cliError.exitCode === configuration.exitCode) { - return category; - } - for (const e of configuration.cliErrorMessageCandidates) { - if (cliError.message.match(e) || cliError.stderr.match(e)) { - return category; - } - } - } - return void 0; -} -function isUnsupportedPlatform() { - return !SUPPORTED_PLATFORMS.some( - ([platform, arch2]) => platform === process.platform && arch2 === process.arch - ); -} -function getUnsupportedPlatformError(cliError) { - return new ConfigurationError( - `The CodeQL CLI does not support the platform/architecture combination of ${process.platform}/${process.arch} (see ${"https://codeql.github.com/docs/codeql-overview/system-requirements/" /* SYSTEM_REQUIREMENTS */}). The underlying error was: ${cliError.message}` - ); -} -function wrapCliConfigurationError(cliError) { - if (isUnsupportedPlatform()) { - return getUnsupportedPlatformError(cliError); - } - const cliConfigErrorCategory = getCliConfigCategoryIfExists(cliError); - if (cliConfigErrorCategory === void 0) { - return cliError; - } - let errorMessageBuilder = cliError.message; - const additionalErrorMessageToAppend = cliErrorsConfig[cliConfigErrorCategory].additionalErrorMessageToAppend; - if (additionalErrorMessageToAppend !== void 0) { - errorMessageBuilder = `${errorMessageBuilder} ${additionalErrorMessageToAppend}`; - } - return new ConfigurationError(errorMessageBuilder); -} - -// src/config-utils.ts -var fs6 = __toESM(require("fs")); -var path6 = __toESM(require("path")); -var core9 = __toESM(require_core()); - -// src/caching-utils.ts -var core6 = __toESM(require_core()); - -// src/config/db-config.ts -var jsonschema = __toESM(require_lib2()); -var semver2 = __toESM(require_semver2()); - -// src/feature-flags/properties.ts -var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => { - RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay"; - RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries"; - RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs"; - return RepositoryPropertyName2; -})(RepositoryPropertyName || {}); -var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set( - Object.values(RepositoryPropertyName) -); - -// src/config/db-config.ts -var PACK_IDENTIFIER_PATTERN = (function() { - const alphaNumeric = "[a-z0-9]"; - const alphaNumericDash = "[a-z0-9-]"; - const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`; - return new RegExp(`^${component}/${component}$`); -})(); - -// src/diagnostics.ts -var import_fs = require("fs"); -var import_path = __toESM(require("path")); - -// src/logging.ts -var core7 = __toESM(require_core()); -function getActionsLogger() { - return { - debug: core7.debug, - info: core7.info, - warning: core7.warning, - error: core7.error, - isDebug: core7.isDebug, - startGroup: core7.startGroup, - endGroup: core7.endGroup - }; -} -function formatDuration(durationMs) { - if (durationMs < 1e3) { - return `${durationMs}ms`; - } - if (durationMs < 60 * 1e3) { - return `${(durationMs / 1e3).toFixed(1)}s`; - } - const minutes = Math.floor(durationMs / (60 * 1e3)); - const seconds = Math.floor(durationMs % (60 * 1e3) / 1e3); - return `${minutes}m${seconds}s`; -} - -// src/diagnostics.ts -var unwrittenDiagnostics = []; -var unwrittenDefaultLanguageDiagnostics = []; -var diagnosticCounter = 0; -function makeDiagnostic(id, name, data = void 0) { - return { - ...data, - timestamp: data?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(), - source: { ...data?.source, id, name } - }; -} -function addDiagnostic(config, language, diagnostic) { - const logger = getActionsLogger(); - const databasePath = language ? getCodeQLDatabasePath(config, language) : config.dbLocation; - if ((0, import_fs.existsSync)(databasePath)) { - writeDiagnostic(config, language, diagnostic); - } else { - logger.debug( - `Writing a diagnostic for ${language}, but the database at ${databasePath} does not exist yet.` - ); - unwrittenDiagnostics.push({ diagnostic, language }); - } -} -function addNoLanguageDiagnostic(config, diagnostic) { - if (config !== void 0) { - addDiagnostic( - config, - // Arbitrarily choose the first language. We could also choose all languages, but that - // increases the risk of misinterpreting the data. - config.languages[0], - diagnostic - ); - } else { - unwrittenDefaultLanguageDiagnostics.push(diagnostic); - } -} -function writeDiagnostic(config, language, diagnostic) { - const logger = getActionsLogger(); - const databasePath = language ? getCodeQLDatabasePath(config, language) : config.dbLocation; - const diagnosticsPath = import_path.default.resolve( - databasePath, - "diagnostic", - "codeql-action" - ); - try { - (0, import_fs.mkdirSync)(diagnosticsPath, { recursive: true }); - const uniqueSuffix = (diagnosticCounter++).toString(); - const sanitizedTimestamp = diagnostic.timestamp.replace( - /[^a-zA-Z0-9.-]/g, - "" - ); - const jsonPath = import_path.default.resolve( - diagnosticsPath, - `codeql-action-${sanitizedTimestamp}-${uniqueSuffix}.json` - ); - (0, import_fs.writeFileSync)(jsonPath, JSON.stringify(diagnostic)); - } catch (err) { - logger.warning(`Unable to write diagnostic message to database: ${err}`); - logger.debug(JSON.stringify(diagnostic)); - } -} - -// src/diff-informed-analysis-utils.ts -var fs5 = __toESM(require("fs")); - -// src/feature-flags.ts -var semver5 = __toESM(require_semver2()); - -// src/defaults.json -var bundleVersion = "codeql-bundle-v2.25.4"; -var cliVersion = "2.25.4"; - -// src/overlay/index.ts -var fs4 = __toESM(require("fs")); -var path5 = __toESM(require("path")); - -// src/git-utils.ts -var fs3 = __toESM(require("fs")); -var path4 = __toESM(require("path")); -var core8 = __toESM(require_core()); -var toolrunner2 = __toESM(require_toolrunner()); -var io3 = __toESM(require_io()); -var semver3 = __toESM(require_semver2()); -var runGitCommand = async function(workingDirectory, args, customErrorMessage, options) { - let stdout = ""; - let stderr = ""; - core8.debug(`Running git command: git ${args.join(" ")}`); - try { - await new toolrunner2.ToolRunner(await io3.which("git", true), args, { - silent: true, - listeners: { - stdout: (data) => { - stdout += data.toString(); - }, - stderr: (data) => { - stderr += data.toString(); - } - }, - cwd: workingDirectory, - ...options - }).exec(); - return stdout; - } catch (error3) { - let reason = stderr; - if (stderr.includes("not a git repository")) { - reason = "The checkout path provided to the action does not appear to be a git repository."; - } - core8.info(`git call failed. ${customErrorMessage} Error: ${reason}`); - throw error3; - } -}; -var getCommitOid = async function(checkoutPath, ref = "HEAD") { - try { - const stdout = await runGitCommand( - checkoutPath, - ["rev-parse", ref], - "Continuing with commit SHA from user input or environment." - ); - return stdout.trim(); - } catch { - return getOptionalInput("sha") || getRequiredEnvParam("GITHUB_SHA"); - } -}; -var determineBaseBranchHeadCommitOid = async function(checkoutPathOverride) { - if (getWorkflowEventName() !== "pull_request") { - return void 0; - } - const mergeSha = getRequiredEnvParam("GITHUB_SHA"); - const checkoutPath = checkoutPathOverride ?? getOptionalInput("checkout_path"); - try { - let commitOid = ""; - let baseOid = ""; - let headOid = ""; - const stdout = await runGitCommand( - checkoutPath, - ["show", "-s", "--format=raw", mergeSha], - "Will calculate the base branch SHA on the server." - ); - for (const data of stdout.split("\n")) { - if (data.startsWith("commit ") && commitOid === "") { - commitOid = data.substring(7); - } else if (data.startsWith("parent ")) { - if (baseOid === "") { - baseOid = data.substring(7); - } else if (headOid === "") { - headOid = data.substring(7); - } - } - } - if (commitOid === mergeSha && headOid.length === 40 && baseOid.length === 40) { - return baseOid; - } - return void 0; - } catch { - return void 0; - } -}; -var decodeGitFilePath = function(filePath) { - if (filePath.startsWith('"') && filePath.endsWith('"')) { - filePath = filePath.substring(1, filePath.length - 1); - return filePath.replace( - /\\([abfnrtv\\"]|[0-7]{1,3})/g, - (_match, seq2) => { - switch (seq2[0]) { - case "a": - return "\x07"; - case "b": - return "\b"; - case "f": - return "\f"; - case "n": - return "\n"; - case "r": - return "\r"; - case "t": - return " "; - case "v": - return "\v"; - case "\\": - return "\\"; - case '"': - return '"'; - default: - return String.fromCharCode(parseInt(seq2, 8)); - } - } - ); - } - return filePath; -}; -var getGitRoot = async function(sourceRoot) { - try { - const stdout = await runGitCommand( - sourceRoot, - ["rev-parse", "--show-toplevel"], - `Cannot find Git repository root from the source root ${sourceRoot}.` - ); - return stdout.trim(); - } catch { - return void 0; - } -}; -function hasSubmodules(gitRoot) { - return fs3.existsSync(path4.join(gitRoot, ".gitmodules")); + return filePath; +}; +var getGitRoot = async function(sourceRoot) { + try { + const stdout = await runGitCommand( + sourceRoot, + ["rev-parse", "--show-toplevel"], + `Cannot find Git repository root from the source root ${sourceRoot}.` + ); + return stdout.trim(); + } catch { + return void 0; + } +}; +function hasSubmodules(gitRoot) { + return fs3.existsSync(path3.join(gitRoot, ".gitmodules")); } var getFileOidsUnderPath = async function(basePath) { const gitRoot = await getGitRoot(basePath); @@ -89548,7 +89110,7 @@ async function getRef() { ) !== head; if (hasChangedRef) { const newRef = ref.replace(pull_ref_regex, "refs/pull/$1/head"); - core8.debug( + core6.debug( `No longer on merge commit, rewriting ref from ${ref} to ${newRef}.` ); return newRef; @@ -89613,7 +89175,7 @@ async function writeOverlayChangesFile(config, sourceRoot, logger) { const diffRangeFiles = await getDiffRangeFilePaths(sourceRoot, logger); const changedFiles = [.../* @__PURE__ */ new Set([...oidChangedFiles, ...diffRangeFiles])]; const changedFilesJson = JSON.stringify({ changes: changedFiles }); - const overlayChangesFile = path5.join( + const overlayChangesFile = path4.join( getTemporaryDirectory(), "overlay-changes.json" ); @@ -89679,13 +89241,13 @@ async function getDiffRangeFilePaths(sourceRoot, logger) { return [...new Set(diffRanges.map((r) => r.path))]; } const relativePaths = diffRanges.map( - (r) => path5.relative(sourceRoot, path5.join(repoRoot, r.path)).replaceAll(path5.sep, "/") + (r) => path4.relative(sourceRoot, path4.join(repoRoot, r.path)).replaceAll(path4.sep, "/") ).filter((rel) => !rel.startsWith("..")); return [...new Set(relativePaths)]; } // src/tools-features.ts -var semver4 = __toESM(require_semver2()); +var semver3 = __toESM(require_semver2()); function isSupportedToolsFeature(versionInfo, feature) { return !!versionInfo.features && versionInfo.features[feature]; } @@ -89693,6 +89255,11 @@ function isSupportedToolsFeature(versionInfo, feature) { // src/feature-flags.ts var CODEQL_VERSION_ZSTD_BUNDLE = "2.19.0"; var featureConfig = { + ["allow_multiple_analysis_kinds" /* AllowMultipleAnalysisKinds */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_ALLOW_MULTIPLE_ANALYSIS_KINDS", + minimumVersion: void 0 + }, ["allow_toolcache_input" /* AllowToolcacheInput */]: { defaultValue: false, envVar: "CODEQL_ACTION_ALLOW_TOOLCACHE_INPUT", @@ -89851,57 +89418,493 @@ var featureConfig = { envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_RESOURCE_CHECKS_V2", minimumVersion: void 0 }, - ["overlay_analysis_status_check" /* OverlayAnalysisStatusCheck */]: { - defaultValue: false, - envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_STATUS_CHECK", - minimumVersion: void 0 + ["overlay_analysis_status_check" /* OverlayAnalysisStatusCheck */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_STATUS_CHECK", + minimumVersion: void 0 + }, + ["overlay_analysis_status_save" /* OverlayAnalysisStatusSave */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_STATUS_SAVE", + minimumVersion: void 0 + }, + ["overlay_analysis_skip_resource_checks" /* OverlayAnalysisSkipResourceChecks */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_SKIP_RESOURCE_CHECKS", + minimumVersion: void 0 + }, + ["qa_telemetry_enabled" /* QaTelemetryEnabled */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_QA_TELEMETRY", + legacyApi: true, + minimumVersion: void 0 + }, + ["skip_file_coverage_on_prs" /* SkipFileCoverageOnPrs */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_SKIP_FILE_COVERAGE_ON_PRS", + minimumVersion: void 0, + toolsFeature: "suppressesMissingFileBaselineWarning" /* SuppressesMissingFileBaselineWarning */ + }, + ["start_proxy_remove_unused_registries" /* StartProxyRemoveUnusedRegistries */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_START_PROXY_REMOVE_UNUSED_REGISTRIES", + minimumVersion: void 0 + }, + ["start_proxy_use_features_release" /* StartProxyUseFeaturesRelease */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_START_PROXY_USE_FEATURES_RELEASE", + minimumVersion: void 0 + }, + ["upload_overlay_db_to_api" /* UploadOverlayDbToApi */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_UPLOAD_OVERLAY_DB_TO_API", + minimumVersion: void 0, + toolsFeature: "bundleSupportsOverlay" /* BundleSupportsOverlay */ + }, + ["validate_db_config" /* ValidateDbConfig */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_VALIDATE_DB_CONFIG", + minimumVersion: void 0 + } +}; + +// src/analyses.ts +var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { + AnalysisKind2["CodeScanning"] = "code-scanning"; + AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["RiskAssessment"] = "risk-assessment"; + return AnalysisKind2; +})(AnalysisKind || {}); +var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); +var CodeScanning = { + kind: "code-scanning" /* CodeScanning */, + name: "code scanning", + target: "PUT /repos/:owner/:repo/code-scanning/analysis" /* CODE_SCANNING */, + sarifExtension: ".sarif", + sarifPredicate: (name) => name.endsWith(CodeScanning.sarifExtension) && !CodeQuality.sarifPredicate(name) && !RiskAssessment.sarifPredicate(name), + fixCategory: (_, category) => category, + sentinelPrefix: "CODEQL_UPLOAD_SARIF_", + transformPayload: (payload) => payload +}; +var CodeQuality = { + kind: "code-quality" /* CodeQuality */, + name: "code quality", + target: "PUT /repos/:owner/:repo/code-quality/analysis" /* CODE_QUALITY */, + sarifExtension: ".quality.sarif", + sarifPredicate: (name) => name.endsWith(CodeQuality.sarifExtension), + fixCategory: fixCodeQualityCategory, + sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_", + transformPayload: (payload) => payload +}; +function addAssessmentId(payload) { + const rawAssessmentId = getRequiredEnvParam("CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */); + const assessmentId = parseInt(rawAssessmentId, 10); + if (Number.isNaN(assessmentId)) { + throw new Error( + `${"CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */} must not be NaN: ${rawAssessmentId}` + ); + } + if (assessmentId < 0) { + throw new Error( + `${"CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */} must not be negative: ${rawAssessmentId}` + ); + } + return { sarif: payload.sarif, assessment_id: assessmentId }; +} +var RiskAssessment = { + kind: "risk-assessment" /* RiskAssessment */, + name: "code scanning risk assessment", + target: "PUT /repos/:owner/:repo/code-scanning/risk-assessment" /* RISK_ASSESSMENT */, + sarifExtension: ".csra.sarif", + sarifPredicate: (name) => name.endsWith(RiskAssessment.sarifExtension), + fixCategory: (_, category) => category, + sentinelPrefix: "CODEQL_UPLOAD_CSRA_SARIF_", + transformPayload: addAssessmentId +}; +var SarifScanOrder = [ + RiskAssessment, + CodeQuality, + CodeScanning +]; + +// src/codeql.ts +var fs10 = __toESM(require("fs")); +var path9 = __toESM(require("path")); +var core11 = __toESM(require_core()); +var toolrunner3 = __toESM(require_toolrunner()); + +// src/cli-errors.ts +var SUPPORTED_PLATFORMS = [ + ["linux", "x64"], + ["win32", "x64"], + ["darwin", "x64"], + ["darwin", "arm64"] +]; +var CliError = class extends Error { + exitCode; + stderr; + constructor({ cmd, args, exitCode, stderr }) { + const prettyCommand = prettyPrintInvocation(cmd, args); + const fatalErrors = extractFatalErrors(stderr); + const autobuildErrors = extractAutobuildErrors(stderr); + let message; + if (fatalErrors) { + message = `Encountered a fatal error while running "${prettyCommand}". Exit code was ${exitCode} and error was: ${ensureEndsInPeriod( + fatalErrors.trim() + )} See the logs for more details.`; + } else if (autobuildErrors) { + message = `We were unable to automatically build your code. Please provide manual build steps. See ${"https://docs.github.com/en/code-security/code-scanning/troubleshooting-code-scanning/automatic-build-failed" /* AUTOMATIC_BUILD_FAILED */} for more information. Encountered the following error: ${autobuildErrors}`; + } else { + const lastLine = ensureEndsInPeriod( + stderr.trim().split("\n").pop()?.trim() || "n/a" + ); + message = `Encountered a fatal error while running "${prettyCommand}". Exit code was ${exitCode} and last log line was: ${lastLine} See the logs for more details.`; + } + super(message); + this.exitCode = exitCode; + this.stderr = stderr; + } +}; +function extractFatalErrors(error3) { + const fatalErrorRegex = /.*fatal (internal )?error occurr?ed(. Details)?:/gi; + let fatalErrors = []; + let lastFatalErrorIndex; + let match; + while ((match = fatalErrorRegex.exec(error3)) !== null) { + if (lastFatalErrorIndex !== void 0) { + fatalErrors.push(error3.slice(lastFatalErrorIndex, match.index).trim()); + } + lastFatalErrorIndex = match.index; + } + if (lastFatalErrorIndex !== void 0) { + const lastError = error3.slice(lastFatalErrorIndex).trim(); + if (fatalErrors.length === 0) { + return lastError; + } + const isOneLiner = !fatalErrors.some((e) => e.includes("\n")); + if (isOneLiner) { + fatalErrors = fatalErrors.map(ensureEndsInPeriod); + } + return [ + ensureEndsInPeriod(lastError), + "Context:", + ...fatalErrors.reverse() + ].join(isOneLiner ? " " : "\n"); + } + return void 0; +} +function extractAutobuildErrors(error3) { + const pattern = /.*\[autobuild\] \[ERROR\] (.*)/gi; + let errorLines = [...error3.matchAll(pattern)].map((match) => match[1]); + if (errorLines.length > 10) { + errorLines = errorLines.slice(0, 10); + errorLines.push("(truncated)"); + } + return errorLines.join("\n") || void 0; +} +var cliErrorsConfig = { + ["AutobuildError" /* AutobuildError */]: { + cliErrorMessageCandidates: [ + new RegExp("We were unable to automatically build your code") + ] + }, + ["CouldNotCreateTempDir" /* CouldNotCreateTempDir */]: { + cliErrorMessageCandidates: [new RegExp("Could not create temp directory")] + }, + ["ExternalRepositoryCloneFailed" /* ExternalRepositoryCloneFailed */]: { + cliErrorMessageCandidates: [ + new RegExp("Failed to clone external Git repository") + ] + }, + ["GradleBuildFailed" /* GradleBuildFailed */]: { + cliErrorMessageCandidates: [ + new RegExp("\\[autobuild\\] FAILURE: Build failed with an exception.") + ] + }, + // Version of CodeQL CLI is incompatible with this version of the CodeQL Action + ["IncompatibleWithActionVersion" /* IncompatibleWithActionVersion */]: { + cliErrorMessageCandidates: [ + new RegExp("is not compatible with this CodeQL CLI") + ] + }, + ["InitCalledTwice" /* InitCalledTwice */]: { + cliErrorMessageCandidates: [ + new RegExp( + "Refusing to create databases .* but could not process any of it" + ) + ], + additionalErrorMessageToAppend: `Is the "init" action called twice in the same job?` + }, + ["InvalidConfigFile" /* InvalidConfigFile */]: { + cliErrorMessageCandidates: [ + new RegExp("Config file .* is not valid"), + new RegExp("The supplied config file is empty") + ] + }, + ["InvalidExternalRepoSpecifier" /* InvalidExternalRepoSpecifier */]: { + cliErrorMessageCandidates: [ + new RegExp("Specifier for external repository is invalid") + ] + }, + // Expected source location for database creation does not exist + ["InvalidSourceRoot" /* InvalidSourceRoot */]: { + cliErrorMessageCandidates: [new RegExp("Invalid source root")] + }, + ["MavenBuildFailed" /* MavenBuildFailed */]: { + cliErrorMessageCandidates: [ + new RegExp("\\[autobuild\\] \\[ERROR\\] Failed to execute goal") + ] + }, + ["NoBuildCommandAutodetected" /* NoBuildCommandAutodetected */]: { + cliErrorMessageCandidates: [ + new RegExp("Could not auto-detect a suitable build method") + ] + }, + ["NoBuildMethodAutodetected" /* NoBuildMethodAutodetected */]: { + cliErrorMessageCandidates: [ + new RegExp( + "Could not detect a suitable build command for the source checkout" + ) + ] + }, + // Usually when a manual build script has failed, or if an autodetected language + // was unintended to have CodeQL analysis run on it. + ["NoSourceCodeSeen" /* NoSourceCodeSeen */]: { + exitCode: 32, + cliErrorMessageCandidates: [ + new RegExp( + "CodeQL detected code written in .* but could not process any of it" + ), + new RegExp( + "CodeQL did not detect any code written in languages supported by CodeQL" + ) + ] + }, + ["NoSupportedBuildCommandSucceeded" /* NoSupportedBuildCommandSucceeded */]: { + cliErrorMessageCandidates: [ + new RegExp("No supported build command succeeded") + ] }, - ["overlay_analysis_status_save" /* OverlayAnalysisStatusSave */]: { - defaultValue: false, - envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_STATUS_SAVE", - minimumVersion: void 0 + ["NoSupportedBuildSystemDetected" /* NoSupportedBuildSystemDetected */]: { + cliErrorMessageCandidates: [ + new RegExp("No supported build system detected") + ] }, - ["overlay_analysis_skip_resource_checks" /* OverlayAnalysisSkipResourceChecks */]: { - defaultValue: false, - envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_SKIP_RESOURCE_CHECKS", - minimumVersion: void 0 + ["OutOfMemoryOrDisk" /* OutOfMemoryOrDisk */]: { + cliErrorMessageCandidates: [ + new RegExp("CodeQL is out of memory."), + new RegExp("out of disk"), + new RegExp("No space left on device") + ], + additionalErrorMessageToAppend: "For more information, see https://gh.io/troubleshooting-code-scanning/out-of-disk-or-memory" }, - ["qa_telemetry_enabled" /* QaTelemetryEnabled */]: { - defaultValue: false, - envVar: "CODEQL_ACTION_QA_TELEMETRY", - legacyApi: true, - minimumVersion: void 0 + ["PackCannotBeFound" /* PackCannotBeFound */]: { + cliErrorMessageCandidates: [ + new RegExp( + "Query pack .* cannot be found\\. Check the spelling of the pack\\." + ), + new RegExp( + "is not a .ql file, .qls file, a directory, or a query pack specification." + ) + ] }, - ["skip_file_coverage_on_prs" /* SkipFileCoverageOnPrs */]: { - defaultValue: false, - envVar: "CODEQL_ACTION_SKIP_FILE_COVERAGE_ON_PRS", - minimumVersion: void 0, - toolsFeature: "suppressesMissingFileBaselineWarning" /* SuppressesMissingFileBaselineWarning */ + ["PackMissingAuth" /* PackMissingAuth */]: { + cliErrorMessageCandidates: [ + new RegExp("GitHub Container registry .* 403 Forbidden"), + new RegExp( + "Do you need to specify a token to authenticate to the registry?" + ) + ] }, - ["start_proxy_remove_unused_registries" /* StartProxyRemoveUnusedRegistries */]: { - defaultValue: false, - envVar: "CODEQL_ACTION_START_PROXY_REMOVE_UNUSED_REGISTRIES", - minimumVersion: void 0 + ["SwiftBuildFailed" /* SwiftBuildFailed */]: { + cliErrorMessageCandidates: [ + new RegExp( + "\\[autobuilder/build\\] \\[build-command-failed\\] `autobuild` failed to run the build command" + ) + ] }, - ["start_proxy_use_features_release" /* StartProxyUseFeaturesRelease */]: { - defaultValue: false, - envVar: "CODEQL_ACTION_START_PROXY_USE_FEATURES_RELEASE", - minimumVersion: void 0 + ["SwiftIncompatibleOs" /* SwiftIncompatibleOs */]: { + cliErrorMessageCandidates: [ + new RegExp("\\[incompatible-os\\]"), + new RegExp("Swift analysis is only supported on macOS") + ] }, - ["upload_overlay_db_to_api" /* UploadOverlayDbToApi */]: { - defaultValue: false, - envVar: "CODEQL_ACTION_UPLOAD_OVERLAY_DB_TO_API", - minimumVersion: void 0, - toolsFeature: "bundleSupportsOverlay" /* BundleSupportsOverlay */ + ["UnsupportedBuildMode" /* UnsupportedBuildMode */]: { + cliErrorMessageCandidates: [ + new RegExp( + "does not support the .* build mode. Please try using one of the following build modes instead" + ) + ] }, - ["validate_db_config" /* ValidateDbConfig */]: { - defaultValue: false, - envVar: "CODEQL_ACTION_VALIDATE_DB_CONFIG", - minimumVersion: void 0 + ["NotFoundInRegistry" /* NotFoundInRegistry */]: { + cliErrorMessageCandidates: [ + new RegExp("'.*' not found in the registry '.*'") + ] } }; +function getCliConfigCategoryIfExists(cliError) { + for (const [category, configuration] of Object.entries(cliErrorsConfig)) { + if (cliError.exitCode !== void 0 && configuration.exitCode !== void 0 && cliError.exitCode === configuration.exitCode) { + return category; + } + for (const e of configuration.cliErrorMessageCandidates) { + if (cliError.message.match(e) || cliError.stderr.match(e)) { + return category; + } + } + } + return void 0; +} +function isUnsupportedPlatform() { + return !SUPPORTED_PLATFORMS.some( + ([platform, arch2]) => platform === process.platform && arch2 === process.arch + ); +} +function getUnsupportedPlatformError(cliError) { + return new ConfigurationError( + `The CodeQL CLI does not support the platform/architecture combination of ${process.platform}/${process.arch} (see ${"https://codeql.github.com/docs/codeql-overview/system-requirements/" /* SYSTEM_REQUIREMENTS */}). The underlying error was: ${cliError.message}` + ); +} +function wrapCliConfigurationError(cliError) { + if (isUnsupportedPlatform()) { + return getUnsupportedPlatformError(cliError); + } + const cliConfigErrorCategory = getCliConfigCategoryIfExists(cliError); + if (cliConfigErrorCategory === void 0) { + return cliError; + } + let errorMessageBuilder = cliError.message; + const additionalErrorMessageToAppend = cliErrorsConfig[cliConfigErrorCategory].additionalErrorMessageToAppend; + if (additionalErrorMessageToAppend !== void 0) { + errorMessageBuilder = `${errorMessageBuilder} ${additionalErrorMessageToAppend}`; + } + return new ConfigurationError(errorMessageBuilder); +} + +// src/config-utils.ts +var fs6 = __toESM(require("fs")); +var path6 = __toESM(require("path")); +var core9 = __toESM(require_core()); + +// src/caching-utils.ts +var core7 = __toESM(require_core()); + +// src/config/db-config.ts +var jsonschema = __toESM(require_lib2()); +var semver5 = __toESM(require_semver2()); + +// src/feature-flags/properties.ts +var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => { + RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay"; + RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries"; + RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs"; + return RepositoryPropertyName2; +})(RepositoryPropertyName || {}); +var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set( + Object.values(RepositoryPropertyName) +); + +// src/config/db-config.ts +var PACK_IDENTIFIER_PATTERN = (function() { + const alphaNumeric = "[a-z0-9]"; + const alphaNumericDash = "[a-z0-9-]"; + const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`; + return new RegExp(`^${component}/${component}$`); +})(); + +// src/diagnostics.ts +var import_fs = require("fs"); +var import_path = __toESM(require("path")); + +// src/logging.ts +var core8 = __toESM(require_core()); +function getActionsLogger() { + return { + debug: core8.debug, + info: core8.info, + warning: core8.warning, + error: core8.error, + isDebug: core8.isDebug, + startGroup: core8.startGroup, + endGroup: core8.endGroup + }; +} +function formatDuration(durationMs) { + if (durationMs < 1e3) { + return `${durationMs}ms`; + } + if (durationMs < 60 * 1e3) { + return `${(durationMs / 1e3).toFixed(1)}s`; + } + const minutes = Math.floor(durationMs / (60 * 1e3)); + const seconds = Math.floor(durationMs % (60 * 1e3) / 1e3); + return `${minutes}m${seconds}s`; +} + +// src/diagnostics.ts +var unwrittenDiagnostics = []; +var unwrittenDefaultLanguageDiagnostics = []; +var diagnosticCounter = 0; +function makeDiagnostic(id, name, data = void 0) { + return { + ...data, + timestamp: data?.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(), + source: { ...data?.source, id, name } + }; +} +function addDiagnostic(config, language, diagnostic) { + const logger = getActionsLogger(); + const databasePath = language ? getCodeQLDatabasePath(config, language) : config.dbLocation; + if ((0, import_fs.existsSync)(databasePath)) { + writeDiagnostic(config, language, diagnostic); + } else { + logger.debug( + `Writing a diagnostic for ${language}, but the database at ${databasePath} does not exist yet.` + ); + unwrittenDiagnostics.push({ diagnostic, language }); + } +} +function addNoLanguageDiagnostic(config, diagnostic) { + if (config !== void 0) { + addDiagnostic( + config, + // Arbitrarily choose the first language. We could also choose all languages, but that + // increases the risk of misinterpreting the data. + config.languages[0], + diagnostic + ); + } else { + unwrittenDefaultLanguageDiagnostics.push(diagnostic); + } +} +function writeDiagnostic(config, language, diagnostic) { + const logger = getActionsLogger(); + const databasePath = language ? getCodeQLDatabasePath(config, language) : config.dbLocation; + const diagnosticsPath = import_path.default.resolve( + databasePath, + "diagnostic", + "codeql-action" + ); + try { + (0, import_fs.mkdirSync)(diagnosticsPath, { recursive: true }); + const uniqueSuffix = (diagnosticCounter++).toString(); + const sanitizedTimestamp = diagnostic.timestamp.replace( + /[^a-zA-Z0-9.-]/g, + "" + ); + const jsonPath = import_path.default.resolve( + diagnosticsPath, + `codeql-action-${sanitizedTimestamp}-${uniqueSuffix}.json` + ); + (0, import_fs.writeFileSync)(jsonPath, JSON.stringify(diagnostic)); + } catch (err) { + logger.warning(`Unable to write diagnostic message to database: ${err}`); + logger.debug(JSON.stringify(diagnostic)); + } +} // src/diff-informed-analysis-utils.ts +var fs5 = __toESM(require("fs")); function readDiffRangesJsonFile(logger) { const jsonFilePath = getDiffRangesJsonFilePath(); if (!fs5.existsSync(jsonFilePath)) { diff --git a/lib/upload-sarif-action-post.js b/lib/upload-sarif-action-post.js index 11873a244c..0c6453af03 100644 --- a/lib/upload-sarif-action-post.js +++ b/lib/upload-sarif-action-post.js @@ -126983,223 +126983,14 @@ var import_archiver = __toESM(require_archiver()); // src/analyze.ts var io5 = __toESM(require_io()); -// src/analyses.ts -var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { - AnalysisKind2["CodeScanning"] = "code-scanning"; - AnalysisKind2["CodeQuality"] = "code-quality"; - AnalysisKind2["RiskAssessment"] = "risk-assessment"; - return AnalysisKind2; -})(AnalysisKind || {}); -var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); - -// src/autobuild.ts -var core12 = __toESM(require_core()); - -// src/codeql.ts -var core11 = __toESM(require_core()); -var toolrunner3 = __toESM(require_toolrunner()); - -// src/cli-errors.ts -var cliErrorsConfig = { - ["AutobuildError" /* AutobuildError */]: { - cliErrorMessageCandidates: [ - new RegExp("We were unable to automatically build your code") - ] - }, - ["CouldNotCreateTempDir" /* CouldNotCreateTempDir */]: { - cliErrorMessageCandidates: [new RegExp("Could not create temp directory")] - }, - ["ExternalRepositoryCloneFailed" /* ExternalRepositoryCloneFailed */]: { - cliErrorMessageCandidates: [ - new RegExp("Failed to clone external Git repository") - ] - }, - ["GradleBuildFailed" /* GradleBuildFailed */]: { - cliErrorMessageCandidates: [ - new RegExp("\\[autobuild\\] FAILURE: Build failed with an exception.") - ] - }, - // Version of CodeQL CLI is incompatible with this version of the CodeQL Action - ["IncompatibleWithActionVersion" /* IncompatibleWithActionVersion */]: { - cliErrorMessageCandidates: [ - new RegExp("is not compatible with this CodeQL CLI") - ] - }, - ["InitCalledTwice" /* InitCalledTwice */]: { - cliErrorMessageCandidates: [ - new RegExp( - "Refusing to create databases .* but could not process any of it" - ) - ], - additionalErrorMessageToAppend: `Is the "init" action called twice in the same job?` - }, - ["InvalidConfigFile" /* InvalidConfigFile */]: { - cliErrorMessageCandidates: [ - new RegExp("Config file .* is not valid"), - new RegExp("The supplied config file is empty") - ] - }, - ["InvalidExternalRepoSpecifier" /* InvalidExternalRepoSpecifier */]: { - cliErrorMessageCandidates: [ - new RegExp("Specifier for external repository is invalid") - ] - }, - // Expected source location for database creation does not exist - ["InvalidSourceRoot" /* InvalidSourceRoot */]: { - cliErrorMessageCandidates: [new RegExp("Invalid source root")] - }, - ["MavenBuildFailed" /* MavenBuildFailed */]: { - cliErrorMessageCandidates: [ - new RegExp("\\[autobuild\\] \\[ERROR\\] Failed to execute goal") - ] - }, - ["NoBuildCommandAutodetected" /* NoBuildCommandAutodetected */]: { - cliErrorMessageCandidates: [ - new RegExp("Could not auto-detect a suitable build method") - ] - }, - ["NoBuildMethodAutodetected" /* NoBuildMethodAutodetected */]: { - cliErrorMessageCandidates: [ - new RegExp( - "Could not detect a suitable build command for the source checkout" - ) - ] - }, - // Usually when a manual build script has failed, or if an autodetected language - // was unintended to have CodeQL analysis run on it. - ["NoSourceCodeSeen" /* NoSourceCodeSeen */]: { - exitCode: 32, - cliErrorMessageCandidates: [ - new RegExp( - "CodeQL detected code written in .* but could not process any of it" - ), - new RegExp( - "CodeQL did not detect any code written in languages supported by CodeQL" - ) - ] - }, - ["NoSupportedBuildCommandSucceeded" /* NoSupportedBuildCommandSucceeded */]: { - cliErrorMessageCandidates: [ - new RegExp("No supported build command succeeded") - ] - }, - ["NoSupportedBuildSystemDetected" /* NoSupportedBuildSystemDetected */]: { - cliErrorMessageCandidates: [ - new RegExp("No supported build system detected") - ] - }, - ["OutOfMemoryOrDisk" /* OutOfMemoryOrDisk */]: { - cliErrorMessageCandidates: [ - new RegExp("CodeQL is out of memory."), - new RegExp("out of disk"), - new RegExp("No space left on device") - ], - additionalErrorMessageToAppend: "For more information, see https://gh.io/troubleshooting-code-scanning/out-of-disk-or-memory" - }, - ["PackCannotBeFound" /* PackCannotBeFound */]: { - cliErrorMessageCandidates: [ - new RegExp( - "Query pack .* cannot be found\\. Check the spelling of the pack\\." - ), - new RegExp( - "is not a .ql file, .qls file, a directory, or a query pack specification." - ) - ] - }, - ["PackMissingAuth" /* PackMissingAuth */]: { - cliErrorMessageCandidates: [ - new RegExp("GitHub Container registry .* 403 Forbidden"), - new RegExp( - "Do you need to specify a token to authenticate to the registry?" - ) - ] - }, - ["SwiftBuildFailed" /* SwiftBuildFailed */]: { - cliErrorMessageCandidates: [ - new RegExp( - "\\[autobuilder/build\\] \\[build-command-failed\\] `autobuild` failed to run the build command" - ) - ] - }, - ["SwiftIncompatibleOs" /* SwiftIncompatibleOs */]: { - cliErrorMessageCandidates: [ - new RegExp("\\[incompatible-os\\]"), - new RegExp("Swift analysis is only supported on macOS") - ] - }, - ["UnsupportedBuildMode" /* UnsupportedBuildMode */]: { - cliErrorMessageCandidates: [ - new RegExp( - "does not support the .* build mode. Please try using one of the following build modes instead" - ) - ] - }, - ["NotFoundInRegistry" /* NotFoundInRegistry */]: { - cliErrorMessageCandidates: [ - new RegExp("'.*' not found in the registry '.*'") - ] - } -}; - -// src/config-utils.ts -var core9 = __toESM(require_core()); - -// src/caching-utils.ts -var core6 = __toESM(require_core()); - -// src/config/db-config.ts -var jsonschema = __toESM(require_lib5()); -var semver2 = __toESM(require_semver2()); - -// src/feature-flags/properties.ts -var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => { - RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay"; - RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries"; - RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs"; - return RepositoryPropertyName2; -})(RepositoryPropertyName || {}); -var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set( - Object.values(RepositoryPropertyName) -); - -// src/config/db-config.ts -var PACK_IDENTIFIER_PATTERN = (function() { - const alphaNumeric = "[a-z0-9]"; - const alphaNumericDash = "[a-z0-9-]"; - const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`; - return new RegExp(`^${component}/${component}$`); -})(); - -// src/logging.ts -var core7 = __toESM(require_core()); -function getActionsLogger() { - return { - debug: core7.debug, - info: core7.info, - warning: core7.warning, - error: core7.error, - isDebug: core7.isDebug, - startGroup: core7.startGroup, - endGroup: core7.endGroup - }; -} -function withGroup(groupName, f) { - core7.startGroup(groupName); - try { - return f(); - } finally { - core7.endGroup(); - } -} - // src/feature-flags.ts -var semver5 = __toESM(require_semver2()); +var semver4 = __toESM(require_semver2()); // src/git-utils.ts -var core8 = __toESM(require_core()); +var core6 = __toESM(require_core()); var toolrunner2 = __toESM(require_toolrunner()); var io3 = __toESM(require_io()); -var semver3 = __toESM(require_semver2()); +var semver2 = __toESM(require_semver2()); // src/overlay/index.ts var CODEQL_OVERLAY_MINIMUM_VERSION = "2.23.8"; @@ -127212,14 +127003,19 @@ var CODEQL_OVERLAY_MINIMUM_VERSION_PYTHON = "2.23.9"; var CODEQL_OVERLAY_MINIMUM_VERSION_RUBY = "2.23.9"; // src/tools-features.ts -var semver4 = __toESM(require_semver2()); +var semver3 = __toESM(require_semver2()); var SafeArtifactUploadVersion = "2.20.3"; function isSafeArtifactUpload(codeQlVersion) { - return !codeQlVersion ? true : semver4.gte(codeQlVersion, SafeArtifactUploadVersion); + return !codeQlVersion ? true : semver3.gte(codeQlVersion, SafeArtifactUploadVersion); } // src/feature-flags.ts var featureConfig = { + ["allow_multiple_analysis_kinds" /* AllowMultipleAnalysisKinds */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_ALLOW_MULTIPLE_ANALYSIS_KINDS", + minimumVersion: void 0 + }, ["allow_toolcache_input" /* AllowToolcacheInput */]: { defaultValue: false, envVar: "CODEQL_ACTION_ALLOW_TOOLCACHE_INPUT", @@ -127428,6 +127224,215 @@ var featureConfig = { } }; +// src/analyses.ts +var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { + AnalysisKind2["CodeScanning"] = "code-scanning"; + AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["RiskAssessment"] = "risk-assessment"; + return AnalysisKind2; +})(AnalysisKind || {}); +var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); + +// src/autobuild.ts +var core12 = __toESM(require_core()); + +// src/codeql.ts +var core11 = __toESM(require_core()); +var toolrunner3 = __toESM(require_toolrunner()); + +// src/cli-errors.ts +var cliErrorsConfig = { + ["AutobuildError" /* AutobuildError */]: { + cliErrorMessageCandidates: [ + new RegExp("We were unable to automatically build your code") + ] + }, + ["CouldNotCreateTempDir" /* CouldNotCreateTempDir */]: { + cliErrorMessageCandidates: [new RegExp("Could not create temp directory")] + }, + ["ExternalRepositoryCloneFailed" /* ExternalRepositoryCloneFailed */]: { + cliErrorMessageCandidates: [ + new RegExp("Failed to clone external Git repository") + ] + }, + ["GradleBuildFailed" /* GradleBuildFailed */]: { + cliErrorMessageCandidates: [ + new RegExp("\\[autobuild\\] FAILURE: Build failed with an exception.") + ] + }, + // Version of CodeQL CLI is incompatible with this version of the CodeQL Action + ["IncompatibleWithActionVersion" /* IncompatibleWithActionVersion */]: { + cliErrorMessageCandidates: [ + new RegExp("is not compatible with this CodeQL CLI") + ] + }, + ["InitCalledTwice" /* InitCalledTwice */]: { + cliErrorMessageCandidates: [ + new RegExp( + "Refusing to create databases .* but could not process any of it" + ) + ], + additionalErrorMessageToAppend: `Is the "init" action called twice in the same job?` + }, + ["InvalidConfigFile" /* InvalidConfigFile */]: { + cliErrorMessageCandidates: [ + new RegExp("Config file .* is not valid"), + new RegExp("The supplied config file is empty") + ] + }, + ["InvalidExternalRepoSpecifier" /* InvalidExternalRepoSpecifier */]: { + cliErrorMessageCandidates: [ + new RegExp("Specifier for external repository is invalid") + ] + }, + // Expected source location for database creation does not exist + ["InvalidSourceRoot" /* InvalidSourceRoot */]: { + cliErrorMessageCandidates: [new RegExp("Invalid source root")] + }, + ["MavenBuildFailed" /* MavenBuildFailed */]: { + cliErrorMessageCandidates: [ + new RegExp("\\[autobuild\\] \\[ERROR\\] Failed to execute goal") + ] + }, + ["NoBuildCommandAutodetected" /* NoBuildCommandAutodetected */]: { + cliErrorMessageCandidates: [ + new RegExp("Could not auto-detect a suitable build method") + ] + }, + ["NoBuildMethodAutodetected" /* NoBuildMethodAutodetected */]: { + cliErrorMessageCandidates: [ + new RegExp( + "Could not detect a suitable build command for the source checkout" + ) + ] + }, + // Usually when a manual build script has failed, or if an autodetected language + // was unintended to have CodeQL analysis run on it. + ["NoSourceCodeSeen" /* NoSourceCodeSeen */]: { + exitCode: 32, + cliErrorMessageCandidates: [ + new RegExp( + "CodeQL detected code written in .* but could not process any of it" + ), + new RegExp( + "CodeQL did not detect any code written in languages supported by CodeQL" + ) + ] + }, + ["NoSupportedBuildCommandSucceeded" /* NoSupportedBuildCommandSucceeded */]: { + cliErrorMessageCandidates: [ + new RegExp("No supported build command succeeded") + ] + }, + ["NoSupportedBuildSystemDetected" /* NoSupportedBuildSystemDetected */]: { + cliErrorMessageCandidates: [ + new RegExp("No supported build system detected") + ] + }, + ["OutOfMemoryOrDisk" /* OutOfMemoryOrDisk */]: { + cliErrorMessageCandidates: [ + new RegExp("CodeQL is out of memory."), + new RegExp("out of disk"), + new RegExp("No space left on device") + ], + additionalErrorMessageToAppend: "For more information, see https://gh.io/troubleshooting-code-scanning/out-of-disk-or-memory" + }, + ["PackCannotBeFound" /* PackCannotBeFound */]: { + cliErrorMessageCandidates: [ + new RegExp( + "Query pack .* cannot be found\\. Check the spelling of the pack\\." + ), + new RegExp( + "is not a .ql file, .qls file, a directory, or a query pack specification." + ) + ] + }, + ["PackMissingAuth" /* PackMissingAuth */]: { + cliErrorMessageCandidates: [ + new RegExp("GitHub Container registry .* 403 Forbidden"), + new RegExp( + "Do you need to specify a token to authenticate to the registry?" + ) + ] + }, + ["SwiftBuildFailed" /* SwiftBuildFailed */]: { + cliErrorMessageCandidates: [ + new RegExp( + "\\[autobuilder/build\\] \\[build-command-failed\\] `autobuild` failed to run the build command" + ) + ] + }, + ["SwiftIncompatibleOs" /* SwiftIncompatibleOs */]: { + cliErrorMessageCandidates: [ + new RegExp("\\[incompatible-os\\]"), + new RegExp("Swift analysis is only supported on macOS") + ] + }, + ["UnsupportedBuildMode" /* UnsupportedBuildMode */]: { + cliErrorMessageCandidates: [ + new RegExp( + "does not support the .* build mode. Please try using one of the following build modes instead" + ) + ] + }, + ["NotFoundInRegistry" /* NotFoundInRegistry */]: { + cliErrorMessageCandidates: [ + new RegExp("'.*' not found in the registry '.*'") + ] + } +}; + +// src/config-utils.ts +var core9 = __toESM(require_core()); + +// src/caching-utils.ts +var core7 = __toESM(require_core()); + +// src/config/db-config.ts +var jsonschema = __toESM(require_lib5()); +var semver5 = __toESM(require_semver2()); + +// src/feature-flags/properties.ts +var RepositoryPropertyName = /* @__PURE__ */ ((RepositoryPropertyName2) => { + RepositoryPropertyName2["DISABLE_OVERLAY"] = "github-codeql-disable-overlay"; + RepositoryPropertyName2["EXTRA_QUERIES"] = "github-codeql-extra-queries"; + RepositoryPropertyName2["FILE_COVERAGE_ON_PRS"] = "github-codeql-file-coverage-on-prs"; + return RepositoryPropertyName2; +})(RepositoryPropertyName || {}); +var KNOWN_REPOSITORY_PROPERTY_NAMES = new Set( + Object.values(RepositoryPropertyName) +); + +// src/config/db-config.ts +var PACK_IDENTIFIER_PATTERN = (function() { + const alphaNumeric = "[a-z0-9]"; + const alphaNumericDash = "[a-z0-9-]"; + const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`; + return new RegExp(`^${component}/${component}$`); +})(); + +// src/logging.ts +var core8 = __toESM(require_core()); +function getActionsLogger() { + return { + debug: core8.debug, + info: core8.info, + warning: core8.warning, + error: core8.error, + isDebug: core8.isDebug, + startGroup: core8.startGroup, + endGroup: core8.endGroup + }; +} +function withGroup(groupName, f) { + core8.startGroup(groupName); + try { + return f(); + } finally { + core8.endGroup(); + } +} + // src/languages/builtin.json var builtin_default = { languages: [ diff --git a/lib/upload-sarif-action.js b/lib/upload-sarif-action.js index 75e8744beb..4f22c134d4 100644 --- a/lib/upload-sarif-action.js +++ b/lib/upload-sarif-action.js @@ -88693,74 +88693,10 @@ function fixCodeQualityCategory(logger, category) { return category; } -// src/analyses.ts -var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { - AnalysisKind2["CodeScanning"] = "code-scanning"; - AnalysisKind2["CodeQuality"] = "code-quality"; - AnalysisKind2["RiskAssessment"] = "risk-assessment"; - return AnalysisKind2; -})(AnalysisKind || {}); -var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); -var CodeScanning = { - kind: "code-scanning" /* CodeScanning */, - name: "code scanning", - target: "PUT /repos/:owner/:repo/code-scanning/analysis" /* CODE_SCANNING */, - sarifExtension: ".sarif", - sarifPredicate: (name) => name.endsWith(CodeScanning.sarifExtension) && !CodeQuality.sarifPredicate(name) && !RiskAssessment.sarifPredicate(name), - fixCategory: (_, category) => category, - sentinelPrefix: "CODEQL_UPLOAD_SARIF_", - transformPayload: (payload) => payload -}; -var CodeQuality = { - kind: "code-quality" /* CodeQuality */, - name: "code quality", - target: "PUT /repos/:owner/:repo/code-quality/analysis" /* CODE_QUALITY */, - sarifExtension: ".quality.sarif", - sarifPredicate: (name) => name.endsWith(CodeQuality.sarifExtension), - fixCategory: fixCodeQualityCategory, - sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_", - transformPayload: (payload) => payload -}; -function addAssessmentId(payload) { - const rawAssessmentId = getRequiredEnvParam("CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */); - const assessmentId = parseInt(rawAssessmentId, 10); - if (Number.isNaN(assessmentId)) { - throw new Error( - `${"CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */} must not be NaN: ${rawAssessmentId}` - ); - } - if (assessmentId < 0) { - throw new Error( - `${"CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */} must not be negative: ${rawAssessmentId}` - ); - } - return { sarif: payload.sarif, assessment_id: assessmentId }; -} -var RiskAssessment = { - kind: "risk-assessment" /* RiskAssessment */, - name: "code scanning risk assessment", - target: "PUT /repos/:owner/:repo/code-scanning/risk-assessment" /* RISK_ASSESSMENT */, - sarifExtension: ".csra.sarif", - sarifPredicate: (name) => name.endsWith(RiskAssessment.sarifExtension), - fixCategory: (_, category) => category, - sentinelPrefix: "CODEQL_UPLOAD_CSRA_SARIF_", - transformPayload: addAssessmentId -}; -function getAnalysisConfig(kind) { - switch (kind) { - case "code-scanning" /* CodeScanning */: - return CodeScanning; - case "code-quality" /* CodeQuality */: - return CodeQuality; - case "risk-assessment" /* RiskAssessment */: - return RiskAssessment; - } -} -var SarifScanOrder = [ - RiskAssessment, - CodeQuality, - CodeScanning -]; +// src/feature-flags.ts +var fs5 = __toESM(require("fs")); +var path5 = __toESM(require("path")); +var semver4 = __toESM(require_semver2()); // src/api-client.ts var core5 = __toESM(require_core()); @@ -89012,11 +88948,6 @@ function wrapApiConfigurationError(e) { return e; } -// src/feature-flags.ts -var fs5 = __toESM(require("fs")); -var path5 = __toESM(require("path")); -var semver4 = __toESM(require_semver2()); - // src/defaults.json var bundleVersion = "codeql-bundle-v2.25.4"; var cliVersion = "2.25.4"; @@ -89366,6 +89297,11 @@ var DEFAULT_VERSION_FEATURE_FLAG_PREFIX = "default_codeql_version_"; var DEFAULT_VERSION_FEATURE_FLAG_SUFFIX = "_enabled"; var CODEQL_VERSION_ZSTD_BUNDLE = "2.19.0"; var featureConfig = { + ["allow_multiple_analysis_kinds" /* AllowMultipleAnalysisKinds */]: { + defaultValue: false, + envVar: "CODEQL_ACTION_ALLOW_MULTIPLE_ANALYSIS_KINDS", + minimumVersion: void 0 + }, ["allow_toolcache_input" /* AllowToolcacheInput */]: { defaultValue: false, envVar: "CODEQL_ACTION_ALLOW_TOOLCACHE_INPUT", @@ -89901,6 +89837,75 @@ function initFeatures(gitHubVersion, repositoryNwo, tempDir, logger) { } } +// src/analyses.ts +var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => { + AnalysisKind2["CodeScanning"] = "code-scanning"; + AnalysisKind2["CodeQuality"] = "code-quality"; + AnalysisKind2["RiskAssessment"] = "risk-assessment"; + return AnalysisKind2; +})(AnalysisKind || {}); +var supportedAnalysisKinds = new Set(Object.values(AnalysisKind)); +var CodeScanning = { + kind: "code-scanning" /* CodeScanning */, + name: "code scanning", + target: "PUT /repos/:owner/:repo/code-scanning/analysis" /* CODE_SCANNING */, + sarifExtension: ".sarif", + sarifPredicate: (name) => name.endsWith(CodeScanning.sarifExtension) && !CodeQuality.sarifPredicate(name) && !RiskAssessment.sarifPredicate(name), + fixCategory: (_, category) => category, + sentinelPrefix: "CODEQL_UPLOAD_SARIF_", + transformPayload: (payload) => payload +}; +var CodeQuality = { + kind: "code-quality" /* CodeQuality */, + name: "code quality", + target: "PUT /repos/:owner/:repo/code-quality/analysis" /* CODE_QUALITY */, + sarifExtension: ".quality.sarif", + sarifPredicate: (name) => name.endsWith(CodeQuality.sarifExtension), + fixCategory: fixCodeQualityCategory, + sentinelPrefix: "CODEQL_UPLOAD_QUALITY_SARIF_", + transformPayload: (payload) => payload +}; +function addAssessmentId(payload) { + const rawAssessmentId = getRequiredEnvParam("CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */); + const assessmentId = parseInt(rawAssessmentId, 10); + if (Number.isNaN(assessmentId)) { + throw new Error( + `${"CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */} must not be NaN: ${rawAssessmentId}` + ); + } + if (assessmentId < 0) { + throw new Error( + `${"CODEQL_ACTION_RISK_ASSESSMENT_ID" /* RISK_ASSESSMENT_ID */} must not be negative: ${rawAssessmentId}` + ); + } + return { sarif: payload.sarif, assessment_id: assessmentId }; +} +var RiskAssessment = { + kind: "risk-assessment" /* RiskAssessment */, + name: "code scanning risk assessment", + target: "PUT /repos/:owner/:repo/code-scanning/risk-assessment" /* RISK_ASSESSMENT */, + sarifExtension: ".csra.sarif", + sarifPredicate: (name) => name.endsWith(RiskAssessment.sarifExtension), + fixCategory: (_, category) => category, + sentinelPrefix: "CODEQL_UPLOAD_CSRA_SARIF_", + transformPayload: addAssessmentId +}; +function getAnalysisConfig(kind) { + switch (kind) { + case "code-scanning" /* CodeScanning */: + return CodeScanning; + case "code-quality" /* CodeQuality */: + return CodeQuality; + case "risk-assessment" /* RiskAssessment */: + return RiskAssessment; + } +} +var SarifScanOrder = [ + RiskAssessment, + CodeQuality, + CodeScanning +]; + // src/logging.ts var core7 = __toESM(require_core()); function getActionsLogger() { diff --git a/src/analyses.test.ts b/src/analyses.test.ts index 293b4be6d2..02df6134c0 100644 --- a/src/analyses.test.ts +++ b/src/analyses.test.ts @@ -16,7 +16,7 @@ import { } from "./analyses"; import { EnvVar } from "./environment"; import { getRunnerLogger } from "./logging"; -import { setupTests } from "./testing-utils"; +import { createFeatures, setupTests } from "./testing-utils"; import { AssessmentPayload } from "./upload-lib/types"; import { ConfigurationError } from "./util"; @@ -53,24 +53,54 @@ test("Parsing analysis kinds requires at least one analysis kind", async (t) => test.serial( "getAnalysisKinds - returns expected analysis kinds for `analysis-kinds` input", async (t) => { + process.env[EnvVar.TEST_MODE] = "true"; + const features = createFeatures([]); const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput"); requiredInputStub .withArgs("analysis-kinds") .returns("code-scanning,code-quality"); - const result = await getAnalysisKinds(getRunnerLogger(true), true); + const result = await getAnalysisKinds( + getRunnerLogger(true), + features, + true, + ); t.assert(result.includes(AnalysisKind.CodeScanning)); t.assert(result.includes(AnalysisKind.CodeQuality)); }, ); +test.serial( + "getAnalysisKinds - throws for multiple analysis kinds outside of test mode", + async (t) => { + process.env[EnvVar.TEST_MODE] = "false"; + const features = createFeatures([]); + const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput"); + requiredInputStub + .withArgs("analysis-kinds") + .returns("code-scanning,code-quality"); + await t.throwsAsync( + getAnalysisKinds(getRunnerLogger(true), features, true), + { + instanceOf: ConfigurationError, + }, + ); + }, +); + test.serial( "getAnalysisKinds - includes `code-quality` when deprecated `quality-queries` input is used", async (t) => { + process.env[EnvVar.TEST_MODE] = "true"; + const features = createFeatures([]); const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput"); requiredInputStub.withArgs("analysis-kinds").returns("code-scanning"); const optionalInputStub = sinon.stub(actionsUtil, "getOptionalInput"); optionalInputStub.withArgs("quality-queries").returns("code-quality"); - const result = await getAnalysisKinds(getRunnerLogger(true), true); + const result = await getAnalysisKinds( + getRunnerLogger(true), + features, + true, + ); t.assert(result.includes(AnalysisKind.CodeScanning)); t.assert(result.includes(AnalysisKind.CodeQuality)); }, @@ -79,9 +109,12 @@ test.serial( test.serial( "getAnalysisKinds - throws if `analysis-kinds` input is invalid", async (t) => { + const features = createFeatures([]); const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput"); requiredInputStub.withArgs("analysis-kinds").returns("no-such-thing"); - await t.throwsAsync(getAnalysisKinds(getRunnerLogger(true), true)); + await t.throwsAsync( + getAnalysisKinds(getRunnerLogger(true), features, true), + ); }, ); @@ -98,11 +131,17 @@ for (let i = 0; i < analysisKinds.length; i++) { test.serial( `getAnalysisKinds - allows ${analysisKind} with ${otherAnalysis}`, async (t) => { + process.env[EnvVar.TEST_MODE] = "true"; + const features = createFeatures([]); const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput"); requiredInputStub .withArgs("analysis-kinds") .returns([analysisKind, otherAnalysis].join(",")); - const result = await getAnalysisKinds(getRunnerLogger(true), true); + const result = await getAnalysisKinds( + getRunnerLogger(true), + features, + true, + ); t.is(result.length, 2); }, ); @@ -110,14 +149,18 @@ for (let i = 0; i < analysisKinds.length; i++) { test.serial( `getAnalysisKinds - throws if ${analysisKind} is enabled with ${otherAnalysis}`, async (t) => { + const features = createFeatures([]); const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput"); requiredInputStub .withArgs("analysis-kinds") .returns([analysisKind, otherAnalysis].join(",")); - await t.throwsAsync(getAnalysisKinds(getRunnerLogger(true), true), { - instanceOf: ConfigurationError, - message: `${analysisKind} and ${otherAnalysis} cannot be enabled at the same time`, - }); + await t.throwsAsync( + getAnalysisKinds(getRunnerLogger(true), features, true), + { + instanceOf: ConfigurationError, + message: `${analysisKind} and ${otherAnalysis} cannot be enabled at the same time`, + }, + ); }, ); } diff --git a/src/analyses.ts b/src/analyses.ts index 11063a3726..69247ab78c 100644 --- a/src/analyses.ts +++ b/src/analyses.ts @@ -4,13 +4,14 @@ import { getRequiredInput, } from "./actions-util"; import { EnvVar } from "./environment"; +import { Feature, FeatureEnablement } from "./feature-flags"; import { Logger } from "./logging"; import { AssessmentPayload, BasePayload, UploadPayload, } from "./upload-lib/types"; -import { ConfigurationError, getRequiredEnvParam } from "./util"; +import { ConfigurationError, getRequiredEnvParam, isInTestMode } from "./util"; export enum AnalysisKind { CodeScanning = "code-scanning", @@ -77,6 +78,7 @@ let cachedAnalysisKinds: AnalysisKind[] | undefined; */ export async function getAnalysisKinds( logger: Logger, + features: FeatureEnablement, skipCache: boolean = false, ): Promise { if (!skipCache && cachedAnalysisKinds !== undefined) { @@ -120,6 +122,19 @@ export async function getAnalysisKinds( } } + // Throw an error if we have multiple inputs for `analysis-kinds` outside of test mode. + if ( + !isInTestMode() && + analysisKinds.length > 1 && + !(await features.getValue(Feature.AllowMultipleAnalysisKinds)) + ) { + throw new ConfigurationError( + "The `analysis-kinds` input is experimental and for GitHub-internal use only. " + + "Its behaviour may change at any time or be removed entirely. " + + "Specifying multiple values as input is no longer supported.", + ); + } + // Cache the analysis kinds and return them. cachedAnalysisKinds = analysisKinds; return cachedAnalysisKinds; diff --git a/src/feature-flags.ts b/src/feature-flags.ts index d28800e9b8..50f10d6ed2 100644 --- a/src/feature-flags.ts +++ b/src/feature-flags.ts @@ -44,6 +44,8 @@ export interface CodeQLDefaultVersionInfo { * Legacy features should end with `_enabled`. */ export enum Feature { + /** Controls whether we allow multiple values for the `analysis-kinds` input. */ + AllowMultipleAnalysisKinds = "allow_multiple_analysis_kinds", AllowToolcacheInput = "allow_toolcache_input", CleanupTrapCaches = "cleanup_trap_caches", CppDependencyInstallation = "cpp_dependency_installation_enabled", @@ -124,6 +126,11 @@ export type FeatureConfig = { }; export const featureConfig = { + [Feature.AllowMultipleAnalysisKinds]: { + defaultValue: false, + envVar: "CODEQL_ACTION_ALLOW_MULTIPLE_ANALYSIS_KINDS", + minimumVersion: undefined, + }, [Feature.AllowToolcacheInput]: { defaultValue: false, envVar: "CODEQL_ACTION_ALLOW_TOOLCACHE_INPUT", diff --git a/src/init-action.ts b/src/init-action.ts index 859dcefa2c..7d46596806 100644 --- a/src/init-action.ts +++ b/src/init-action.ts @@ -281,7 +281,7 @@ async function run(startedAt: Date) { // successful, the results are cached so that we don't duplicate the work in normal runs. let analysisKinds: AnalysisKind[] | undefined; try { - analysisKinds = await getAnalysisKinds(logger); + analysisKinds = await getAnalysisKinds(logger, features); } catch (err) { logger.debug( `Failed to parse analysis kinds for 'starting' status report: ${getErrorMessage(err)}`, @@ -346,7 +346,7 @@ async function run(startedAt: Date) { } } - analysisKinds = await getAnalysisKinds(logger); + analysisKinds = await getAnalysisKinds(logger, features); const debugMode = getOptionalInput("debug") === "true" || core.isDebug(); const repositoryProperties = repositoryPropertiesResult.orElse({}); const fileCoverageResult = await getFileCoverageInformationEnabled( From 312a2fee968d17552828b941776d9a3185adf6c8 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Tue, 12 May 2026 15:03:58 +0100 Subject: [PATCH 2/3] Add changelog entry --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7463862936..db23331b58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th ## [UNRELEASED] -No user facing changes. +- An error is now thrown if multiple inputs are provided for the GitHub-internal `analysis-kinds` input. The `analysis-kinds` input is experimental, for GitHub-internal use only, and may change without notice at any time. [#3892](https://github.com/github/codeql-action/pull/3892) ## 4.35.4 - 07 May 2026 From 257b3d3fc8c43360913681efccc21bc2f00429bc Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Tue, 12 May 2026 15:46:28 +0100 Subject: [PATCH 3/3] Enable only `code-scanning` --- CHANGELOG.md | 2 +- lib/init-action.js | 6 ++++-- src/analyses.test.ts | 16 +++++++++------- src/analyses.ts | 12 +++++++++--- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db23331b58..a5270ebc9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th ## [UNRELEASED] -- An error is now thrown if multiple inputs are provided for the GitHub-internal `analysis-kinds` input. The `analysis-kinds` input is experimental, for GitHub-internal use only, and may change without notice at any time. [#3892](https://github.com/github/codeql-action/pull/3892) +- If multiple inputs are provided for the GitHub-internal `analysis-kinds` input, only `code-scanning` will be enabled. The `analysis-kinds` input is experimental, for GitHub-internal use only, and may change without notice at any time. [#3892](https://github.com/github/codeql-action/pull/3892) ## 4.35.4 - 07 May 2026 diff --git a/lib/init-action.js b/lib/init-action.js index c6f67eec45..5cdc800db9 100644 --- a/lib/init-action.js +++ b/lib/init-action.js @@ -87589,9 +87589,11 @@ async function getAnalysisKinds(logger, features, skipCache = false) { } } if (!isInTestMode() && analysisKinds.length > 1 && !await features.getValue("allow_multiple_analysis_kinds" /* AllowMultipleAnalysisKinds */)) { - throw new ConfigurationError( - "The `analysis-kinds` input is experimental and for GitHub-internal use only. Its behaviour may change at any time or be removed entirely. Specifying multiple values as input is no longer supported." + logger.error( + "The `analysis-kinds` input is experimental and for GitHub-internal use only. Its behaviour may change at any time or be removed entirely. Specifying multiple values as input is no longer supported. Continuing with only `analysis-kinds: code-scanning`." ); + cachedAnalysisKinds = ["code-scanning" /* CodeScanning */]; + return cachedAnalysisKinds; } cachedAnalysisKinds = analysisKinds; return cachedAnalysisKinds; diff --git a/src/analyses.test.ts b/src/analyses.test.ts index 02df6134c0..57848ebd39 100644 --- a/src/analyses.test.ts +++ b/src/analyses.test.ts @@ -16,7 +16,7 @@ import { } from "./analyses"; import { EnvVar } from "./environment"; import { getRunnerLogger } from "./logging"; -import { createFeatures, setupTests } from "./testing-utils"; +import { createFeatures, RecordingLogger, setupTests } from "./testing-utils"; import { AssessmentPayload } from "./upload-lib/types"; import { ConfigurationError } from "./util"; @@ -70,19 +70,21 @@ test.serial( ); test.serial( - "getAnalysisKinds - throws for multiple analysis kinds outside of test mode", + "getAnalysisKinds - only use `code-scanning` for multiple analysis kinds outside of test mode", async (t) => { process.env[EnvVar.TEST_MODE] = "false"; const features = createFeatures([]); + const logger = new RecordingLogger(); const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput"); requiredInputStub .withArgs("analysis-kinds") .returns("code-scanning,code-quality"); - await t.throwsAsync( - getAnalysisKinds(getRunnerLogger(true), features, true), - { - instanceOf: ConfigurationError, - }, + const result = await getAnalysisKinds(logger, features, true); + t.deepEqual(result, [AnalysisKind.CodeScanning]); + t.assert( + logger.hasMessage( + "Continuing with only `analysis-kinds: code-scanning`.", + ), ); }, ); diff --git a/src/analyses.ts b/src/analyses.ts index 69247ab78c..a2dd5e8db5 100644 --- a/src/analyses.ts +++ b/src/analyses.ts @@ -122,17 +122,23 @@ export async function getAnalysisKinds( } } - // Throw an error if we have multiple inputs for `analysis-kinds` outside of test mode. + // Log an error if we have multiple inputs for `analysis-kinds` outside of test mode, + // and enable only `code-scanning`. if ( !isInTestMode() && analysisKinds.length > 1 && !(await features.getValue(Feature.AllowMultipleAnalysisKinds)) ) { - throw new ConfigurationError( + logger.error( "The `analysis-kinds` input is experimental and for GitHub-internal use only. " + "Its behaviour may change at any time or be removed entirely. " + - "Specifying multiple values as input is no longer supported.", + "Specifying multiple values as input is no longer supported. " + + "Continuing with only `analysis-kinds: code-scanning`.", ); + + // Only enable Code Scanning. + cachedAnalysisKinds = [AnalysisKind.CodeScanning]; + return cachedAnalysisKinds; } // Cache the analysis kinds and return them.