"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.computeAutomationID = exports.getAutomationID = exports.getAnalysisKey = exports.getWorkflowRelativePath = exports.sendStatusReport = exports.createStatusReportBase = exports.getGitHubVersion = exports.getGitHubVersionFromApi = exports.getApiClientWithExternalAuth = exports.getApiClient = exports.getApiDetails = exports.DisallowedAPIVersionReason = void 0; const os = __importStar(require("os")); const core = __importStar(require("@actions/core")); const githubUtils = __importStar(require("@actions/github/lib/utils")); const retry = __importStar(require("@octokit/plugin-retry")); const console_log_level_1 = __importDefault(require("console-log-level")); const actions_util_1 = require("./actions-util"); const environment_1 = require("./environment"); const util_1 = require("./util"); const GITHUB_ENTERPRISE_VERSION_HEADER = "x-github-enterprise-version"; var DisallowedAPIVersionReason; (function (DisallowedAPIVersionReason) { DisallowedAPIVersionReason[DisallowedAPIVersionReason["ACTION_TOO_OLD"] = 0] = "ACTION_TOO_OLD"; DisallowedAPIVersionReason[DisallowedAPIVersionReason["ACTION_TOO_NEW"] = 1] = "ACTION_TOO_NEW"; })(DisallowedAPIVersionReason || (exports.DisallowedAPIVersionReason = DisallowedAPIVersionReason = {})); function createApiClientWithDetails(apiDetails, { allowExternal = false } = {}) { const auth = (allowExternal && apiDetails.externalRepoAuth) || apiDetails.auth; const retryingOctokit = githubUtils.GitHub.plugin(retry.retry); return new retryingOctokit(githubUtils.getOctokitOptions(auth, { baseUrl: apiDetails.apiURL, userAgent: `CodeQL-Action/${(0, actions_util_1.getActionVersion)()}`, log: (0, console_log_level_1.default)({ level: "debug" }), })); } function getApiDetails() { return { auth: (0, actions_util_1.getRequiredInput)("token"), url: (0, util_1.getRequiredEnvParam)("GITHUB_SERVER_URL"), apiURL: (0, util_1.getRequiredEnvParam)("GITHUB_API_URL"), }; } exports.getApiDetails = getApiDetails; function getApiClient() { return createApiClientWithDetails(getApiDetails()); } exports.getApiClient = getApiClient; function getApiClientWithExternalAuth(apiDetails) { return createApiClientWithDetails(apiDetails, { allowExternal: true }); } exports.getApiClientWithExternalAuth = getApiClientWithExternalAuth; let cachedGitHubVersion = undefined; async function getGitHubVersionFromApi(apiClient, apiDetails) { // We can avoid making an API request in the standard dotcom case if ((0, util_1.parseGitHubUrl)(apiDetails.url) === util_1.GITHUB_DOTCOM_URL) { return { type: util_1.GitHubVariant.DOTCOM }; } // Doesn't strictly have to be the meta endpoint as we're only // using the response headers which are available on every request. const response = await apiClient.rest.meta.get(); // This happens on dotcom, although we expect to have already returned in that // case. This can also serve as a fallback in cases we haven't foreseen. if (response.headers[GITHUB_ENTERPRISE_VERSION_HEADER] === undefined) { return { type: util_1.GitHubVariant.DOTCOM }; } if (response.headers[GITHUB_ENTERPRISE_VERSION_HEADER] === "GitHub AE") { return { type: util_1.GitHubVariant.GHAE }; } if (response.headers[GITHUB_ENTERPRISE_VERSION_HEADER] === "ghe.com") { return { type: util_1.GitHubVariant.GHE_DOTCOM }; } const version = response.headers[GITHUB_ENTERPRISE_VERSION_HEADER]; return { type: util_1.GitHubVariant.GHES, version }; } exports.getGitHubVersionFromApi = getGitHubVersionFromApi; /** * Report the GitHub server version. This is a wrapper around * util.getGitHubVersion() that automatically supplies GitHub API details using * GitHub Action inputs. * * @returns GitHub version */ async function getGitHubVersion() { if (cachedGitHubVersion === undefined) { cachedGitHubVersion = await getGitHubVersionFromApi(getApiClient(), getApiDetails()); } return cachedGitHubVersion; } exports.getGitHubVersion = getGitHubVersion; /** * Compose a StatusReport. * * @param actionName The name of the action, e.g. 'init', 'finish', 'upload-sarif' * @param status The status. Must be 'success', 'failure', or 'starting' * @param startedAt The time this action started executing. * @param cause Cause of failure (only supply if status is 'failure') * @param exception Exception (only supply if status is 'failure') */ async function createStatusReportBase(actionName, status, actionStartedAt, cause, exception) { const commitOid = (0, actions_util_1.getOptionalInput)("sha") || process.env["GITHUB_SHA"] || ""; const ref = await (0, actions_util_1.getRef)(); const jobRunUUID = process.env[environment_1.EnvVar.JOB_RUN_UUID] || ""; const workflowRunID = (0, actions_util_1.getWorkflowRunID)(); const workflowRunAttempt = (0, actions_util_1.getWorkflowRunAttempt)(); const workflowName = process.env["GITHUB_WORKFLOW"] || ""; const jobName = process.env["GITHUB_JOB"] || ""; const analysis_key = await getAnalysisKey(); let workflowStartedAt = process.env[environment_1.EnvVar.WORKFLOW_STARTED_AT]; if (workflowStartedAt === undefined) { workflowStartedAt = actionStartedAt.toISOString(); core.exportVariable(environment_1.EnvVar.WORKFLOW_STARTED_AT, workflowStartedAt); } const runnerOs = (0, util_1.getRequiredEnvParam)("RUNNER_OS"); const codeQlCliVersion = (0, util_1.getCachedCodeQlVersion)(); const actionRef = process.env["GITHUB_ACTION_REF"]; const testingEnvironment = process.env[environment_1.EnvVar.TESTING_ENVIRONMENT] || ""; // re-export the testing environment variable so that it is available to subsequent steps, // even if it was only set for this step if (testingEnvironment !== "") { core.exportVariable(environment_1.EnvVar.TESTING_ENVIRONMENT, testingEnvironment); } const statusReport = { job_run_uuid: jobRunUUID, workflow_run_id: workflowRunID, workflow_run_attempt: workflowRunAttempt, workflow_name: workflowName, job_name: jobName, analysis_key, commit_oid: commitOid, ref, action_name: actionName, action_ref: actionRef, action_oid: "unknown", started_at: workflowStartedAt, action_started_at: actionStartedAt.toISOString(), status, testing_environment: testingEnvironment, runner_os: runnerOs, action_version: (0, actions_util_1.getActionVersion)(), }; // Add optional parameters if (cause) { statusReport.cause = cause; } if (exception) { statusReport.exception = exception; } if (status === "success" || status === "failure" || status === "aborted" || status === "user-error") { statusReport.completed_at = new Date().toISOString(); } const matrix = (0, actions_util_1.getRequiredInput)("matrix"); if (matrix) { statusReport.matrix_vars = matrix; } if ("RUNNER_ARCH" in process.env) { // RUNNER_ARCH is available only in GHES 3.4 and later // Values other than X86, X64, ARM, or ARM64 are discarded server side statusReport.runner_arch = process.env["RUNNER_ARCH"]; } if (runnerOs === "Windows" || runnerOs === "macOS") { statusReport.runner_os_release = os.release(); } if (codeQlCliVersion !== undefined) { statusReport.codeql_version = codeQlCliVersion; } return statusReport; } exports.createStatusReportBase = createStatusReportBase; const GENERIC_403_MSG = "The repo on which this action is running is not opted-in to CodeQL code scanning."; const GENERIC_404_MSG = "Not authorized to use the CodeQL code scanning feature on this repo."; const OUT_OF_DATE_MSG = "CodeQL Action is out-of-date. Please upgrade to the latest version of codeql-action."; const INCOMPATIBLE_MSG = "CodeQL Action version is incompatible with the code scanning endpoint. Please update to a compatible version of codeql-action."; /** * Send a status report to the code_scanning/analysis/status endpoint. * * Optionally checks the response from the API endpoint and sets the action * as failed if the status report failed. This is only expected to be used * when sending a 'starting' report. * * Returns whether sending the status report was successful of not. */ async function sendStatusReport(statusReport) { const statusReportJSON = JSON.stringify(statusReport); core.debug(`Sending status report: ${statusReportJSON}`); // If in test mode we don't want to upload the results if ((0, util_1.isInTestMode)()) { core.debug("In test mode. Status reports are not uploaded."); return true; } const nwo = (0, util_1.getRequiredEnvParam)("GITHUB_REPOSITORY"); const [owner, repo] = nwo.split("/"); const client = getApiClient(); try { await client.request("PUT /repos/:owner/:repo/code-scanning/analysis/status", { owner, repo, data: statusReportJSON, }); return true; } catch (e) { console.log(e); if ((0, util_1.isHTTPError)(e)) { switch (e.status) { case 403: if ((0, actions_util_1.getWorkflowEventName)() === "push" && process.env["GITHUB_ACTOR"] === "dependabot[bot]") { core.setFailed('Workflows triggered by Dependabot on the "push" event run with read-only access. ' + "Uploading Code Scanning results requires write access. " + 'To use Code Scanning with Dependabot, please ensure you are using the "pull_request" event for this workflow and avoid triggering on the "push" event for Dependabot branches. ' + "See https://docs.github.com/en/code-security/secure-coding/configuring-code-scanning#scanning-on-push for more information on how to configure these events."); } else { core.setFailed(e.message || GENERIC_403_MSG); } return false; case 404: core.setFailed(GENERIC_404_MSG); return false; case 422: // schema incompatibility when reporting status // this means that this action version is no longer compatible with the API // we still want to continue as it is likely the analysis endpoint will work if ((0, util_1.getRequiredEnvParam)("GITHUB_SERVER_URL") !== util_1.GITHUB_DOTCOM_URL) { core.debug(INCOMPATIBLE_MSG); } else { core.debug(OUT_OF_DATE_MSG); } return true; } } // something else has gone wrong and the request/response will be logged by octokit // it's possible this is a transient error and we should continue scanning core.error("An unexpected error occurred when sending code scanning status report."); return true; } } exports.sendStatusReport = sendStatusReport; /** * Get the path of the currently executing workflow relative to the repository root. */ async function getWorkflowRelativePath() { const repo_nwo = (0, util_1.getRequiredEnvParam)("GITHUB_REPOSITORY").split("/"); const owner = repo_nwo[0]; const repo = repo_nwo[1]; const run_id = Number((0, util_1.getRequiredEnvParam)("GITHUB_RUN_ID")); const apiClient = getApiClient(); const runsResponse = await apiClient.request("GET /repos/:owner/:repo/actions/runs/:run_id?exclude_pull_requests=true", { owner, repo, run_id, }); const workflowUrl = runsResponse.data.workflow_url; const workflowResponse = await apiClient.request(`GET ${workflowUrl}`); return workflowResponse.data.path; } exports.getWorkflowRelativePath = getWorkflowRelativePath; /** * Get the analysis key parameter for the current job. * * This will combine the workflow path and current job name. * Computing this the first time requires making requests to * the GitHub API, but after that the result will be cached. */ async function getAnalysisKey() { const analysisKeyEnvVar = "CODEQL_ACTION_ANALYSIS_KEY"; let analysisKey = process.env[analysisKeyEnvVar]; if (analysisKey !== undefined) { return analysisKey; } const workflowPath = await getWorkflowRelativePath(); const jobName = (0, util_1.getRequiredEnvParam)("GITHUB_JOB"); analysisKey = `${workflowPath}:${jobName}`; core.exportVariable(analysisKeyEnvVar, analysisKey); return analysisKey; } exports.getAnalysisKey = getAnalysisKey; async function getAutomationID() { const analysis_key = await getAnalysisKey(); const environment = (0, actions_util_1.getRequiredInput)("matrix"); return computeAutomationID(analysis_key, environment); } exports.getAutomationID = getAutomationID; function computeAutomationID(analysis_key, environment) { let automationID = `${analysis_key}/`; const matrix = (0, util_1.parseMatrixInput)(environment); if (matrix !== undefined) { // the id has to be deterministic so we sort the fields for (const entry of Object.entries(matrix).sort()) { if (typeof entry[1] === "string") { automationID += `${entry[0]}:${entry[1]}/`; } else { // In code scanning we just handle the string values, // the rest get converted to the empty string automationID += `${entry[0]}:/`; } } } return automationID; } exports.computeAutomationID = computeAutomationID; //# sourceMappingURL=api-client.js.map