mirror of
https://github.com/github/codeql-action.git
synced 2026-04-29 02:18:47 +00:00
Add StartProxyError for status-report-safe errors, and use for proxy download
This commit is contained in:
@@ -12,6 +12,7 @@ import { getActionsLogger, Logger } from "./logging";
|
||||
import {
|
||||
Credential,
|
||||
credentialToStr,
|
||||
downloadProxy,
|
||||
getCredentials,
|
||||
getDownloadUrl,
|
||||
parseLanguage,
|
||||
@@ -238,14 +239,7 @@ async function getProxyBinaryPath(logger: Logger): Promise<string> {
|
||||
apiDetails,
|
||||
proxyInfo.url,
|
||||
);
|
||||
const temp = await toolcache.downloadTool(
|
||||
proxyInfo.url,
|
||||
undefined,
|
||||
authorization,
|
||||
{
|
||||
accept: "application/octet-stream",
|
||||
},
|
||||
);
|
||||
const temp = await downloadProxy(logger, proxyInfo.url, authorization);
|
||||
const extracted = await toolcache.extractTar(temp);
|
||||
proxyBin = await toolcache.cacheDir(
|
||||
extracted,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import * as toolcache from "@actions/tool-cache";
|
||||
import test from "ava";
|
||||
import sinon from "sinon";
|
||||
|
||||
@@ -318,3 +319,47 @@ test("credentialToStr - hides passwords/tokens", (t) => {
|
||||
.includes(secret),
|
||||
);
|
||||
});
|
||||
|
||||
test("getSafeErrorMessage - returns actual message for `StartProxyError`", (t) => {
|
||||
const error = new startProxyExports.StartProxyError(
|
||||
startProxyExports.StartProxyErrorType.DownloadFailed,
|
||||
);
|
||||
t.is(startProxyExports.getSafeErrorMessage(error), error.message);
|
||||
});
|
||||
|
||||
test("getSafeErrorMessage - does not return message for arbitrary errors", (t) => {
|
||||
const error = new Error(startProxyExports.StartProxyErrorType.DownloadFailed);
|
||||
|
||||
const message = startProxyExports.getSafeErrorMessage(error);
|
||||
|
||||
t.not(message, error.message);
|
||||
t.assert(message.startsWith("Error from start-proxy Action omitted"));
|
||||
t.assert(message.includes(typeof error));
|
||||
});
|
||||
|
||||
test("downloadProxy - returns file path on success", async (t) => {
|
||||
const loggedMessages = [];
|
||||
const logger = getRecordingLogger(loggedMessages);
|
||||
const testPath = "/some/path";
|
||||
sinon.stub(toolcache, "downloadTool").resolves(testPath);
|
||||
|
||||
const result = await startProxyExports.downloadProxy(
|
||||
logger,
|
||||
"url",
|
||||
undefined,
|
||||
);
|
||||
t.is(result, testPath);
|
||||
});
|
||||
|
||||
test("downloadProxy - wraps errors on failure", async (t) => {
|
||||
const loggedMessages = [];
|
||||
const logger = getRecordingLogger(loggedMessages);
|
||||
sinon.stub(toolcache, "downloadTool").throws();
|
||||
|
||||
await t.throwsAsync(
|
||||
startProxyExports.downloadProxy(logger, "url", undefined),
|
||||
{
|
||||
instanceOf: startProxyExports.StartProxyError,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
+66
-1
@@ -1,4 +1,5 @@
|
||||
import * as core from "@actions/core";
|
||||
import * as toolcache from "@actions/tool-cache";
|
||||
|
||||
import { getApiClient } from "./api-client";
|
||||
import * as artifactScanner from "./artifact-scanner";
|
||||
@@ -16,6 +17,26 @@ import {
|
||||
import * as util from "./util";
|
||||
import { ConfigurationError, getErrorMessage, isDefined } from "./util";
|
||||
|
||||
/**
|
||||
* Enumerates specific error types, along with suitable error messages, for errors
|
||||
* that we want to track in status reports.
|
||||
*/
|
||||
export enum StartProxyErrorType {
|
||||
DownloadFailed = "Failed to download proxy archive.",
|
||||
}
|
||||
|
||||
/**
|
||||
* We want to avoid accidentally leaking secrets that may be contained in exception
|
||||
* messages in the `start-proxy` action. Consequently, we don't report the messages
|
||||
* of arbitrary exceptions. This type of error ensures that the message is one from
|
||||
* `StartProxyErrorType` and therefore safe to include in a status report.
|
||||
*/
|
||||
export class StartProxyError extends Error {
|
||||
constructor(errorType: StartProxyErrorType) {
|
||||
super(errorType);
|
||||
}
|
||||
}
|
||||
|
||||
interface StartProxyStatus extends StatusReportBase {
|
||||
// A comma-separated list of registry types which are configured for CodeQL.
|
||||
// This only includes registry types we support, not all that are configured.
|
||||
@@ -53,6 +74,23 @@ export async function sendSuccessStatusReport(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an error message for `error` that can safely be reported in a status report,
|
||||
* i.e. that does not contain sensitive information.
|
||||
*
|
||||
* @param error The error for which to get an error message.
|
||||
*/
|
||||
export function getSafeErrorMessage(error: Error): string {
|
||||
// If the error is a `StartProxyError`, the constructor ensures that the
|
||||
// message comes from `StartProxyErrorType`.
|
||||
if (error instanceof StartProxyError) {
|
||||
return error.message;
|
||||
}
|
||||
|
||||
// Otherwise, omit the actual error message.
|
||||
return `Error from start-proxy Action omitted (${typeof error}).`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a status report for the `start-proxy` action indicating a failure.
|
||||
*
|
||||
@@ -70,6 +108,8 @@ export async function sendFailedStatusReport(
|
||||
const error = util.wrapError(unwrappedError);
|
||||
core.setFailed(`start-proxy action failed: ${error.message}`);
|
||||
|
||||
const statusReportMessage = getSafeErrorMessage(error);
|
||||
|
||||
// We skip sending the error message and stack trace here to avoid the possibility
|
||||
// of leaking any sensitive information into the telemetry.
|
||||
const errorStatusReportBase = await createStatusReportBase(
|
||||
@@ -81,7 +121,7 @@ export async function sendFailedStatusReport(
|
||||
},
|
||||
await util.checkDiskUsage(logger),
|
||||
logger,
|
||||
"Error from start-proxy Action omitted",
|
||||
statusReportMessage,
|
||||
);
|
||||
if (errorStatusReportBase !== undefined) {
|
||||
await sendStatusReport(errorStatusReportBase);
|
||||
@@ -369,3 +409,28 @@ export function credentialToStr(c: Credential): string {
|
||||
c.username
|
||||
}; Password: ${c.password !== undefined}; Token: ${c.token !== undefined}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to download a file from `url` into the toolcache.
|
||||
*
|
||||
* @param logger THe logger to use.
|
||||
* @param url The URL to download the proxy binary from.
|
||||
* @param authorization The authorization information to use.
|
||||
* @returns If successful, the path to the downloaded file.
|
||||
*/
|
||||
export async function downloadProxy(
|
||||
logger: Logger,
|
||||
url: string,
|
||||
authorization: string | undefined,
|
||||
) {
|
||||
try {
|
||||
return toolcache.downloadTool(url, undefined, authorization, {
|
||||
accept: "application/octet-stream",
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
`Failed to download proxy archive from ${url}: ${getErrorMessage(error)}`,
|
||||
);
|
||||
throw new StartProxyError(StartProxyErrorType.DownloadFailed);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user