mirror of
https://github.com/github/codeql-action.git
synced 2026-10-21 02:01:27 +00:00
Merge pull request #4198 from github/mbg/start-proxy/deprecate-fallback
Use `setup-codeql` logic for finding release assets in `start-proxy`
This commit is contained in:
326
lib/entry-points.js
generated
326
lib/entry-points.js
generated
@@ -42967,11 +42967,11 @@ var require_tracingPolicy = __commonJS({
|
||||
var import_log = require_log3();
|
||||
var import_core_util = require_commonjs4();
|
||||
var import_restError = require_restError3();
|
||||
var import_util58 = require_internal3();
|
||||
var import_util59 = require_internal3();
|
||||
var tracingPolicyName2 = "tracingPolicy";
|
||||
function tracingPolicy2(options = {}) {
|
||||
const userAgentPromise = (0, import_userAgent.getUserAgentValue)(options.userAgentPrefix);
|
||||
const sanitizer = new import_util58.Sanitizer({
|
||||
const sanitizer = new import_util59.Sanitizer({
|
||||
additionalAllowedQueryParameters: options.additionalAllowedQueryParameters
|
||||
});
|
||||
const tracingClient = tryCreateTracingClient();
|
||||
@@ -46597,11 +46597,11 @@ var require_response2 = __commonJS({
|
||||
});
|
||||
module2.exports = __toCommonJS2(response_exports);
|
||||
var import_core_rest_pipeline = require_commonjs6();
|
||||
var import_util58 = require_util9();
|
||||
var import_util59 = require_util9();
|
||||
var originalResponse = /* @__PURE__ */ Symbol("Original FullOperationResponse");
|
||||
function toCompatResponse2(response, options) {
|
||||
let request3 = (0, import_util58.toWebResourceLike)(response.request);
|
||||
let headers = (0, import_util58.toHttpHeadersLike)(response.headers);
|
||||
let request3 = (0, import_util59.toWebResourceLike)(response.request);
|
||||
let headers = (0, import_util59.toHttpHeadersLike)(response.headers);
|
||||
if (options?.createProxy) {
|
||||
return new Proxy(response, {
|
||||
get(target, prop, receiver) {
|
||||
@@ -46642,7 +46642,7 @@ var require_response2 = __commonJS({
|
||||
return {
|
||||
...compatResponse,
|
||||
headers,
|
||||
request: (0, import_util58.toPipelineRequest)(compatResponse.request)
|
||||
request: (0, import_util59.toPipelineRequest)(compatResponse.request)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -46749,7 +46749,7 @@ var require_requestPolicyFactoryPolicy = __commonJS({
|
||||
requestPolicyFactoryPolicyName: () => requestPolicyFactoryPolicyName2
|
||||
});
|
||||
module2.exports = __toCommonJS2(requestPolicyFactoryPolicy_exports);
|
||||
var import_util58 = require_util9();
|
||||
var import_util59 = require_util9();
|
||||
var import_response = require_response2();
|
||||
var HttpPipelineLogLevel2 = /* @__PURE__ */ ((HttpPipelineLogLevel22) => {
|
||||
HttpPipelineLogLevel22[HttpPipelineLogLevel22["ERROR"] = 1] = "ERROR";
|
||||
@@ -46773,14 +46773,14 @@ var require_requestPolicyFactoryPolicy = __commonJS({
|
||||
async sendRequest(request3, next) {
|
||||
let httpPipeline = {
|
||||
async sendRequest(httpRequest) {
|
||||
const response2 = await next((0, import_util58.toPipelineRequest)(httpRequest));
|
||||
const response2 = await next((0, import_util59.toPipelineRequest)(httpRequest));
|
||||
return (0, import_response.toCompatResponse)(response2, { createProxy: true });
|
||||
}
|
||||
};
|
||||
for (const factory of orderedFactories) {
|
||||
httpPipeline = factory.create(httpPipeline, mockRequestPolicyOptions);
|
||||
}
|
||||
const webResourceLike = (0, import_util58.toWebResourceLike)(request3, { createProxy: true });
|
||||
const webResourceLike = (0, import_util59.toWebResourceLike)(request3, { createProxy: true });
|
||||
const response = await httpPipeline.sendRequest(webResourceLike);
|
||||
return (0, import_response.toPipelineResponse)(response);
|
||||
}
|
||||
@@ -46815,12 +46815,12 @@ var require_httpClientAdapter = __commonJS({
|
||||
});
|
||||
module2.exports = __toCommonJS2(httpClientAdapter_exports);
|
||||
var import_response = require_response2();
|
||||
var import_util58 = require_util9();
|
||||
var import_util59 = require_util9();
|
||||
function convertHttpClient2(requestPolicyClient) {
|
||||
return {
|
||||
sendRequest: async (request3) => {
|
||||
const response = await requestPolicyClient.sendRequest(
|
||||
(0, import_util58.toWebResourceLike)(request3, { createProxy: true })
|
||||
(0, import_util59.toWebResourceLike)(request3, { createProxy: true })
|
||||
);
|
||||
return (0, import_response.toPipelineResponse)(response);
|
||||
}
|
||||
@@ -46858,7 +46858,7 @@ var require_commonjs9 = __commonJS({
|
||||
disableKeepAlivePolicyName: () => import_disableKeepAlivePolicy.disableKeepAlivePolicyName,
|
||||
requestPolicyFactoryPolicyName: () => import_requestPolicyFactoryPolicy.requestPolicyFactoryPolicyName,
|
||||
toCompatResponse: () => import_response.toCompatResponse,
|
||||
toHttpHeadersLike: () => import_util58.toHttpHeadersLike
|
||||
toHttpHeadersLike: () => import_util59.toHttpHeadersLike
|
||||
});
|
||||
module2.exports = __toCommonJS2(src_exports);
|
||||
var import_extendedClient = require_extendedClient();
|
||||
@@ -46866,7 +46866,7 @@ var require_commonjs9 = __commonJS({
|
||||
var import_requestPolicyFactoryPolicy = require_requestPolicyFactoryPolicy();
|
||||
var import_disableKeepAlivePolicy = require_disableKeepAlivePolicy();
|
||||
var import_httpClientAdapter = require_httpClientAdapter();
|
||||
var import_util58 = require_util9();
|
||||
var import_util59 = require_util9();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -107111,41 +107111,6 @@ var require_tool_cache = __commonJS({
|
||||
}
|
||||
});
|
||||
|
||||
// node_modules/fast-deep-equal/index.js
|
||||
var require_fast_deep_equal = __commonJS({
|
||||
"node_modules/fast-deep-equal/index.js"(exports2, module2) {
|
||||
"use strict";
|
||||
module2.exports = function equal(a, b) {
|
||||
if (a === b) return true;
|
||||
if (a && b && typeof a == "object" && typeof b == "object") {
|
||||
if (a.constructor !== b.constructor) return false;
|
||||
var length, i, keys;
|
||||
if (Array.isArray(a)) {
|
||||
length = a.length;
|
||||
if (length != b.length) return false;
|
||||
for (i = length; i-- !== 0; )
|
||||
if (!equal(a[i], b[i])) return false;
|
||||
return true;
|
||||
}
|
||||
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
|
||||
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
|
||||
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
|
||||
keys = Object.keys(a);
|
||||
length = keys.length;
|
||||
if (length !== Object.keys(b).length) return false;
|
||||
for (i = length; i-- !== 0; )
|
||||
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
|
||||
for (i = length; i-- !== 0; ) {
|
||||
var key = keys[i];
|
||||
if (!equal(a[key], b[key])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return a !== a && b !== b;
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// node_modules/follow-redirects/debug.js
|
||||
var require_debug3 = __commonJS({
|
||||
"node_modules/follow-redirects/debug.js"(exports2, module2) {
|
||||
@@ -169874,12 +169839,12 @@ var ExhaustivityCheckingError = class extends Error {
|
||||
function assertNever(value) {
|
||||
throw new ExhaustivityCheckingError(value);
|
||||
}
|
||||
function initializeEnvironment(version) {
|
||||
exportEnvVar("CODEQL_ACTION_FEATURE_MULTI_LANGUAGE" /* FEATURE_MULTI_LANGUAGE */, "false");
|
||||
exportEnvVar("CODEQL_ACTION_FEATURE_SANDWICH" /* FEATURE_SANDWICH */, "false");
|
||||
exportEnvVar("CODEQL_ACTION_FEATURE_SARIF_COMBINE" /* FEATURE_SARIF_COMBINE */, "true");
|
||||
exportEnvVar("CODEQL_ACTION_FEATURE_WILL_UPLOAD" /* FEATURE_WILL_UPLOAD */, "true");
|
||||
exportEnvVar("CODEQL_ACTION_VERSION" /* VERSION */, version);
|
||||
function initializeEnvironment(version, env = getEnv()) {
|
||||
env.export("CODEQL_ACTION_FEATURE_MULTI_LANGUAGE" /* FEATURE_MULTI_LANGUAGE */, "false");
|
||||
env.export("CODEQL_ACTION_FEATURE_SANDWICH" /* FEATURE_SANDWICH */, "false");
|
||||
env.export("CODEQL_ACTION_FEATURE_SARIF_COMBINE" /* FEATURE_SARIF_COMBINE */, "true");
|
||||
env.export("CODEQL_ACTION_FEATURE_WILL_UPLOAD" /* FEATURE_WILL_UPLOAD */, "true");
|
||||
env.export("CODEQL_ACTION_VERSION" /* VERSION */, version);
|
||||
}
|
||||
var HTTPError = class extends Error {
|
||||
status;
|
||||
@@ -170689,6 +170654,9 @@ retry.VERSION = VERSION7;
|
||||
var import_undici = __toESM(require_undici());
|
||||
|
||||
// src/repository.ts
|
||||
function isRepositoryNwoStr(val) {
|
||||
return val.includes("/");
|
||||
}
|
||||
function getRepositoryNwo() {
|
||||
return getRepositoryNwoFromEnv("GITHUB_REPOSITORY");
|
||||
}
|
||||
@@ -175307,7 +175275,6 @@ var fs14 = __toESM(require("fs"));
|
||||
var path13 = __toESM(require("path"));
|
||||
var import_perf_hooks4 = require("perf_hooks");
|
||||
var toolcache3 = __toESM(require_tool_cache());
|
||||
var import_fast_deep_equal = __toESM(require_fast_deep_equal());
|
||||
var semver9 = __toESM(require_semver2());
|
||||
|
||||
// src/codeql-bundle.ts
|
||||
@@ -175763,6 +175730,78 @@ function logPerLanguageBundleFallback({ logger: logger2 }, language, location) {
|
||||
);
|
||||
}
|
||||
|
||||
// src/setup/repository.ts
|
||||
var CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action";
|
||||
function getCodeQLActionRepository(action) {
|
||||
if (isRunningLocalAction(action.env)) {
|
||||
action.logger.info(
|
||||
"The CodeQL Action is checked out locally. Using the default CodeQL Action repository."
|
||||
);
|
||||
return CODEQL_DEFAULT_ACTION_REPOSITORY;
|
||||
}
|
||||
const actionRepository = action.env.getRequired(
|
||||
"GITHUB_ACTION_REPOSITORY" /* GITHUB_ACTION_REPOSITORY */
|
||||
);
|
||||
if (isRepositoryNwoStr(actionRepository)) {
|
||||
return actionRepository;
|
||||
}
|
||||
throw new Error(
|
||||
`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;
|
||||
};
|
||||
function getDefaultDotcomDownloadURL(tagName, assetName) {
|
||||
return `${GITHUB_DOTCOM_URL}/${CODEQL_DEFAULT_ACTION_REPOSITORY}/releases/download/${tagName}/${assetName}`;
|
||||
}
|
||||
async function getCodeQLAssetDownloadURL(action, apiDetails, tagName, assetName, assetKind = "CodeQL bundle") {
|
||||
const codeQLActionRepository = getCodeQLActionRepository(action);
|
||||
const potentialDownloadSources = [
|
||||
// This GitHub instance, and this Action.
|
||||
[apiDetails.url, codeQLActionRepository],
|
||||
// This GitHub instance, and the canonical Action.
|
||||
[apiDetails.url, CODEQL_DEFAULT_ACTION_REPOSITORY],
|
||||
// GitHub.com, and the canonical Action.
|
||||
DEFAULT_DOWNLOAD_SOURCE
|
||||
];
|
||||
const uniqueDownloadSources = potentialDownloadSources.filter(
|
||||
(source, index2, self2) => {
|
||||
return !self2.slice(0, index2).some((other) => isSameDownloadSource(source, other));
|
||||
}
|
||||
);
|
||||
for (const [instanceURL, repository] of uniqueDownloadSources) {
|
||||
if (isSameDownloadSource(DEFAULT_DOWNLOAD_SOURCE, [instanceURL, repository])) {
|
||||
break;
|
||||
}
|
||||
const { owner: repositoryOwner, repo: repositoryName } = parseRepositoryNwo(repository);
|
||||
try {
|
||||
const release2 = await getApiClient().rest.repos.getReleaseByTag({
|
||||
owner: repositoryOwner,
|
||||
repo: repositoryName,
|
||||
tag: tagName
|
||||
});
|
||||
for (const asset of release2.data.assets) {
|
||||
if (asset.name === assetName) {
|
||||
action.logger.info(
|
||||
`Found ${assetKind} ${assetName} in ${repository} on ${instanceURL} with URL ${asset.url}.`
|
||||
);
|
||||
return asset.url;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
action.logger.info(
|
||||
`Looked for ${assetKind} ${assetName} in ${repository} on ${instanceURL} but got error ${e}.`
|
||||
);
|
||||
}
|
||||
}
|
||||
return getDefaultDotcomDownloadURL(tagName, assetName);
|
||||
}
|
||||
|
||||
// src/tar.ts
|
||||
var import_child_process = require("child_process");
|
||||
var fs12 = __toESM(require("fs"));
|
||||
@@ -176154,64 +176193,11 @@ function writeToolcacheMarkerFile(extractedPath, logger2) {
|
||||
}
|
||||
|
||||
// src/setup-codeql.ts
|
||||
var CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action";
|
||||
var CODEQL_NIGHTLIES_REPOSITORY_OWNER = "dsp-testing";
|
||||
var CODEQL_NIGHTLIES_REPOSITORY_NAME = "codeql-cli-nightlies";
|
||||
var CODEQL_BUNDLE_VERSION_ALIAS = ["linked", "latest"];
|
||||
var CODEQL_NIGHTLY_TOOLS_INPUTS = ["nightly", "nightly-latest"];
|
||||
var CODEQL_TOOLCACHE_INPUT = "toolcache";
|
||||
function getCodeQLActionRepository(logger2) {
|
||||
if (isRunningLocalAction()) {
|
||||
logger2.info(
|
||||
"The CodeQL Action is checked out locally. Using the default CodeQL Action repository."
|
||||
);
|
||||
return CODEQL_DEFAULT_ACTION_REPOSITORY;
|
||||
}
|
||||
return getRequiredEnvParam("GITHUB_ACTION_REPOSITORY");
|
||||
}
|
||||
async function getCodeQLBundleDownloadURL(tagName, apiDetails, codeQLBundleName, logger2) {
|
||||
const codeQLActionRepository = getCodeQLActionRepository(logger2);
|
||||
const potentialDownloadSources = [
|
||||
// This GitHub instance, and this Action.
|
||||
[apiDetails.url, codeQLActionRepository],
|
||||
// This GitHub instance, and the canonical Action.
|
||||
[apiDetails.url, CODEQL_DEFAULT_ACTION_REPOSITORY],
|
||||
// GitHub.com, and the canonical Action.
|
||||
[GITHUB_DOTCOM_URL, CODEQL_DEFAULT_ACTION_REPOSITORY]
|
||||
];
|
||||
const uniqueDownloadSources = potentialDownloadSources.filter(
|
||||
(source, index2, self2) => {
|
||||
return !self2.slice(0, index2).some((other) => (0, import_fast_deep_equal.default)(source, other));
|
||||
}
|
||||
);
|
||||
for (const downloadSource of uniqueDownloadSources) {
|
||||
const [apiURL, repository] = downloadSource;
|
||||
if (apiURL === GITHUB_DOTCOM_URL && repository === CODEQL_DEFAULT_ACTION_REPOSITORY) {
|
||||
break;
|
||||
}
|
||||
const [repositoryOwner, repositoryName] = repository.split("/");
|
||||
try {
|
||||
const release2 = await getApiClient().rest.repos.getReleaseByTag({
|
||||
owner: repositoryOwner,
|
||||
repo: repositoryName,
|
||||
tag: tagName
|
||||
});
|
||||
for (const asset of release2.data.assets) {
|
||||
if (asset.name === codeQLBundleName) {
|
||||
logger2.info(
|
||||
`Found CodeQL bundle ${codeQLBundleName} in ${repository} on ${apiURL} with URL ${asset.url}.`
|
||||
);
|
||||
return asset.url;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
logger2.info(
|
||||
`Looked for CodeQL bundle ${codeQLBundleName} in ${repository} on ${apiURL} but got error ${e}.`
|
||||
);
|
||||
}
|
||||
}
|
||||
return `https://github.com/${CODEQL_DEFAULT_ACTION_REPOSITORY}/releases/download/${tagName}/${codeQLBundleName}`;
|
||||
}
|
||||
function tryGetBundleVersionFromTagName(tagName, logger2) {
|
||||
const match2 = tagName.match(/^codeql-bundle-(.+)$/);
|
||||
if (match2 === null || match2.length < 2) {
|
||||
@@ -176569,9 +176555,10 @@ async function getCodeQLSource(toolsInput, defaultCliVersion, rawLanguages, othe
|
||||
);
|
||||
}
|
||||
compressionMethod = cliVersion2 !== void 0 && await useZstdBundle(cliVersion2, tarSupportsZstd) ? "zstd" : "gzip";
|
||||
const action = { env: getEnv(), logger: logger2 };
|
||||
const platform2 = getBundlePlatform();
|
||||
const perLanguageBundleLanguage = await getPerLanguageBundleLanguage(
|
||||
{ env: getEnv(), features, logger: logger2 },
|
||||
{ ...action, features },
|
||||
{
|
||||
rawLanguages,
|
||||
otherLanguagePacksReason,
|
||||
@@ -176581,11 +176568,11 @@ async function getCodeQLSource(toolsInput, defaultCliVersion, rawLanguages, othe
|
||||
variant
|
||||
}
|
||||
);
|
||||
const resolveBundleURL = (language) => getCodeQLBundleDownloadURL(
|
||||
bundleTagName,
|
||||
const resolveBundleURL = (language) => getCodeQLAssetDownloadURL(
|
||||
action,
|
||||
apiDetails,
|
||||
getCodeQLBundleName(compressionMethod, platform2, language),
|
||||
logger2
|
||||
bundleTagName,
|
||||
getCodeQLBundleName(compressionMethod, platform2, language)
|
||||
);
|
||||
const combinedBundleURL = await resolveBundleURL();
|
||||
if (perLanguageBundleLanguage !== void 0) {
|
||||
@@ -183046,7 +183033,7 @@ var import_async = __toESM(require_async(), 1);
|
||||
var import_path7 = require("path");
|
||||
|
||||
// node_modules/archiver/lib/error.js
|
||||
var import_util36 = __toESM(require("util"), 1);
|
||||
var import_util37 = __toESM(require("util"), 1);
|
||||
var ERROR_CODES = {
|
||||
ABORTED: "archive was aborted",
|
||||
DIRECTORYDIRPATHREQUIRED: "diretory dirpath argument must be a non-empty string value",
|
||||
@@ -183071,7 +183058,7 @@ function ArchiverError(code, data) {
|
||||
this.code = code;
|
||||
this.data = data;
|
||||
}
|
||||
import_util36.default.inherits(ArchiverError, Error);
|
||||
import_util37.default.inherits(ArchiverError, Error);
|
||||
|
||||
// node_modules/archiver/lib/core.js
|
||||
var import_readable_stream2 = __toESM(require_ours(), 1);
|
||||
@@ -187652,8 +187639,6 @@ async function sendFailedStatusReport(logger2, startedAt, language, unwrappedErr
|
||||
}
|
||||
}
|
||||
var UPDATEJOB_PROXY = "update-job-proxy";
|
||||
var UPDATEJOB_PROXY_VERSION = "v2.0.20250624110901";
|
||||
var UPDATEJOB_PROXY_URL_PREFIX = "https://github.com/github/codeql-action/releases/download/codeql-bundle-v2.22.0/";
|
||||
function isPAT(value) {
|
||||
return isAuthToken(value, [
|
||||
GITHUB_PAT_CLASSIC_PATTERN,
|
||||
@@ -187771,21 +187756,11 @@ function getCredentials(logger2, registrySecrets, registriesCredentials, languag
|
||||
function getProxyPackage(platform2) {
|
||||
return `${UPDATEJOB_PROXY}-${platform2}.tar.gz`;
|
||||
}
|
||||
function getFallbackUrl(proxyPackage) {
|
||||
return `${UPDATEJOB_PROXY_URL_PREFIX}${proxyPackage}`;
|
||||
}
|
||||
async function getReleaseByVersion(version) {
|
||||
return getApiClient().rest.repos.getReleaseByTag({
|
||||
owner: "github",
|
||||
repo: "codeql-action",
|
||||
tag: version
|
||||
});
|
||||
}
|
||||
async function getCliVersionFromFeatures(features) {
|
||||
const gitHubVersion = await getGitHubVersion();
|
||||
return await features.getEnabledDefaultCliVersions(gitHubVersion.type);
|
||||
}
|
||||
async function getDownloadUrl(action) {
|
||||
async function getDownloadUrl(action, apiDetails) {
|
||||
let platform2 = getBundlePlatform(action.platform, action.arch);
|
||||
if (platform2 === void 0) {
|
||||
action.logger.warning(
|
||||
@@ -187802,37 +187777,29 @@ async function getDownloadUrl(action) {
|
||||
cliVersion,
|
||||
tagName: bundleVersion
|
||||
};
|
||||
const cliRelease = await getReleaseByVersion(versionInfo.tagName);
|
||||
for (const asset of cliRelease.data.assets) {
|
||||
if (asset.name === proxyPackage) {
|
||||
action.logger.info(
|
||||
`Found '${proxyPackage}' in release '${versionInfo.tagName}' at '${asset.url}'`
|
||||
);
|
||||
return {
|
||||
url: asset.url,
|
||||
// The `update-job-proxy` doesn't have a version as such. Since we now bundle it
|
||||
// with CodeQL CLI bundle releases, we use the corresponding CLI version to
|
||||
// differentiate between (potentially) different versions of `update-job-proxy`.
|
||||
version: versionInfo.cliVersion
|
||||
};
|
||||
}
|
||||
}
|
||||
const proxyAssetUrl = await getCodeQLAssetDownloadURL(
|
||||
action,
|
||||
apiDetails,
|
||||
versionInfo.tagName,
|
||||
proxyPackage,
|
||||
"private registry proxy"
|
||||
);
|
||||
return {
|
||||
url: proxyAssetUrl,
|
||||
// The `update-job-proxy` doesn't have a version as such. Since we now bundle it
|
||||
// with CodeQL CLI bundle releases, we use the corresponding CLI version to
|
||||
// differentiate between (potentially) different versions of `update-job-proxy`.
|
||||
version: versionInfo.cliVersion
|
||||
};
|
||||
} catch (ex) {
|
||||
action.logger.warning(
|
||||
throw new Error(
|
||||
`Failed to retrieve information about the linked release: ${getErrorMessage(ex)}`
|
||||
);
|
||||
}
|
||||
action.logger.info(
|
||||
`Did not find '${proxyPackage}' in the linked release, falling back to hard-coded version.`
|
||||
);
|
||||
return {
|
||||
url: getFallbackUrl(proxyPackage),
|
||||
version: UPDATEJOB_PROXY_VERSION
|
||||
};
|
||||
}
|
||||
async function downloadProxy(logger2, url2, authorization) {
|
||||
try {
|
||||
return toolcache4.downloadTool(
|
||||
return await toolcache4.downloadTool(
|
||||
url2,
|
||||
/* dest: */
|
||||
void 0,
|
||||
@@ -187871,28 +187838,40 @@ async function cacheProxy(logger2, source, filename, version) {
|
||||
function getProxyFilename() {
|
||||
return process.platform === "win32" ? `${UPDATEJOB_PROXY}.exe` : UPDATEJOB_PROXY;
|
||||
}
|
||||
async function getProxyBinaryPath(action) {
|
||||
async function getProxyBinaryPath(action, apiDetails) {
|
||||
const logger2 = action.logger;
|
||||
const proxyFileName = getProxyFilename();
|
||||
const proxyInfo = await getDownloadUrl(action);
|
||||
let proxyBin = toolcache4.find(proxyFileName, proxyInfo.version);
|
||||
if (!proxyBin) {
|
||||
const apiDetails = getApiDetails();
|
||||
const authorization = getAuthorizationHeaderFor(
|
||||
logger2,
|
||||
apiDetails,
|
||||
proxyInfo.url
|
||||
);
|
||||
const temp = await downloadProxy(logger2, proxyInfo.url, authorization);
|
||||
const extracted = await extractProxy(logger2, temp);
|
||||
proxyBin = await cacheProxy(
|
||||
logger2,
|
||||
extracted,
|
||||
proxyFileName,
|
||||
proxyInfo.version
|
||||
logger2.startGroup("Setting up authentication proxy");
|
||||
try {
|
||||
const proxyFileName = getProxyFilename();
|
||||
const proxyInfo = await getDownloadUrl(action, apiDetails);
|
||||
logger2.info(
|
||||
`Using authentication proxy from CodeQL release ${proxyInfo.version}.`
|
||||
);
|
||||
let proxyDir = toolcache4.find(proxyFileName, proxyInfo.version);
|
||||
if (!proxyDir) {
|
||||
logger2.info(
|
||||
`Authentication proxy is not in the toolcache. Will try to download it from '${proxyInfo.url}'.`
|
||||
);
|
||||
const authorization = getAuthorizationHeaderFor(
|
||||
logger2,
|
||||
apiDetails,
|
||||
proxyInfo.url
|
||||
);
|
||||
const temp = await downloadProxy(logger2, proxyInfo.url, authorization);
|
||||
logger2.info(`Downloaded the authentication proxy asset to '${temp}'.`);
|
||||
const extracted = await extractProxy(logger2, temp);
|
||||
proxyDir = await cacheProxy(
|
||||
logger2,
|
||||
extracted,
|
||||
proxyFileName,
|
||||
proxyInfo.version
|
||||
);
|
||||
logger2.info(`Extracted the authentication proxy to '${proxyDir}'.`);
|
||||
}
|
||||
return path27.join(proxyDir, proxyFileName);
|
||||
} finally {
|
||||
logger2.endGroup();
|
||||
}
|
||||
return path27.join(proxyBin, proxyFileName);
|
||||
}
|
||||
|
||||
// src/start-proxy/ca.ts
|
||||
@@ -188255,7 +188234,10 @@ async function run7(action) {
|
||||
ca
|
||||
};
|
||||
const actionWithFeatures = extendActionState(action, { features });
|
||||
const proxyBin = await getProxyBinaryPath(actionWithFeatures);
|
||||
const proxyBin = await getProxyBinaryPath(
|
||||
actionWithFeatures,
|
||||
getApiDetails(action.env)
|
||||
);
|
||||
const proxyInfo = await startProxy(
|
||||
proxyBin,
|
||||
proxyConfig,
|
||||
|
||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -27,7 +27,6 @@
|
||||
"@octokit/plugin-rest-endpoint-methods": "^18.0.0",
|
||||
"@octokit/plugin-retry": "^8.1.1",
|
||||
"archiver": "^8.0.0",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"follow-redirects": "^1.16.1",
|
||||
"get-folder-size": "^5.0.0",
|
||||
"https-proxy-agent": "^7.0.6",
|
||||
@@ -5802,6 +5801,7 @@
|
||||
},
|
||||
"node_modules/fast-deep-equal": {
|
||||
"version": "3.1.3",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-diff": {
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
"@octokit/plugin-rest-endpoint-methods": "^18.0.0",
|
||||
"@octokit/plugin-retry": "^8.1.1",
|
||||
"archiver": "^8.0.0",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"follow-redirects": "^1.16.1",
|
||||
"get-folder-size": "^5.0.0",
|
||||
"https-proxy-agent": "^7.0.6",
|
||||
|
||||
@@ -101,7 +101,7 @@ export function getWorkflowEventName(env: Env = getEnv()) {
|
||||
* Returns whether the current workflow is executing a local copy of the Action, e.g. we're running
|
||||
* a workflow on the codeql-action repo itself.
|
||||
*/
|
||||
export function isRunningLocalAction(env: Env = getEnv()): boolean {
|
||||
export function isRunningLocalAction(env: ReadOnlyEnv = getEnv()): boolean {
|
||||
const relativeScriptPath = getRelativeScriptPath(env);
|
||||
return (
|
||||
relativeScriptPath.startsWith("..") || path.isAbsolute(relativeScriptPath)
|
||||
@@ -113,7 +113,7 @@ export function isRunningLocalAction(env: Env = getEnv()): boolean {
|
||||
*
|
||||
* This can be used to get the Action's name or tell if we're running a local Action.
|
||||
*/
|
||||
function getRelativeScriptPath(env: Env): string {
|
||||
function getRelativeScriptPath(env: ReadOnlyEnv): string {
|
||||
const runnerTemp = env.getRequired(ActionsEnvVars.RUNNER_TEMP);
|
||||
const actionsDirectory = path.join(path.dirname(runnerTemp), "_actions");
|
||||
return path.relative(actionsDirectory, __filename);
|
||||
|
||||
@@ -6,6 +6,14 @@ export interface RepositoryNwo {
|
||||
repo: string;
|
||||
}
|
||||
|
||||
/** An approximation of what a repository NWO string looks like. */
|
||||
export type RepositoryNwoStr = `${string}/${string}`;
|
||||
|
||||
/** A basic check that `val` looks like a `RepositoryNwoStr`. */
|
||||
export function isRepositoryNwoStr(val: string): val is RepositoryNwoStr {
|
||||
return val.includes("/");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the repository name with owner from the environment variable
|
||||
* `GITHUB_REPOSITORY`.
|
||||
|
||||
@@ -126,24 +126,6 @@ test.serial("convert to semver", (t) => {
|
||||
}
|
||||
});
|
||||
|
||||
test.serial("getCodeQLActionRepository", (t) => {
|
||||
const logger = getRunnerLogger(true);
|
||||
|
||||
initializeEnvironment("1.2.3");
|
||||
|
||||
// isRunningLocalAction() === true
|
||||
delete process.env["GITHUB_ACTION_REPOSITORY"];
|
||||
process.env["RUNNER_TEMP"] = path.dirname(__dirname);
|
||||
const repoLocalRunner = setupCodeql.getCodeQLActionRepository(logger);
|
||||
t.deepEqual(repoLocalRunner, "github/codeql-action");
|
||||
|
||||
// isRunningLocalAction() === false
|
||||
sinon.stub(actionsUtil, "isRunningLocalAction").returns(false);
|
||||
process.env["GITHUB_ACTION_REPOSITORY"] = "xxx/yyy";
|
||||
const repoEnv = setupCodeql.getCodeQLActionRepository(logger);
|
||||
t.deepEqual(repoEnv, "xxx/yyy");
|
||||
});
|
||||
|
||||
test.serial(
|
||||
"getCodeQLSource sets CLI version for a semver tagged bundle",
|
||||
async (t) => {
|
||||
|
||||
@@ -4,7 +4,6 @@ import * as path from "path";
|
||||
import { performance } from "perf_hooks";
|
||||
|
||||
import * as toolcache from "@actions/tool-cache";
|
||||
import { default as deepEqual } from "fast-deep-equal";
|
||||
import * as semver from "semver";
|
||||
import { v4 as uuidV4 } from "uuid";
|
||||
|
||||
@@ -13,7 +12,6 @@ import {
|
||||
isAnalyzingPullRequest,
|
||||
isDynamicWorkflow,
|
||||
isGitHubHostedRunner,
|
||||
isRunningLocalAction,
|
||||
} from "./actions-util";
|
||||
import * as api from "./api-client";
|
||||
import {
|
||||
@@ -44,6 +42,7 @@ import {
|
||||
logPerLanguageBundleFallback,
|
||||
} from "./per-language-bundles";
|
||||
import { getBundlePlatform } from "./platform";
|
||||
import { getCodeQLAssetDownloadURL } from "./setup/repository";
|
||||
import * as tar from "./tar";
|
||||
import {
|
||||
deleteToolcacheBundles,
|
||||
@@ -65,7 +64,6 @@ export enum ToolsSource {
|
||||
Download = "DOWNLOAD",
|
||||
}
|
||||
|
||||
const CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action";
|
||||
const CODEQL_NIGHTLIES_REPOSITORY_OWNER = "dsp-testing";
|
||||
const CODEQL_NIGHTLIES_REPOSITORY_NAME = "codeql-cli-nightlies";
|
||||
|
||||
@@ -73,75 +71,6 @@ const CODEQL_BUNDLE_VERSION_ALIAS: string[] = ["linked", "latest"];
|
||||
const CODEQL_NIGHTLY_TOOLS_INPUTS = ["nightly", "nightly-latest"];
|
||||
const CODEQL_TOOLCACHE_INPUT = "toolcache";
|
||||
|
||||
export function getCodeQLActionRepository(logger: Logger): string {
|
||||
if (isRunningLocalAction()) {
|
||||
// This handles the case where the Action does not come from an Action repository,
|
||||
// e.g. our integration tests which use the Action code from the current checkout.
|
||||
// In these cases, the GITHUB_ACTION_REPOSITORY environment variable is not set.
|
||||
logger.info(
|
||||
"The CodeQL Action is checked out locally. Using the default CodeQL Action repository.",
|
||||
);
|
||||
return CODEQL_DEFAULT_ACTION_REPOSITORY;
|
||||
}
|
||||
|
||||
return util.getRequiredEnvParam("GITHUB_ACTION_REPOSITORY");
|
||||
}
|
||||
|
||||
async function getCodeQLBundleDownloadURL(
|
||||
tagName: string,
|
||||
apiDetails: api.GitHubApiDetails,
|
||||
codeQLBundleName: string,
|
||||
logger: Logger,
|
||||
): Promise<string> {
|
||||
const codeQLActionRepository = getCodeQLActionRepository(logger);
|
||||
const potentialDownloadSources = [
|
||||
// This GitHub instance, and this Action.
|
||||
[apiDetails.url, codeQLActionRepository],
|
||||
// This GitHub instance, and the canonical Action.
|
||||
[apiDetails.url, CODEQL_DEFAULT_ACTION_REPOSITORY],
|
||||
// GitHub.com, and the canonical Action.
|
||||
[util.GITHUB_DOTCOM_URL, CODEQL_DEFAULT_ACTION_REPOSITORY],
|
||||
];
|
||||
// We now filter out any duplicates.
|
||||
// Duplicates will happen either because the GitHub instance is GitHub.com, or because the Action is not a fork.
|
||||
const uniqueDownloadSources = potentialDownloadSources.filter(
|
||||
(source, index, self) => {
|
||||
return !self.slice(0, index).some((other) => deepEqual(source, other));
|
||||
},
|
||||
);
|
||||
for (const downloadSource of uniqueDownloadSources) {
|
||||
const [apiURL, repository] = downloadSource;
|
||||
// If we've reached the final case, short-circuit the API check since we know the bundle exists and is public.
|
||||
if (
|
||||
apiURL === util.GITHUB_DOTCOM_URL &&
|
||||
repository === CODEQL_DEFAULT_ACTION_REPOSITORY
|
||||
) {
|
||||
break;
|
||||
}
|
||||
const [repositoryOwner, repositoryName] = repository.split("/");
|
||||
try {
|
||||
const release = await api.getApiClient().rest.repos.getReleaseByTag({
|
||||
owner: repositoryOwner,
|
||||
repo: repositoryName,
|
||||
tag: tagName,
|
||||
});
|
||||
for (const asset of release.data.assets) {
|
||||
if (asset.name === codeQLBundleName) {
|
||||
logger.info(
|
||||
`Found CodeQL bundle ${codeQLBundleName} in ${repository} on ${apiURL} with URL ${asset.url}.`,
|
||||
);
|
||||
return asset.url;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
logger.info(
|
||||
`Looked for CodeQL bundle ${codeQLBundleName} in ${repository} on ${apiURL} but got error ${e}.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
return `https://github.com/${CODEQL_DEFAULT_ACTION_REPOSITORY}/releases/download/${tagName}/${codeQLBundleName}`;
|
||||
}
|
||||
|
||||
function tryGetBundleVersionFromTagName(
|
||||
tagName: string,
|
||||
logger: Logger,
|
||||
@@ -720,9 +649,10 @@ export async function getCodeQLSource(
|
||||
? "zstd"
|
||||
: "gzip";
|
||||
|
||||
const action = { env: getEnv(), logger };
|
||||
const platform = getBundlePlatform();
|
||||
const perLanguageBundleLanguage = await getPerLanguageBundleLanguage(
|
||||
{ env: getEnv(), features, logger },
|
||||
{ ...action, features },
|
||||
{
|
||||
rawLanguages,
|
||||
otherLanguagePacksReason,
|
||||
@@ -735,11 +665,11 @@ export async function getCodeQLSource(
|
||||
|
||||
// Resolves the combined or per-language bundle URL for the requested release.
|
||||
const resolveBundleURL = (language?: BuiltInLanguage) =>
|
||||
getCodeQLBundleDownloadURL(
|
||||
bundleTagName,
|
||||
getCodeQLAssetDownloadURL(
|
||||
action,
|
||||
apiDetails,
|
||||
bundleTagName,
|
||||
getCodeQLBundleName(compressionMethod, platform, language),
|
||||
logger,
|
||||
);
|
||||
|
||||
const combinedBundleURL = await resolveBundleURL();
|
||||
|
||||
35
src/setup/repository.test.ts
Normal file
35
src/setup/repository.test.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import * as path from "path";
|
||||
|
||||
import test from "ava";
|
||||
import * as sinon from "sinon";
|
||||
|
||||
import * as actionsUtil from "../actions-util";
|
||||
import { ActionsEnvVars } from "../environment";
|
||||
import { callee, getTestEnv, setupTests } from "../testing-utils";
|
||||
import { initializeEnvironment } from "../util";
|
||||
|
||||
import { getCodeQLActionRepository } from "./repository";
|
||||
|
||||
setupTests(test);
|
||||
|
||||
test.serial("getCodeQLActionRepository", async (t) => {
|
||||
const initialEnv = getTestEnv({
|
||||
[ActionsEnvVars.RUNNER_TEMP]: path.dirname(__dirname),
|
||||
});
|
||||
initializeEnvironment("1.2.3", initialEnv);
|
||||
|
||||
const target = callee(getCodeQLActionRepository)
|
||||
.withArgs()
|
||||
.withEnv(initialEnv);
|
||||
|
||||
// isRunningLocalAction() === true
|
||||
await target.passes(t.deepEqual, "github/codeql-action");
|
||||
|
||||
// isRunningLocalAction() === false
|
||||
sinon.stub(actionsUtil, "isRunningLocalAction").returns(false);
|
||||
await target
|
||||
.withEnv((env) => {
|
||||
env.set(ActionsEnvVars.GITHUB_ACTION_REPOSITORY, "xxx/yyy");
|
||||
})
|
||||
.passes(t.deepEqual, "xxx/yyy");
|
||||
});
|
||||
158
src/setup/repository.ts
Normal file
158
src/setup/repository.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
import { ActionState } from "../action-common";
|
||||
import { isRunningLocalAction } from "../actions-util";
|
||||
import * as api from "../api-client";
|
||||
import { ActionsEnvVars } from "../environment";
|
||||
import {
|
||||
isRepositoryNwoStr,
|
||||
parseRepositoryNwo,
|
||||
type RepositoryNwoStr,
|
||||
} from "../repository";
|
||||
import { GITHUB_DOTCOM_URL, type InstanceURL } from "../util";
|
||||
|
||||
/** The NWO of the standard CodeQL Action repository. */
|
||||
export const CODEQL_DEFAULT_ACTION_REPOSITORY = "github/codeql-action";
|
||||
|
||||
/**
|
||||
* Retrieves the NWO of the repository that the CodeQL Action is loaded from.
|
||||
* Typically, this will be `github/codeql-action`, but it may be something else for
|
||||
* forks of the Action or in environments other than GitHub.com.
|
||||
*
|
||||
* If this function detects that we are running the Action locally (e.g. in tests),
|
||||
* then we default to `CODEQL_DEFAULT_ACTION_REPOSITORY`.
|
||||
*/
|
||||
export function getCodeQLActionRepository(
|
||||
action: ActionState<["ReadOnlyEnv", "Logger"]>,
|
||||
): RepositoryNwoStr {
|
||||
if (isRunningLocalAction(action.env)) {
|
||||
// This handles the case where the Action does not come from an Action repository,
|
||||
// e.g. our integration tests which use the Action code from the current checkout.
|
||||
// In these cases, the GITHUB_ACTION_REPOSITORY environment variable is not set.
|
||||
action.logger.info(
|
||||
"The CodeQL Action is checked out locally. Using the default CodeQL Action repository.",
|
||||
);
|
||||
return CODEQL_DEFAULT_ACTION_REPOSITORY;
|
||||
}
|
||||
|
||||
const actionRepository = action.env.getRequired(
|
||||
ActionsEnvVars.GITHUB_ACTION_REPOSITORY,
|
||||
);
|
||||
|
||||
if (isRepositoryNwoStr(actionRepository)) {
|
||||
return actionRepository;
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`The value of '${ActionsEnvVars.GITHUB_ACTION_REPOSITORY}' is '${actionRepository}', which does not match the expected 'owner/repo' format.`,
|
||||
);
|
||||
}
|
||||
|
||||
/**A download source is a pair of strings. */
|
||||
export type DownloadSource = [InstanceURL, RepositoryNwoStr];
|
||||
|
||||
/** GitHub.com, and the canonical Action. */
|
||||
export const DEFAULT_DOWNLOAD_SOURCE: DownloadSource = [
|
||||
GITHUB_DOTCOM_URL,
|
||||
CODEQL_DEFAULT_ACTION_REPOSITORY,
|
||||
];
|
||||
|
||||
/** Decides if the two provided download sources are the same. */
|
||||
const isSameDownloadSource = (
|
||||
[srcUrl, srcRepo]: DownloadSource,
|
||||
[otherUrl, otherRepo]: DownloadSource,
|
||||
) => {
|
||||
return srcUrl === otherUrl && srcRepo === otherRepo;
|
||||
};
|
||||
|
||||
/** A download URL is represented as a string. */
|
||||
export type DownloadURL = string;
|
||||
|
||||
/** Gets the default GitHub.com download URL for `assetName` in a release tagged `tagName`. */
|
||||
export function getDefaultDotcomDownloadURL(
|
||||
tagName: string,
|
||||
assetName: string,
|
||||
): DownloadURL {
|
||||
return `${GITHUB_DOTCOM_URL}/${CODEQL_DEFAULT_ACTION_REPOSITORY}/releases/download/${tagName}/${assetName}`;
|
||||
}
|
||||
|
||||
/** Enumerates log-friendly descriptions of different kinds of assets we might look for in releases. */
|
||||
export type ReleaseAssetKind = "CodeQL bundle" | "private registry proxy";
|
||||
|
||||
/**
|
||||
* Tries to find a download URL for `assetName` in a release tagged with `tagName`.
|
||||
*
|
||||
* Depending on where and how the CodeQL Action is running, we may be using different `apiDetails` and there may be
|
||||
* different options for where to source CodeQL releases from.
|
||||
*
|
||||
* This function either returns the download URL for the asset for the first release we find, or
|
||||
* defaults to the assumed download URL for the asset on the default CodeQL Action repository on GitHub.com.
|
||||
* In the latter case, this function does not guarantee that the asset actually exists.
|
||||
*
|
||||
* @param action The Action state.
|
||||
* @param apiDetails The details of the GitHub API in use.
|
||||
* @param tagName The name of the release tag we want to obtain the asset from.
|
||||
* @param assetName The name of the asset we should look for in the release.
|
||||
* @param [assetKind="CodeQL bundle"] The kind of asset we are looking for to show in log messages.
|
||||
* @returns A URL that we can use to download the asset.
|
||||
*/
|
||||
export async function getCodeQLAssetDownloadURL(
|
||||
action: ActionState<["ReadOnlyEnv", "Logger"]>,
|
||||
apiDetails: api.GitHubApiDetails,
|
||||
tagName: string,
|
||||
assetName: string,
|
||||
assetKind: ReleaseAssetKind = "CodeQL bundle",
|
||||
): Promise<DownloadURL> {
|
||||
const codeQLActionRepository = getCodeQLActionRepository(action);
|
||||
|
||||
const potentialDownloadSources: DownloadSource[] = [
|
||||
// This GitHub instance, and this Action.
|
||||
[apiDetails.url, codeQLActionRepository],
|
||||
// This GitHub instance, and the canonical Action.
|
||||
[apiDetails.url, CODEQL_DEFAULT_ACTION_REPOSITORY],
|
||||
// GitHub.com, and the canonical Action.
|
||||
DEFAULT_DOWNLOAD_SOURCE,
|
||||
];
|
||||
|
||||
// We now filter out any duplicates.
|
||||
// Duplicates will happen either because the GitHub instance is GitHub.com, or because the Action is not a fork.
|
||||
const uniqueDownloadSources = potentialDownloadSources.filter(
|
||||
(source, index, self) => {
|
||||
return !self
|
||||
.slice(0, index)
|
||||
.some((other) => isSameDownloadSource(source, other));
|
||||
},
|
||||
);
|
||||
|
||||
for (const [instanceURL, 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, [instanceURL, repository])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
const { owner: repositoryOwner, repo: repositoryName } =
|
||||
parseRepositoryNwo(repository);
|
||||
try {
|
||||
const release = await api.getApiClient().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 ${instanceURL} with URL ${asset.url}.`,
|
||||
);
|
||||
return asset.url;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
action.logger.info(
|
||||
`Looked for ${assetKind} ${assetName} in ${repository} on ${instanceURL} but got error ${e}.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return getDefaultDotcomDownloadURL(tagName, assetName);
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
runInActions,
|
||||
} from "./action-common";
|
||||
import * as actionsUtil from "./actions-util";
|
||||
import { getGitHubVersion } from "./api-client";
|
||||
import { getApiDetails, getGitHubVersion } from "./api-client";
|
||||
import { FeatureEnablement, initFeatures } from "./feature-flags";
|
||||
import { BuiltInLanguage, parseBuiltInLanguage } from "./languages";
|
||||
import { Logger } from "./logging";
|
||||
@@ -104,7 +104,10 @@ async function run(action: ActionState<["Base", "Logger", "Env", "Actions"]>) {
|
||||
|
||||
// Start the Proxy
|
||||
const actionWithFeatures = extendActionState(action, { features });
|
||||
const proxyBin = await getProxyBinaryPath(actionWithFeatures);
|
||||
const proxyBin = await getProxyBinaryPath(
|
||||
actionWithFeatures,
|
||||
getApiDetails(action.env),
|
||||
);
|
||||
const proxyInfo = await startProxy(
|
||||
proxyBin,
|
||||
proxyConfig,
|
||||
|
||||
@@ -6,17 +6,21 @@ import test, { ExecutionContext } from "ava";
|
||||
import sinon from "sinon";
|
||||
|
||||
import { ActionState } from "./action-common";
|
||||
import * as actionsUtil from "./actions-util";
|
||||
import * as apiClient from "./api-client";
|
||||
import * as defaults from "./defaults.json";
|
||||
import { ActionsEnvVars } from "./environment";
|
||||
import { setUpFeatureFlagTests } from "./feature-flags/testing-util";
|
||||
import { UnvalidatedObject, validateSchema } from "./json";
|
||||
import { makeFromSchema } from "./json/testing-util";
|
||||
import { BuiltInLanguage } from "./languages";
|
||||
import { getRunnerLogger, Logger } from "./logging";
|
||||
import { BundlePlatform, getBundlePlatform } from "./platform";
|
||||
import * as repository from "./setup/repository";
|
||||
import * as startProxyExports from "./start-proxy";
|
||||
import * as statusReport from "./status-report";
|
||||
import {
|
||||
addSinonAssertions,
|
||||
assertNotLogged,
|
||||
checkExpectedLogMessages,
|
||||
createFeatures,
|
||||
@@ -24,6 +28,7 @@ import {
|
||||
makeMacro,
|
||||
makeTestToken,
|
||||
RecordingLogger,
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
setupTests,
|
||||
withRecordingLoggerAsync,
|
||||
} from "./testing-utils";
|
||||
@@ -705,18 +710,29 @@ function mockGetApiClient(endpoints: any) {
|
||||
|
||||
type ReleaseAssets = Array<{ name: string; url?: string }>;
|
||||
|
||||
function mockGetReleaseByTag(assets?: ReleaseAssets) {
|
||||
function mockGetReleaseByTag(expectedTag?: string, assets?: ReleaseAssets) {
|
||||
const getReleaseByTag =
|
||||
assets === undefined
|
||||
? sinon.stub().rejects()
|
||||
: sinon.stub().resolves({
|
||||
status: 200,
|
||||
data: { assets },
|
||||
headers: {},
|
||||
url: "GET /repos/:owner/:repo/releases/tags/:tag",
|
||||
: sinon.stub().callsFake(({ tag }) => {
|
||||
if (tag === expectedTag) {
|
||||
return {
|
||||
status: 200,
|
||||
data: { assets },
|
||||
headers: {},
|
||||
url: "GET /repos/:owner/:repo/releases/tags/:tag",
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
status: 404,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return mockGetApiClient({ repos: { getReleaseByTag } });
|
||||
return {
|
||||
getReleaseByTag,
|
||||
getApiClient: mockGetApiClient({ repos: { getReleaseByTag } }),
|
||||
};
|
||||
}
|
||||
|
||||
function mockOfflineFeatures(tempDir: string, logger: Logger) {
|
||||
@@ -751,25 +767,33 @@ test.serial(
|
||||
logger,
|
||||
features,
|
||||
});
|
||||
const info = await startProxyExports.getDownloadUrl(state);
|
||||
|
||||
t.is(info.version, startProxyExports.UPDATEJOB_PROXY_VERSION);
|
||||
t.is(
|
||||
info.url,
|
||||
startProxyExports.getFallbackUrl(
|
||||
startProxyExports.getProxyPackage(BundlePlatform.Linux64),
|
||||
),
|
||||
// Stub this to always return `true` so we get the default repo for the tests.
|
||||
sinon.stub(actionsUtil, "isRunningLocalAction").returns(true);
|
||||
|
||||
const info = await startProxyExports.getDownloadUrl(
|
||||
state,
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
);
|
||||
|
||||
t.true(
|
||||
logger.hasMessage(`Unsupported platform android on architecture ppc`),
|
||||
);
|
||||
|
||||
t.is(info.version, defaults.cliVersion);
|
||||
t.is(
|
||||
info.url,
|
||||
repository.getDefaultDotcomDownloadURL(
|
||||
defaults.bundleVersion,
|
||||
startProxyExports.getProxyPackage(BundlePlatform.Linux64),
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getDownloadUrl returns fallback when `getReleaseByVersion` rejects",
|
||||
"getDownloadUrl returns default bundle URL for linked version",
|
||||
async (t) => {
|
||||
const logger = new RecordingLogger();
|
||||
mockGetReleaseByTag();
|
||||
@@ -777,12 +801,20 @@ test.serial(
|
||||
await withTmpDir(async (tempDir) => {
|
||||
const features = mockOfflineFeatures(tempDir, logger);
|
||||
const state = initAllState({ logger, features });
|
||||
const info = await startProxyExports.getDownloadUrl(state);
|
||||
|
||||
t.is(info.version, startProxyExports.UPDATEJOB_PROXY_VERSION);
|
||||
// Stub this to always return `true` so we get the default repo for the tests.
|
||||
sinon.stub(actionsUtil, "isRunningLocalAction").returns(true);
|
||||
|
||||
const info = await startProxyExports.getDownloadUrl(
|
||||
state,
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
);
|
||||
|
||||
t.is(info.version, defaults.cliVersion);
|
||||
t.is(
|
||||
info.url,
|
||||
startProxyExports.getFallbackUrl(
|
||||
repository.getDefaultDotcomDownloadURL(
|
||||
defaults.bundleVersion,
|
||||
startProxyExports.getProxyPackage(getTestPlatform(state)),
|
||||
),
|
||||
);
|
||||
@@ -791,7 +823,7 @@ test.serial(
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getDownloadUrl returns fallback when there's no matching release asset",
|
||||
"getDownloadUrl doesn't check that the default asset exists",
|
||||
async (t) => {
|
||||
const logger = new RecordingLogger();
|
||||
const testAssets = [[], [{ name: "foo" }]];
|
||||
@@ -800,19 +832,28 @@ test.serial(
|
||||
const features = mockOfflineFeatures(tempDir, logger);
|
||||
const state = initAllState({ logger, features });
|
||||
|
||||
for (const assets of testAssets) {
|
||||
const stub = mockGetReleaseByTag(assets);
|
||||
const info = await startProxyExports.getDownloadUrl(state);
|
||||
// Stub this to always return `true` so we get the default repo for the tests.
|
||||
sinon.stub(actionsUtil, "isRunningLocalAction").returns(true);
|
||||
|
||||
t.is(info.version, startProxyExports.UPDATEJOB_PROXY_VERSION);
|
||||
for (const assets of testAssets) {
|
||||
const stubs = mockGetReleaseByTag(defaults.bundleVersion, assets);
|
||||
const info = await startProxyExports.getDownloadUrl(
|
||||
state,
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
);
|
||||
|
||||
t.is(info.version, defaults.cliVersion);
|
||||
t.is(
|
||||
info.url,
|
||||
startProxyExports.getFallbackUrl(
|
||||
repository.getDefaultDotcomDownloadURL(
|
||||
defaults.bundleVersion,
|
||||
startProxyExports.getProxyPackage(getTestPlatform(state)),
|
||||
),
|
||||
);
|
||||
|
||||
stub.restore();
|
||||
// mockGetReleaseByTag stubs the global getApiClient; since we are calling
|
||||
// that in a loop, we need to manually restore it here
|
||||
stubs.getApiClient.restore();
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -828,11 +869,22 @@ test.serial("getDownloadUrl returns matching release asset", async (t) => {
|
||||
url: "url-we-want",
|
||||
},
|
||||
];
|
||||
mockGetReleaseByTag(assets);
|
||||
const stubs = mockGetReleaseByTag(defaults.bundleVersion, assets);
|
||||
|
||||
await withTmpDir(async (tempDir) => {
|
||||
state.env.set(ActionsEnvVars.RUNNER_TEMP, tempDir);
|
||||
const features = mockOfflineFeatures(tempDir, logger);
|
||||
const info = await startProxyExports.getDownloadUrl({ ...state, features });
|
||||
|
||||
// Stub this to always return `false` so we force `getCodeQLAssetDownloadURL` to use the (mocked) API.
|
||||
sinon.stub(actionsUtil, "isRunningLocalAction").returns(false);
|
||||
state.env.set(ActionsEnvVars.GITHUB_ACTION_REPOSITORY, "test/repo");
|
||||
|
||||
const info = await startProxyExports.getDownloadUrl(
|
||||
{ ...state, features },
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
);
|
||||
|
||||
t.is(stubs.getReleaseByTag.callCount, 1);
|
||||
|
||||
t.is(info.version, defaults.cliVersion);
|
||||
t.is(info.url, "url-we-want");
|
||||
@@ -965,9 +1017,13 @@ test.serial(
|
||||
const toolcachePath = "/path/to/proxy/dir";
|
||||
sinon.stub(toolcache, "find").returns(toolcachePath);
|
||||
|
||||
// Stub this to always return `true` so we get the default repo for the tests.
|
||||
sinon.stub(actionsUtil, "isRunningLocalAction").returns(true);
|
||||
|
||||
const features = mockOfflineFeatures(tempDir, logger);
|
||||
const path = await startProxyExports.getProxyBinaryPath(
|
||||
initAllState({ logger, features }),
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
);
|
||||
|
||||
t.assert(path);
|
||||
@@ -985,7 +1041,7 @@ test.serial(
|
||||
const logger = new RecordingLogger();
|
||||
const state = initAllState({ logger });
|
||||
const downloadUrl = "url-we-want";
|
||||
mockGetReleaseByTag([
|
||||
const stubs = mockGetReleaseByTag(defaults.bundleVersion, [
|
||||
{
|
||||
name: startProxyExports.getProxyPackage(getTestPlatform(state)),
|
||||
url: downloadUrl,
|
||||
@@ -994,11 +1050,6 @@ test.serial(
|
||||
|
||||
const toolcachePath = "/path/to/proxy/dir";
|
||||
const find = sinon.stub(toolcache, "find").returns("");
|
||||
const getApiDetails = sinon.stub(apiClient, "getApiDetails").returns({
|
||||
auth: "",
|
||||
url: "",
|
||||
apiURL: "",
|
||||
});
|
||||
const getAuthorizationHeaderFor = sinon
|
||||
.stub(apiClient, "getAuthorizationHeaderFor")
|
||||
.returns(undefined);
|
||||
@@ -1012,17 +1063,27 @@ test.serial(
|
||||
.resolves(extractedPath);
|
||||
const cacheDir = sinon.stub(toolcache, "cacheDir").resolves(toolcachePath);
|
||||
|
||||
const path = await startProxyExports.getProxyBinaryPath({
|
||||
...state,
|
||||
features: createFeatures([]),
|
||||
});
|
||||
// Stub this to always return `false` so we force `getCodeQLAssetDownloadURL` to use the (mocked) API.
|
||||
sinon.stub(actionsUtil, "isRunningLocalAction").returns(false);
|
||||
state.env.set(ActionsEnvVars.GITHUB_ACTION_REPOSITORY, "test/repo");
|
||||
|
||||
const path = await startProxyExports.getProxyBinaryPath(
|
||||
{
|
||||
...state,
|
||||
features: createFeatures([]),
|
||||
},
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
);
|
||||
|
||||
t.is(stubs.getReleaseByTag.callCount, 1);
|
||||
t.assert(find.calledOnce);
|
||||
t.assert(getApiDetails.calledOnce);
|
||||
t.assert(getAuthorizationHeaderFor.calledOnce);
|
||||
t.assert(downloadTool.calledOnceWith(downloadUrl));
|
||||
t.assert(extractTar.calledOnceWith(archivePath));
|
||||
t.assert(cacheDir.calledOnceWith(extractedPath));
|
||||
|
||||
const st = addSinonAssertions(t);
|
||||
st.onceWith(downloadTool, downloadUrl);
|
||||
st.onceWith(extractTar, archivePath);
|
||||
st.onceWith(cacheDir, extractedPath);
|
||||
|
||||
t.assert(path);
|
||||
t.is(
|
||||
path,
|
||||
@@ -1030,7 +1091,7 @@ test.serial(
|
||||
);
|
||||
|
||||
checkExpectedLogMessages(t, logger.messages, [
|
||||
`Found '${startProxyExports.getProxyPackage(getTestPlatform(state))}' in release '${defaults.bundleVersion}' at '${downloadUrl}'`,
|
||||
`Found private registry proxy ${startProxyExports.getProxyPackage(getTestPlatform(state))} in test/repo on https://github.com with URL ${downloadUrl}`,
|
||||
]);
|
||||
},
|
||||
);
|
||||
@@ -1042,8 +1103,8 @@ test.serial(
|
||||
const state = initAllState({ logger });
|
||||
const expectedTag = "codeql-bundle-v2.20.1";
|
||||
const expectedParams = {
|
||||
owner: "github",
|
||||
repo: "codeql-action",
|
||||
owner: "test",
|
||||
repo: "repo",
|
||||
tag: expectedTag,
|
||||
};
|
||||
const downloadUrl = "url-we-want";
|
||||
@@ -1066,11 +1127,6 @@ test.serial(
|
||||
await withTmpDir(async (tempDir) => {
|
||||
const toolcachePath = "/path/to/proxy/dir";
|
||||
const find = sinon.stub(toolcache, "find").returns("");
|
||||
const getApiDetails = sinon.stub(apiClient, "getApiDetails").returns({
|
||||
auth: "",
|
||||
url: "",
|
||||
apiURL: "",
|
||||
});
|
||||
const getAuthorizationHeaderFor = sinon
|
||||
.stub(apiClient, "getAuthorizationHeaderFor")
|
||||
.returns(undefined);
|
||||
@@ -1100,22 +1156,28 @@ test.serial(
|
||||
.resolves({
|
||||
enabledVersions: [{ cliVersion: "2.20.1", tagName: expectedTag }],
|
||||
});
|
||||
const path = await startProxyExports.getProxyBinaryPath({
|
||||
...state,
|
||||
features,
|
||||
});
|
||||
|
||||
// Stub this to always return `false` so we force `getCodeQLAssetDownloadURL` to use the (mocked) API.
|
||||
sinon.stub(actionsUtil, "isRunningLocalAction").returns(false);
|
||||
state.env.set(ActionsEnvVars.GITHUB_ACTION_REPOSITORY, "test/repo");
|
||||
|
||||
const path = await startProxyExports.getProxyBinaryPath(
|
||||
{
|
||||
...state,
|
||||
features,
|
||||
},
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
);
|
||||
|
||||
t.assert(getDefaultCliVersion.calledOnce);
|
||||
sinon.assert.calledOnceWithMatch(
|
||||
getReleaseByTag,
|
||||
sinon.match(expectedParams),
|
||||
);
|
||||
|
||||
const st = addSinonAssertions(t);
|
||||
st.onceWith(getReleaseByTag, expectedParams);
|
||||
t.assert(find.calledOnce);
|
||||
t.assert(getApiDetails.calledOnce);
|
||||
t.assert(getAuthorizationHeaderFor.calledOnce);
|
||||
t.assert(downloadTool.calledOnceWith(downloadUrl));
|
||||
t.assert(extractTar.calledOnceWith(archivePath));
|
||||
t.assert(cacheDir.calledOnceWith(extractedPath));
|
||||
st.onceWith(downloadTool, downloadUrl);
|
||||
st.onceWith(extractTar, archivePath);
|
||||
st.onceWith(cacheDir, extractedPath);
|
||||
|
||||
t.assert(path);
|
||||
t.is(
|
||||
@@ -1125,7 +1187,7 @@ test.serial(
|
||||
});
|
||||
|
||||
checkExpectedLogMessages(t, logger.messages, [
|
||||
`Found '${startProxyExports.getProxyPackage(getTestPlatform(state))}' in release '${expectedTag}' at '${downloadUrl}'`,
|
||||
`Found private registry proxy ${startProxyExports.getProxyPackage(getTestPlatform(state))} in test/repo on https://github.com with URL url-we-want.`,
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -5,10 +5,9 @@ import * as toolcache from "@actions/tool-cache";
|
||||
|
||||
import { ActionState } from "./action-common";
|
||||
import {
|
||||
getApiClient,
|
||||
getApiDetails,
|
||||
getAuthorizationHeaderFor,
|
||||
getGitHubVersion,
|
||||
GitHubApiDetails,
|
||||
} from "./api-client";
|
||||
import * as artifactScanner from "./artifact-scanner";
|
||||
import { Config } from "./config-utils";
|
||||
@@ -22,6 +21,7 @@ import * as json from "./json";
|
||||
import { BuiltInLanguage } from "./languages";
|
||||
import { Logger } from "./logging";
|
||||
import { BundlePlatform, getBundlePlatform } from "./platform";
|
||||
import { getCodeQLAssetDownloadURL } from "./setup/repository";
|
||||
import {
|
||||
Address,
|
||||
Registry,
|
||||
@@ -171,10 +171,8 @@ export async function sendFailedStatusReport(
|
||||
}
|
||||
}
|
||||
|
||||
/** The basename of the proxy artifacts. */
|
||||
export const UPDATEJOB_PROXY = "update-job-proxy";
|
||||
export const UPDATEJOB_PROXY_VERSION = "v2.0.20250624110901";
|
||||
const UPDATEJOB_PROXY_URL_PREFIX =
|
||||
"https://github.com/github/codeql-action/releases/download/codeql-bundle-v2.22.0/";
|
||||
|
||||
function isPAT(value: string) {
|
||||
return artifactScanner.isAuthToken(value, [
|
||||
@@ -379,30 +377,6 @@ export function getProxyPackage(platform: BundlePlatform): string {
|
||||
return `${UPDATEJOB_PROXY}-${platform}.tar.gz`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the fallback URL for downloading the proxy release asset.
|
||||
*
|
||||
* @param proxyPackage The asset name.
|
||||
* @returns The full URL to download the specified asset from the fallback release.
|
||||
*/
|
||||
export function getFallbackUrl(proxyPackage: string): string {
|
||||
return `${UPDATEJOB_PROXY_URL_PREFIX}${proxyPackage}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the GitHub API to obtain information about the CodeQL CLI bundle release
|
||||
* that is tagged by `version`.
|
||||
*
|
||||
* @returns The response from the GitHub API.
|
||||
*/
|
||||
async function getReleaseByVersion(version: string) {
|
||||
return getApiClient().rest.repos.getReleaseByTag({
|
||||
owner: "github",
|
||||
repo: "codeql-action",
|
||||
tag: version,
|
||||
});
|
||||
}
|
||||
|
||||
/** Uses `features` to determine the default CLI version. */
|
||||
async function getCliVersionFromFeatures(
|
||||
features: FeatureEnablement,
|
||||
@@ -419,7 +393,8 @@ async function getCliVersionFromFeatures(
|
||||
* @returns Returns the download URL and version of the proxy package we plan to use.
|
||||
*/
|
||||
export async function getDownloadUrl(
|
||||
action: ActionState<["Base", "Logger", "FeatureFlags"]>,
|
||||
action: ActionState<["Base", "ReadOnlyEnv", "Logger", "FeatureFlags"]>,
|
||||
apiDetails: GitHubApiDetails,
|
||||
): Promise<{ url: string; version: string }> {
|
||||
// Default to linux64 if we don't recognise the platform+arch pair.
|
||||
// This maintains the behaviour we had before switching to `getBundlePlatform` here.
|
||||
@@ -448,37 +423,26 @@ export async function getDownloadUrl(
|
||||
};
|
||||
|
||||
// Try to retrieve information about the CLI bundle release identified by `versionInfo`.
|
||||
const cliRelease = await getReleaseByVersion(versionInfo.tagName);
|
||||
const proxyAssetUrl = await getCodeQLAssetDownloadURL(
|
||||
action,
|
||||
apiDetails,
|
||||
versionInfo.tagName,
|
||||
proxyPackage,
|
||||
"private registry proxy",
|
||||
);
|
||||
|
||||
// Search the release's assets to find the one we are looking for.
|
||||
for (const asset of cliRelease.data.assets) {
|
||||
if (asset.name === proxyPackage) {
|
||||
action.logger.info(
|
||||
`Found '${proxyPackage}' in release '${versionInfo.tagName}' at '${asset.url}'`,
|
||||
);
|
||||
return {
|
||||
url: asset.url,
|
||||
// The `update-job-proxy` doesn't have a version as such. Since we now bundle it
|
||||
// with CodeQL CLI bundle releases, we use the corresponding CLI version to
|
||||
// differentiate between (potentially) different versions of `update-job-proxy`.
|
||||
version: versionInfo.cliVersion,
|
||||
};
|
||||
}
|
||||
}
|
||||
return {
|
||||
url: proxyAssetUrl,
|
||||
// The `update-job-proxy` doesn't have a version as such. Since we now bundle it
|
||||
// with CodeQL CLI bundle releases, we use the corresponding CLI version to
|
||||
// differentiate between (potentially) different versions of `update-job-proxy`.
|
||||
version: versionInfo.cliVersion,
|
||||
};
|
||||
} catch (ex) {
|
||||
action.logger.warning(
|
||||
throw new Error(
|
||||
`Failed to retrieve information about the linked release: ${getErrorMessage(ex)}`,
|
||||
);
|
||||
}
|
||||
|
||||
// Fallback to the hard-coded URL.
|
||||
action.logger.info(
|
||||
`Did not find '${proxyPackage}' in the linked release, falling back to hard-coded version.`,
|
||||
);
|
||||
return {
|
||||
url: getFallbackUrl(proxyPackage),
|
||||
version: UPDATEJOB_PROXY_VERSION,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -497,9 +461,14 @@ export async function downloadProxy(
|
||||
try {
|
||||
// Download the proxy archive from `url`. We let `downloadTool` choose where
|
||||
// to store it. The path to the downloaded file will be returned if successful.
|
||||
return toolcache.downloadTool(url, /* dest: */ undefined, authorization, {
|
||||
accept: "application/octet-stream",
|
||||
});
|
||||
return await toolcache.downloadTool(
|
||||
url,
|
||||
/* dest: */ undefined,
|
||||
authorization,
|
||||
{
|
||||
accept: "application/octet-stream",
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
`Failed to download proxy archive from ${url}: ${getErrorMessage(error)}`,
|
||||
@@ -569,28 +538,48 @@ export function getProxyFilename() {
|
||||
* @returns The path to the proxy binary.
|
||||
*/
|
||||
export async function getProxyBinaryPath(
|
||||
action: ActionState<["Base", "Logger", "FeatureFlags"]>,
|
||||
action: ActionState<["Base", "ReadOnlyEnv", "Logger", "FeatureFlags"]>,
|
||||
apiDetails: GitHubApiDetails,
|
||||
): Promise<string> {
|
||||
const logger = action.logger;
|
||||
const proxyFileName = getProxyFilename();
|
||||
const proxyInfo = await getDownloadUrl(action);
|
||||
logger.startGroup("Setting up authentication proxy");
|
||||
|
||||
let proxyBin = toolcache.find(proxyFileName, proxyInfo.version);
|
||||
if (!proxyBin) {
|
||||
const apiDetails = getApiDetails();
|
||||
const authorization = getAuthorizationHeaderFor(
|
||||
logger,
|
||||
apiDetails,
|
||||
proxyInfo.url,
|
||||
);
|
||||
const temp = await downloadProxy(logger, proxyInfo.url, authorization);
|
||||
const extracted = await extractProxy(logger, temp);
|
||||
proxyBin = await cacheProxy(
|
||||
logger,
|
||||
extracted,
|
||||
proxyFileName,
|
||||
proxyInfo.version,
|
||||
try {
|
||||
const proxyFileName = getProxyFilename();
|
||||
const proxyInfo = await getDownloadUrl(action, apiDetails);
|
||||
|
||||
logger.info(
|
||||
`Using authentication proxy from CodeQL release ${proxyInfo.version}.`,
|
||||
);
|
||||
|
||||
let proxyDir = toolcache.find(proxyFileName, proxyInfo.version);
|
||||
|
||||
if (!proxyDir) {
|
||||
logger.info(
|
||||
`Authentication proxy is not in the toolcache. Will try to download it from '${proxyInfo.url}'.`,
|
||||
);
|
||||
|
||||
const authorization = getAuthorizationHeaderFor(
|
||||
logger,
|
||||
apiDetails,
|
||||
proxyInfo.url,
|
||||
);
|
||||
const temp = await downloadProxy(logger, proxyInfo.url, authorization);
|
||||
|
||||
logger.info(`Downloaded the authentication proxy asset to '${temp}'.`);
|
||||
|
||||
const extracted = await extractProxy(logger, temp);
|
||||
proxyDir = await cacheProxy(
|
||||
logger,
|
||||
extracted,
|
||||
proxyFileName,
|
||||
proxyInfo.version,
|
||||
);
|
||||
|
||||
logger.info(`Extracted the authentication proxy to '${proxyDir}'.`);
|
||||
}
|
||||
return path.join(proxyDir, proxyFileName);
|
||||
} finally {
|
||||
logger.endGroup();
|
||||
}
|
||||
return path.join(proxyBin, proxyFileName);
|
||||
}
|
||||
|
||||
@@ -163,6 +163,46 @@ export function setupTests(testFn: TestFn<any>) {
|
||||
});
|
||||
}
|
||||
|
||||
export interface AvaSinonAssertions {
|
||||
/**
|
||||
* Asserts that `stub` must have been called once with at least the `expected` arguments.
|
||||
*/
|
||||
onceWith: <TArgs extends readonly any[]>(
|
||||
stub: sinon.SinonStub<TArgs>,
|
||||
...expected: sinon.MatchPartialArguments<TArgs>
|
||||
) => boolean;
|
||||
}
|
||||
|
||||
/** Adds additional assertions for use with `sinon` to `t`. */
|
||||
export function addSinonAssertions(
|
||||
t: ExecutionContext<unknown>,
|
||||
): ExecutionContext<unknown> & AvaSinonAssertions {
|
||||
return {
|
||||
...t,
|
||||
onceWith: <TArgs extends readonly any[]>(
|
||||
stub: sinon.SinonStub<TArgs>,
|
||||
...expected: sinon.MatchPartialArguments<TArgs>
|
||||
) => {
|
||||
// Fail if the stub hasn't been called at all so that we can safely compare
|
||||
// the arguments of the first call in the else branch.
|
||||
if (stub.callCount === 0) {
|
||||
t.fail("The stub wasn't called.");
|
||||
} else {
|
||||
// Reduce the arguments of each to the same number that was provided,
|
||||
// so that extra arguments don't lead to a failure.
|
||||
const actual = stub.args.map<sinon.MatchPartialArguments<TArgs>>(
|
||||
(args: TArgs) =>
|
||||
args.slice(
|
||||
0,
|
||||
expected.length,
|
||||
) as sinon.MatchPartialArguments<TArgs>,
|
||||
);
|
||||
return t.deepEqual(actual, [expected]);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Declare a reusable test implementation, with better type safety than `test.macro`.
|
||||
*/
|
||||
|
||||
19
src/util.ts
19
src/util.ts
@@ -20,6 +20,8 @@ import {
|
||||
getRequiredEnvParam,
|
||||
isInTestMode,
|
||||
exportEnvVar,
|
||||
getEnv,
|
||||
type Env,
|
||||
} from "./environment";
|
||||
import * as json from "./json";
|
||||
import { Language } from "./languages";
|
||||
@@ -45,10 +47,13 @@ const BASE_DATABASE_OIDS_FILE_NAME = "base-database-oids.json";
|
||||
*/
|
||||
const BROKEN_VERSIONS = ["0.0.0-20211207"];
|
||||
|
||||
/** A string representing a GitHub instance. */
|
||||
export type InstanceURL = string;
|
||||
|
||||
/**
|
||||
* The URL for github.com.
|
||||
*/
|
||||
export const GITHUB_DOTCOM_URL = "https://github.com";
|
||||
export const GITHUB_DOTCOM_URL: InstanceURL = "https://github.com";
|
||||
|
||||
/**
|
||||
* Default name of the debugging artifact.
|
||||
@@ -599,12 +604,12 @@ export function assertNever(value: never): never {
|
||||
* Set some initial environment variables that we can set even without
|
||||
* knowing what version of CodeQL we're running.
|
||||
*/
|
||||
export function initializeEnvironment(version: string) {
|
||||
exportEnvVar(EnvVar.FEATURE_MULTI_LANGUAGE, "false");
|
||||
exportEnvVar(EnvVar.FEATURE_SANDWICH, "false");
|
||||
exportEnvVar(EnvVar.FEATURE_SARIF_COMBINE, "true");
|
||||
exportEnvVar(EnvVar.FEATURE_WILL_UPLOAD, "true");
|
||||
exportEnvVar(EnvVar.VERSION, version);
|
||||
export function initializeEnvironment(version: string, env: Env = getEnv()) {
|
||||
env.export(EnvVar.FEATURE_MULTI_LANGUAGE, "false");
|
||||
env.export(EnvVar.FEATURE_SANDWICH, "false");
|
||||
env.export(EnvVar.FEATURE_SARIF_COMBINE, "true");
|
||||
env.export(EnvVar.FEATURE_WILL_UPLOAD, "true");
|
||||
env.export(EnvVar.VERSION, version);
|
||||
}
|
||||
|
||||
export class HTTPError extends Error {
|
||||
|
||||
Reference in New Issue
Block a user