diff --git a/lib/entry-points.js b/lib/entry-points.js index 845944a72..bba87bbc4 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -170626,6 +170626,7 @@ var import_undici = __toESM(require_undici()); // src/github.ts var GITHUB_DOTCOM_URL = "https://github.com"; +var GITHUB_DOTCOM_API_URL = "https://api.github.com"; function parseGitHubUrl(inputUrl) { const originalUrl = inputUrl; if (inputUrl.indexOf("://") === -1) { @@ -170660,6 +170661,12 @@ function getCurrentInstance(env) { apiURL: env.getRequired("GITHUB_API_URL" /* GITHUB_API_URL */) }; } +function getDotcomInstance() { + return { + url: GITHUB_DOTCOM_URL, + apiURL: GITHUB_DOTCOM_API_URL + }; +} // src/repository.ts function isRepositoryNwoStr(val) { @@ -170752,8 +170759,18 @@ function getApiDetails(env = getEnv()) { ...getCurrentInstance(env) }; } -function getApiClient(env = getEnv()) { - return createApiClientWithDetails(getApiDetails(env)); +function getDotcomApiDetails(env) { + if (env.getRequired("GITHUB_SERVER_URL" /* GITHUB_SERVER_URL */) === GITHUB_DOTCOM_URL) { + return getApiDetails(env); + } else { + return { + auth: void 0, + ...getDotcomInstance() + }; + } +} +function getApiClient(env = getEnv(), apiDetails) { + return createApiClientWithDetails(apiDetails ?? getApiDetails(env)); } function getApiClientWithExternalAuth(apiDetails, proxy) { return createApiClientWithDetails(apiDetails, { allowExternal: true, proxy }); @@ -175760,35 +175777,35 @@ function getCodeQLActionRepository(action) { `The value of '${"GITHUB_ACTION_REPOSITORY" /* GITHUB_ACTION_REPOSITORY */}' is '${actionRepository}', which does not match the expected 'owner/repo' format.` ); } -var DEFAULT_DOWNLOAD_SOURCE = [ - GITHUB_DOTCOM_URL, - CODEQL_DEFAULT_ACTION_REPOSITORY -]; -var isSameDownloadSource = ([srcUrl, srcRepo], [otherUrl, otherRepo]) => { - return srcUrl === otherUrl && srcRepo === otherRepo; +var isSameDownloadSource = ([srcInstance, srcRepo], [otherInstance, otherRepo]) => { + return srcInstance.url === otherInstance.url && srcRepo === otherRepo; }; async function getCodeQLAssetDownloadURL(action, apiDetails, tagName, assetName, assetKind = "CodeQL bundle") { const codeQLActionRepository = getCodeQLActionRepository(action); + const defaultDownloadSource = [ + getDotcomApiDetails(action.env), + CODEQL_DEFAULT_ACTION_REPOSITORY + ]; const potentialDownloadSources = [ // This GitHub instance, and this Action. - [apiDetails.url, codeQLActionRepository], + [apiDetails, codeQLActionRepository], // This GitHub instance, and the canonical Action. - [apiDetails.url, CODEQL_DEFAULT_ACTION_REPOSITORY], + [apiDetails, CODEQL_DEFAULT_ACTION_REPOSITORY], // GitHub.com, and the canonical Action. - DEFAULT_DOWNLOAD_SOURCE + defaultDownloadSource ]; const uniqueDownloadSources = potentialDownloadSources.filter( (source, index2, self2) => { return !self2.slice(0, index2).some((other) => isSameDownloadSource(source, other)); } ); - for (const [apiURL, repository] of uniqueDownloadSources) { - if (isSameDownloadSource(DEFAULT_DOWNLOAD_SOURCE, [apiURL, repository])) { + for (const [instance8, repository] of uniqueDownloadSources) { + if (isSameDownloadSource(defaultDownloadSource, [instance8, repository])) { break; } const [repositoryOwner, repositoryName] = repository.split("/"); try { - const release2 = await getApiClient().rest.repos.getReleaseByTag({ + const release2 = await getApiClient(action.env, instance8).rest.repos.getReleaseByTag({ owner: repositoryOwner, repo: repositoryName, tag: tagName @@ -175796,14 +175813,14 @@ async function getCodeQLAssetDownloadURL(action, apiDetails, tagName, assetName, for (const asset of release2.data.assets) { if (asset.name === assetName) { action.logger.info( - `Found ${assetKind} ${assetName} in ${repository} on ${apiURL} with URL ${asset.url}.` + `Found ${assetKind} ${assetName} in ${repository} on ${instance8.apiURL} with URL ${asset.url}.` ); return asset.url; } } } catch (e) { action.logger.info( - `Looked for ${assetKind} ${assetName} in ${repository} on ${apiURL} but got error ${e}.` + `Looked for ${assetKind} ${assetName} in ${repository} on ${instance8.apiURL} but got error ${e}.` ); } } diff --git a/src/api-client.ts b/src/api-client.ts index 6eac4bc93..bd9ac339c 100644 --- a/src/api-client.ts +++ b/src/api-client.ts @@ -193,8 +193,11 @@ export function getDotcomApiDetails(env: ReadOnlyEnv): GitHubApiDetails { } } -export function getApiClient(env: ReadOnlyEnv = getEnv()) { - return createApiClientWithDetails(getApiDetails(env)); +export function getApiClient( + env: ReadOnlyEnv = getEnv(), + apiDetails?: GitHubApiDetails, +) { + return createApiClientWithDetails(apiDetails ?? getApiDetails(env)); } export function getApiClientWithExternalAuth( diff --git a/src/codeql.test.ts b/src/codeql.test.ts index e70dcd99f..ff0a4d5b6 100644 --- a/src/codeql.test.ts +++ b/src/codeql.test.ts @@ -34,6 +34,7 @@ import { makeVersionInfo, createTestConfig, makeMacro, + mockApiDetails, } from "./testing-utils"; import { ToolsDownloadStatusReport } from "./tools-download"; import * as util from "./util"; @@ -126,19 +127,6 @@ function mockReleaseApi({ }); } -function mockApiDetails(apiDetails: Required) { - // This is a workaround to mock `api.getApiDetails()` since it doesn't seem to be possible to - // mock this directly. The difficulty is that `getApiDetails()` is called locally in - // `api-client.ts`, but `sinon.stub(api, "getApiDetails")` only affects calls to - // `getApiDetails()` via an imported `api` module. - sinon - .stub(actionsUtil, "getRequiredInput") - .withArgs("token") - .returns(apiDetails.auth); - process.env["GITHUB_SERVER_URL"] = apiDetails.url; - process.env["GITHUB_API_URL"] = apiDetails.apiURL || ""; -} - async function stubCodeql(): Promise { const codeqlObject = await codeql.getCodeQLForTesting(); sinon.stub(codeqlObject, "getVersion").resolves(makeVersionInfo("2.17.6")); @@ -290,6 +278,7 @@ for (const { cliVersion, tagName, expectedToolcacheVersion } of [ async (t) => { await util.withTmpDir(async (tmpDir) => { setupActionsVars(tmpDir, tmpDir); + mockApiDetails(SAMPLE_DOTCOM_API_DETAILS); const result = await installIntoToolcache({ cliVersion, @@ -470,6 +459,7 @@ test.serial( await util.withTmpDir(async (tmpDir) => { setupActionsVars(tmpDir, tmpDir); + mockApiDetails(SAMPLE_DOTCOM_API_DETAILS); await installIntoToolcache({ tagName: "codeql-bundle-20200601", @@ -517,6 +507,7 @@ test.serial( await util.withTmpDir(async (tmpDir) => { setupActionsVars(tmpDir, tmpDir); + mockApiDetails(SAMPLE_DOTCOM_API_DETAILS); await installIntoToolcache({ tagName: "codeql-bundle-20200601", diff --git a/src/setup-codeql.test.ts b/src/setup-codeql.test.ts index 6bdb29f46..9ad2c6773 100644 --- a/src/setup-codeql.test.ts +++ b/src/setup-codeql.test.ts @@ -32,6 +32,7 @@ import { getTestEnv, initAllState, makeMacro, + mockApiDetails, mockBundleDownloadApi, setupActionsVars, setupTests, @@ -221,6 +222,7 @@ for (const { await withTmpDir(async (tmpDir) => { setupActionsVars(tmpDir, tmpDir); + mockApiDetails(SAMPLE_DOTCOM_API_DETAILS); const source = await setupCodeql.getCodeQLSource( "linked", SAMPLE_DEFAULT_CLI_VERSION, @@ -255,6 +257,7 @@ test.serial( await withTmpDir(async (tmpDir) => { setupActionsVars(tmpDir, tmpDir); + mockApiDetails(SAMPLE_DOTCOM_API_DETAILS); const source = await setupCodeql.getCodeQLSource( "latest", SAMPLE_DEFAULT_CLI_VERSION, @@ -298,6 +301,7 @@ test.serial( await withTmpDir(async (tmpDir) => { setupActionsVars(tmpDir, tmpDir); + mockApiDetails(SAMPLE_DOTCOM_API_DETAILS); const result = await setupCodeql.setupCodeQLBundle( "linked", SAMPLE_DOTCOM_API_DETAILS, @@ -479,6 +483,7 @@ test.serial( await withTmpDir(async (tmpDir) => { setupActionsVars(tmpDir, tmpDir, { GITHUB_EVENT_NAME: "dynamic" }); + mockApiDetails(SAMPLE_DOTCOM_API_DETAILS); const source = await setupCodeql.getCodeQLSource( undefined, @@ -624,6 +629,7 @@ for (const toolsInput of ["nightly", "nightly-latest"]) { await withTmpDir(async (tmpDir) => { setupActionsVars(tmpDir, tmpDir); + mockApiDetails(SAMPLE_DOTCOM_API_DETAILS); const source = await setupCodeql.getCodeQLSource( toolsInput, SAMPLE_DEFAULT_CLI_VERSION, @@ -945,6 +951,7 @@ const toolcacheInputFallbackMacro = makeMacro({ await withTmpDir(async (tmpDir) => { setupActionsVars(tmpDir, tmpDir); + mockApiDetails(SAMPLE_DOTCOM_API_DETAILS); for (const [k, v] of Object.entries(environment)) { process.env[k] = v; @@ -1165,6 +1172,7 @@ test.serial( await withTmpDir(async (tmpDir) => { setupActionsVars(tmpDir, tmpDir); + mockApiDetails(SAMPLE_DOTCOM_API_DETAILS); const source = await setupCodeql.getCodeQLSource( undefined, PER_LANGUAGE_CLI_VERSION, @@ -1207,6 +1215,7 @@ test.serial( await withTmpDir(async (tmpDir) => { setupActionsVars(tmpDir, tmpDir); + mockApiDetails(SAMPLE_DOTCOM_API_DETAILS); for (const { otherLanguagePacksReason, features } of [ // The per-language feature is disabled. { otherLanguagePacksReason: undefined, features: createFeatures([]) }, @@ -1286,6 +1295,7 @@ for (const fallback of [false, true]) { setupActionsVars(tmpDir, tmpDir, { GITHUB_ACTION_REPOSITORY: "codeql-testing/action-fork", }); + mockApiDetails(SAMPLE_DOTCOM_API_DETAILS); const result = await setupCodeql.setupCodeQLBundle( undefined, SAMPLE_DOTCOM_API_DETAILS, @@ -1553,6 +1563,7 @@ for (const error of [ await withTmpDir(async (tmpDir) => { setupActionsVars(tmpDir, tmpDir); + mockApiDetails(SAMPLE_DOTCOM_API_DETAILS); await t.throwsAsync( setupCodeql.setupCodeQLBundle( undefined, @@ -2259,6 +2270,7 @@ test.serial( async (t) => { await withTmpDir(async (tmpDir) => { setupActionsVars(tmpDir, tmpDir); + mockApiDetails(SAMPLE_DOTCOM_API_DETAILS); delete process.env[EnvVar.HAS_SET_UP_CODEQL]; stubDownloadAndExtract(); @@ -2294,6 +2306,7 @@ test.serial( await withTmpDir(async (tmpDir) => { setupActionsVars(tmpDir, tmpDir); + mockApiDetails(SAMPLE_DOTCOM_API_DETAILS); process.env[ActionsEnvVars.RUNNER_ENVIRONMENT] = "github-hosted"; delete process.env[EnvVar.HAS_SET_UP_CODEQL]; const staleDirectory = createToolcacheEntry( diff --git a/src/setup/repository.ts b/src/setup/repository.ts index 8db559a86..d845f0953 100644 --- a/src/setup/repository.ts +++ b/src/setup/repository.ts @@ -2,7 +2,6 @@ import { ActionState } from "../action-common"; import { isRunningLocalAction } from "../actions-util"; import * as api from "../api-client"; import { ActionsEnvVars } from "../environment"; -import { GITHUB_DOTCOM_URL } from "../github"; import { isRepositoryNwoStr, type RepositoryNwoStr } from "../repository"; /** The NWO of the standard CodeQL Action repository. */ @@ -43,20 +42,14 @@ export function getCodeQLActionRepository( } /**A download source is a pair of strings. */ -export type DownloadSource = [string, RepositoryNwoStr]; - -/** GitHub.com, and the canonical Action. */ -export const DEFAULT_DOWNLOAD_SOURCE: DownloadSource = [ - GITHUB_DOTCOM_URL, - CODEQL_DEFAULT_ACTION_REPOSITORY, -]; +export type DownloadSource = [api.GitHubApiDetails, RepositoryNwoStr]; /** Decides if the two provided download sources are the same. */ const isSameDownloadSource = ( - [srcUrl, srcRepo]: DownloadSource, - [otherUrl, otherRepo]: DownloadSource, + [srcInstance, srcRepo]: DownloadSource, + [otherInstance, otherRepo]: DownloadSource, ) => { - return srcUrl === otherUrl && srcRepo === otherRepo; + return srcInstance.url === otherInstance.url && srcRepo === otherRepo; }; /** A download URL is represented as a string. */ @@ -88,13 +81,21 @@ export async function getCodeQLAssetDownloadURL( ): Promise { const codeQLActionRepository = getCodeQLActionRepository(action); + // We construct the default GitHub.com source here, because `getDotcomApiDetails` + // may retrieve the `token` input if we are currently running on GitHub.com and + // we want to avoid doing that statically. + const defaultDownloadSource: DownloadSource = [ + api.getDotcomApiDetails(action.env), + CODEQL_DEFAULT_ACTION_REPOSITORY, + ]; + const potentialDownloadSources: DownloadSource[] = [ // This GitHub instance, and this Action. - [apiDetails.url, codeQLActionRepository], + [apiDetails, codeQLActionRepository], // This GitHub instance, and the canonical Action. - [apiDetails.url, CODEQL_DEFAULT_ACTION_REPOSITORY], + [apiDetails, CODEQL_DEFAULT_ACTION_REPOSITORY], // GitHub.com, and the canonical Action. - DEFAULT_DOWNLOAD_SOURCE, + defaultDownloadSource, ]; // We now filter out any duplicates. @@ -107,31 +108,33 @@ export async function getCodeQLAssetDownloadURL( }, ); - for (const [apiURL, repository] of uniqueDownloadSources) { + for (const [instance, repository] of uniqueDownloadSources) { // If we've reached the final case, short-circuit the API check since we know the asset exists and is public. - if (isSameDownloadSource(DEFAULT_DOWNLOAD_SOURCE, [apiURL, repository])) { + if (isSameDownloadSource(defaultDownloadSource, [instance, repository])) { break; } const [repositoryOwner, repositoryName] = repository.split("/"); try { - const release = await api.getApiClient().rest.repos.getReleaseByTag({ - owner: repositoryOwner, - repo: repositoryName, - tag: tagName, - }); + const release = await api + .getApiClient(action.env, instance) + .rest.repos.getReleaseByTag({ + owner: repositoryOwner, + repo: repositoryName, + tag: tagName, + }); for (const asset of release.data.assets) { if (asset.name === assetName) { action.logger.info( - `Found ${assetKind} ${assetName} in ${repository} on ${apiURL} with URL ${asset.url}.`, + `Found ${assetKind} ${assetName} in ${repository} on ${instance.apiURL} with URL ${asset.url}.`, ); return asset.url; } } } catch (e) { action.logger.info( - `Looked for ${assetKind} ${assetName} in ${repository} on ${apiURL} but got error ${e}.`, + `Looked for ${assetKind} ${assetName} in ${repository} on ${instance.apiURL} but got error ${e}.`, ); } } diff --git a/src/testing-utils.ts b/src/testing-utils.ts index cd6031894..7ae83e906 100644 --- a/src/testing-utils.ts +++ b/src/testing-utils.ts @@ -14,6 +14,7 @@ import * as sinon from "sinon"; import { ActionState, StateFeature } from "./action-common"; import { ActionsEnv, getActionVersion } from "./actions-util"; +import * as actionsUtil from "./actions-util"; import { AnalysisKind } from "./analyses"; import * as apiClient from "./api-client"; import { GitHubApiDetails } from "./api-client"; @@ -52,6 +53,19 @@ export const SAMPLE_DOTCOM_API_DETAILS = { apiURL: "https://api.github.com", }; +export function mockApiDetails(apiDetails: Required) { + // This is a workaround to mock `api.getApiDetails()` since it doesn't seem to be possible to + // mock this directly. The difficulty is that `getApiDetails()` is called locally in + // `api-client.ts`, but `sinon.stub(api, "getApiDetails")` only affects calls to + // `getApiDetails()` via an imported `api` module. + sinon + .stub(actionsUtil, "getRequiredInput") + .withArgs("token") + .returns(apiDetails.auth); + process.env["GITHUB_SERVER_URL"] = apiDetails.url; + process.env["GITHUB_API_URL"] = apiDetails.apiURL || ""; +} + export const LINKED_CLI_VERSION = { cliVersion: defaults.cliVersion, tagName: defaults.bundleVersion,