import * as path from "path"; import { exportVariable } from "@actions/core"; import * as githubUtils from "@actions/github/lib/utils"; import * as retry from "@octokit/plugin-retry"; import { OctokitResponse } from "@octokit/types"; import consoleLogLevel from "console-log-level"; import * as semver from "semver"; import { getRequiredEnvParam, getRequiredInput } from "./actions-util"; import * as apiCompatibility from "./api-compatibility.json"; import { Logger, getActionsLogger } from "./logging"; import { isLocalRun, Mode } from "./util"; export enum DisallowedAPIVersionReason { ACTION_TOO_OLD, ACTION_TOO_NEW, } const GITHUB_ENTERPRISE_VERSION_HEADER = "x-github-enterprise-version"; const CODEQL_ACTION_WARNED_ABOUT_VERSION_ENV_VAR = "CODEQL_ACTION_WARNED_ABOUT_VERSION"; let hasBeenWarnedAboutVersion = false; export const getApiClient = function ( githubAuth: string, githubUrl: string, mode: Mode, logger: Logger, allowLocalRun = false, possibleFailureExpected = false ) { if (isLocalRun() && !allowLocalRun) { throw new Error("Invalid API call in local run"); } const customOctokit = githubUtils.GitHub.plugin(retry.retry, (octokit, _) => { octokit.hook.after("request", (response: OctokitResponse<any>, _) => { if (response.status < 400 && !possibleFailureExpected) { if (hasBeenWarnedAboutVersion) { return; } } if ( response.headers[GITHUB_ENTERPRISE_VERSION_HEADER] === undefined || process.env[CODEQL_ACTION_WARNED_ABOUT_VERSION_ENV_VAR] === undefined ) { return; } const installedVersion = response.headers[ GITHUB_ENTERPRISE_VERSION_HEADER ] as string; const disallowedAPIVersionReason = apiVersionInRange( installedVersion, apiCompatibility.minimumVersion, apiCompatibility.maximumVersion ); const toolName = mode === "actions" ? "Action" : "Runner"; if ( disallowedAPIVersionReason === DisallowedAPIVersionReason.ACTION_TOO_OLD ) { logger.warning( `The CodeQL ${toolName} version you are using is too old to be compatible with GitHub Enterprise ${installedVersion}. If you experience issues, please upgrade to a more recent version of the CodeQL ${toolName}.` ); } if ( disallowedAPIVersionReason === DisallowedAPIVersionReason.ACTION_TOO_NEW ) { logger.warning( `GitHub Enterprise ${installedVersion} is too old to be compatible with this version of the CodeQL ${toolName}. If you experience issues, please upgrade to a more recent version of GitHub Enterprise or use an older version of the CodeQL ${toolName}.` ); } hasBeenWarnedAboutVersion = true; if (mode === "actions") { exportVariable(CODEQL_ACTION_WARNED_ABOUT_VERSION_ENV_VAR, true); } }); }); return new customOctokit( githubUtils.getOctokitOptions(githubAuth, { baseUrl: getApiUrl(githubUrl), userAgent: "CodeQL Action", log: consoleLogLevel({ level: "debug" }), }) ); }; function getApiUrl(githubUrl: string): string { const url = new URL(githubUrl); // If we detect this is trying to be to github.com // then return with a fixed canonical URL. if (url.hostname === "github.com" || url.hostname === "api.github.com") { return "https://api.github.com"; } // Add the /api/v3 API prefix url.pathname = path.join(url.pathname, "api", "v3"); return url.toString(); } // Temporary function to aid in the transition to running on and off of github actions. // Once all code has been coverted this function should be removed or made canonical // and called only from the action entrypoints. export function getActionsApiClient(allowLocalRun = false) { return getApiClient( getRequiredInput("token"), getRequiredEnvParam("GITHUB_SERVER_URL"), "actions", getActionsLogger(), allowLocalRun ); } export function apiVersionInRange( version: string, minimumVersion: string, maximumVersion: string ): DisallowedAPIVersionReason | undefined { if (!semver.satisfies(version, `>=${minimumVersion}`)) { return DisallowedAPIVersionReason.ACTION_TOO_NEW; } if (!semver.satisfies(version, `<=${maximumVersion}`)) { return DisallowedAPIVersionReason.ACTION_TOO_OLD; } return undefined; }