Merge pull request #1981 from github/aeisenberg/delete-analysis-after-upload
Delete analysis after uploading
This commit is contained in:
commit
10f05151c5
10 changed files with 170 additions and 16 deletions
1
.github/workflows/python312-windows.yml
vendored
1
.github/workflows/python312-windows.yml
vendored
|
|
@ -38,4 +38,5 @@ jobs:
|
|||
- name: Analyze
|
||||
uses: ./../action/analyze
|
||||
with:
|
||||
upload: false
|
||||
upload-database: false
|
||||
|
|
|
|||
65
lib/init-action-post-helper.js
generated
65
lib/init-action-post-helper.js
generated
|
|
@ -24,12 +24,13 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.run = exports.tryUploadSarifIfRunFailed = void 0;
|
||||
const core = __importStar(require("@actions/core"));
|
||||
const actionsUtil = __importStar(require("./actions-util"));
|
||||
const api_client_1 = require("./api-client");
|
||||
const codeql_1 = require("./codeql");
|
||||
const config_utils_1 = require("./config-utils");
|
||||
const environment_1 = require("./environment");
|
||||
const feature_flags_1 = require("./feature-flags");
|
||||
const repository_1 = require("./repository");
|
||||
const uploadLib = __importStar(require("./upload-lib"));
|
||||
const util_1 = require("./util");
|
||||
const workflow_1 = require("./workflow");
|
||||
|
|
@ -73,10 +74,12 @@ async function maybeUploadFailedSarif(config, repositoryNwo, features, logger) {
|
|||
// We call 'database export-diagnostics' to find any per-database diagnostics.
|
||||
await codeql.databaseExportDiagnostics(databasePath, sarifFile, category, config.tempDir, logger);
|
||||
}
|
||||
core.info(`Uploading failed SARIF file ${sarifFile}`);
|
||||
logger.info(`Uploading failed SARIF file ${sarifFile}`);
|
||||
const uploadResult = await uploadLib.uploadFromActions(sarifFile, checkoutPath, category, logger, { considerInvalidRequestUserError: false });
|
||||
await uploadLib.waitForProcessing(repositoryNwo, uploadResult.sarifID, logger, { isUnsuccessfulExecution: true });
|
||||
return uploadResult?.statusReport ?? {};
|
||||
return uploadResult
|
||||
? { ...uploadResult.statusReport, sarifID: uploadResult.sarifID }
|
||||
: {};
|
||||
}
|
||||
async function tryUploadSarifIfRunFailed(config, repositoryNwo, features, logger) {
|
||||
if (process.env[environment_1.EnvVar.ANALYZE_DID_COMPLETE_SUCCESSFULLY] !== "true") {
|
||||
|
|
@ -114,9 +117,12 @@ async function run(uploadDatabaseBundleDebugArtifact, uploadLogsDebugArtifact, p
|
|||
throw new Error("Expected to upload a failed SARIF file for this CodeQL code scanning run, " +
|
||||
`but the result was instead ${error}.`);
|
||||
}
|
||||
if (process.env["CODEQL_ACTION_EXPECT_UPLOAD_FAILED_SARIF"] === "true") {
|
||||
await removeUploadedSarif(uploadFailedSarifResult, logger);
|
||||
}
|
||||
// Upload appropriate Actions artifacts for debugging
|
||||
if (config.debugMode) {
|
||||
core.info("Debug mode is on. Uploading available database bundles and logs as Actions debugging artifacts...");
|
||||
logger.info("Debug mode is on. Uploading available database bundles and logs as Actions debugging artifacts...");
|
||||
await uploadDatabaseBundleDebugArtifact(config, logger);
|
||||
await uploadLogsDebugArtifact(config);
|
||||
await printDebugLogs(config);
|
||||
|
|
@ -124,4 +130,55 @@ async function run(uploadDatabaseBundleDebugArtifact, uploadLogsDebugArtifact, p
|
|||
return uploadFailedSarifResult;
|
||||
}
|
||||
exports.run = run;
|
||||
async function removeUploadedSarif(uploadFailedSarifResult, logger) {
|
||||
const sarifID = uploadFailedSarifResult.sarifID;
|
||||
if (sarifID) {
|
||||
logger.startGroup("Deleting failed SARIF upload");
|
||||
logger.info(`In test mode, therefore deleting the failed analysis to avoid impacting tool status for the Action repository. SARIF ID to delete: ${sarifID}.`);
|
||||
const client = (0, api_client_1.getApiClient)();
|
||||
try {
|
||||
const repositoryNwo = (0, repository_1.parseRepositoryNwo)((0, util_1.getRequiredEnvParam)("GITHUB_REPOSITORY"));
|
||||
// Wait to make sure the analysis is ready for download before requesting it.
|
||||
await (0, util_1.delay)(5000);
|
||||
// Get the analysis associated with the uploaded sarif
|
||||
const analysisInfo = await client.request("GET /repos/:owner/:repo/code-scanning/analyses?sarif_id=:sarif_id", {
|
||||
owner: repositoryNwo.owner,
|
||||
repo: repositoryNwo.repo,
|
||||
sarif_id: sarifID,
|
||||
});
|
||||
// Delete the analysis.
|
||||
if (analysisInfo.data.length === 1) {
|
||||
const analysis = analysisInfo.data[0];
|
||||
logger.info(`Analysis ID to delete: ${analysis.id}.`);
|
||||
try {
|
||||
await client.request("DELETE /repos/:owner/:repo/code-scanning/analyses/:analysis_id?confirm_delete", {
|
||||
owner: repositoryNwo.owner,
|
||||
repo: repositoryNwo.repo,
|
||||
analysis_id: analysis.id,
|
||||
});
|
||||
logger.info(`Analysis deleted.`);
|
||||
}
|
||||
catch (e) {
|
||||
const origMessage = (0, util_1.getErrorMessage)(e);
|
||||
const newMessage = origMessage.includes("No analysis found for analysis ID")
|
||||
? `Analysis ${analysis.id} does not exist. It was likely already deleted.`
|
||||
: origMessage;
|
||||
throw new Error(newMessage);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new Error(`Expected to find exactly one analysis with sarif_id ${sarifID}. Found ${analysisInfo.data.length}.`);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error(`Failed to delete uploaded SARIF analysis. Reason: ${(0, util_1.getErrorMessage)(e)}`);
|
||||
}
|
||||
finally {
|
||||
logger.endGroup();
|
||||
}
|
||||
}
|
||||
else {
|
||||
logger.warning("Could not delete the uploaded SARIF analysis because a SARIF ID wasn't provided by the API when uploading the SARIF file.");
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=init-action-post-helper.js.map
|
||||
File diff suppressed because one or more lines are too long
1
lib/init-action-post-helper.test.js
generated
1
lib/init-action-post-helper.test.js
generated
|
|
@ -341,6 +341,7 @@ async function testFailedSarifUpload(t, actionsWorkflow, { category, databaseExi
|
|||
const result = await initActionPostHelper.tryUploadSarifIfRunFailed(config, (0, repository_1.parseRepositoryNwo)("github/codeql-action"), (0, testing_utils_1.createFeatures)(features), (0, logging_1.getRunnerLogger)(true));
|
||||
if (expectUpload) {
|
||||
t.deepEqual(result, {
|
||||
sarifID: "42",
|
||||
raw_upload_size_bytes: 20,
|
||||
zipped_upload_size_bytes: 10,
|
||||
});
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
9
lib/util.js
generated
9
lib/util.js
generated
|
|
@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.checkDiskUsage = exports.prettyPrintPack = exports.wrapError = exports.fixInvalidNotificationsInFile = exports.fixInvalidNotifications = exports.parseMatrixInput = exports.isHostedRunner = exports.checkForTimeout = exports.withTimeout = exports.tryGetFolderBytes = exports.listFolder = exports.doesDirectoryExist = exports.isInTestMode = exports.supportExpectDiscardedCache = exports.isGoodVersion = exports.delay = exports.bundleDb = exports.codeQlVersionAbove = exports.getCachedCodeQlVersion = exports.cacheCodeQlVersion = exports.isHTTPError = exports.UserError = exports.HTTPError = exports.getRequiredEnvParam = exports.initializeEnvironment = exports.assertNever = exports.apiVersionInRange = exports.DisallowedAPIVersionReason = exports.checkGitHubVersionInRange = exports.GitHubVariant = exports.parseGitHubUrl = exports.getCodeQLDatabasePath = exports.getThreadsFlag = exports.getThreadsFlagValue = exports.getAddSnippetsFlag = exports.getMemoryFlag = exports.getMemoryFlagValue = exports.getMemoryFlagValueForPlatform = exports.withTmpDir = exports.getToolNames = exports.getExtraOptionsEnvParam = exports.DEFAULT_DEBUG_DATABASE_NAME = exports.DEFAULT_DEBUG_ARTIFACT_NAME = exports.GITHUB_DOTCOM_URL = void 0;
|
||||
exports.checkDiskUsage = exports.prettyPrintPack = exports.getErrorMessage = exports.wrapError = exports.fixInvalidNotificationsInFile = exports.fixInvalidNotifications = exports.parseMatrixInput = exports.isHostedRunner = exports.checkForTimeout = exports.withTimeout = exports.tryGetFolderBytes = exports.listFolder = exports.doesDirectoryExist = exports.isInTestMode = exports.supportExpectDiscardedCache = exports.isGoodVersion = exports.delay = exports.bundleDb = exports.codeQlVersionAbove = exports.getCachedCodeQlVersion = exports.cacheCodeQlVersion = exports.isHTTPError = exports.UserError = exports.HTTPError = exports.getRequiredEnvParam = exports.initializeEnvironment = exports.assertNever = exports.apiVersionInRange = exports.DisallowedAPIVersionReason = exports.checkGitHubVersionInRange = exports.GitHubVariant = exports.parseGitHubUrl = exports.getCodeQLDatabasePath = exports.getThreadsFlag = exports.getThreadsFlagValue = exports.getAddSnippetsFlag = exports.getMemoryFlag = exports.getMemoryFlagValue = exports.getMemoryFlagValueForPlatform = exports.withTmpDir = exports.getToolNames = exports.getExtraOptionsEnvParam = exports.DEFAULT_DEBUG_DATABASE_NAME = exports.DEFAULT_DEBUG_ARTIFACT_NAME = exports.GITHUB_DOTCOM_URL = void 0;
|
||||
const fs = __importStar(require("fs"));
|
||||
const os = __importStar(require("os"));
|
||||
const path = __importStar(require("path"));
|
||||
|
|
@ -465,7 +465,8 @@ exports.bundleDb = bundleDb;
|
|||
* @param opts options
|
||||
* @param opts.allowProcessExit if true, the timer will not prevent the process from exiting
|
||||
*/
|
||||
async function delay(milliseconds, { allowProcessExit }) {
|
||||
async function delay(milliseconds, opts) {
|
||||
const { allowProcessExit } = opts || {};
|
||||
return new Promise((resolve) => {
|
||||
const timer = setTimeout(resolve, milliseconds);
|
||||
if (allowProcessExit) {
|
||||
|
|
@ -719,6 +720,10 @@ function wrapError(error) {
|
|||
return error instanceof Error ? error : new Error(String(error));
|
||||
}
|
||||
exports.wrapError = wrapError;
|
||||
function getErrorMessage(error) {
|
||||
return error instanceof Error ? error.toString() : String(error);
|
||||
}
|
||||
exports.getErrorMessage = getErrorMessage;
|
||||
function prettyPrintPack(pack) {
|
||||
return `${pack.name}${pack.version ? `@${pack.version}` : ""}${pack.path ? `:${pack.path}` : ""}`;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -391,6 +391,7 @@ async function testFailedSarifUpload(
|
|||
);
|
||||
if (expectUpload) {
|
||||
t.deepEqual(result, {
|
||||
sarifID: "42",
|
||||
raw_upload_size_bytes: 20,
|
||||
zipped_upload_size_bytes: 10,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
import * as core from "@actions/core";
|
||||
|
||||
import * as actionsUtil from "./actions-util";
|
||||
import { getApiClient } from "./api-client";
|
||||
import { CODEQL_VERSION_EXPORT_FAILED_SARIF, getCodeQL } from "./codeql";
|
||||
import { Config, getConfig } from "./config-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import { Feature, FeatureEnablement } from "./feature-flags";
|
||||
import { Logger } from "./logging";
|
||||
import { RepositoryNwo } from "./repository";
|
||||
import { RepositoryNwo, parseRepositoryNwo } from "./repository";
|
||||
import * as uploadLib from "./upload-lib";
|
||||
import {
|
||||
codeQlVersionAbove,
|
||||
delay,
|
||||
getErrorMessage,
|
||||
getRequiredEnvParam,
|
||||
isInTestMode,
|
||||
parseMatrixInput,
|
||||
|
|
@ -29,6 +30,9 @@ export interface UploadFailedSarifResult extends uploadLib.UploadStatusReport {
|
|||
upload_failed_run_stack_trace?: string;
|
||||
/** Reason why we did not upload a SARIF payload with `executionSuccessful: false`. */
|
||||
upload_failed_run_skipped_because?: string;
|
||||
|
||||
/** The internal ID of SARIF analysis. */
|
||||
sarifID?: string;
|
||||
}
|
||||
|
||||
function createFailedUploadFailedSarifResult(
|
||||
|
|
@ -93,7 +97,7 @@ async function maybeUploadFailedSarif(
|
|||
);
|
||||
}
|
||||
|
||||
core.info(`Uploading failed SARIF file ${sarifFile}`);
|
||||
logger.info(`Uploading failed SARIF file ${sarifFile}`);
|
||||
const uploadResult = await uploadLib.uploadFromActions(
|
||||
sarifFile,
|
||||
checkoutPath,
|
||||
|
|
@ -107,7 +111,9 @@ async function maybeUploadFailedSarif(
|
|||
logger,
|
||||
{ isUnsuccessfulExecution: true },
|
||||
);
|
||||
return uploadResult?.statusReport ?? {};
|
||||
return uploadResult
|
||||
? { ...uploadResult.statusReport, sarifID: uploadResult.sarifID }
|
||||
: {};
|
||||
}
|
||||
|
||||
export async function tryUploadSarifIfRunFailed(
|
||||
|
|
@ -180,9 +186,13 @@ export async function run(
|
|||
);
|
||||
}
|
||||
|
||||
if (process.env["CODEQL_ACTION_EXPECT_UPLOAD_FAILED_SARIF"] === "true") {
|
||||
await removeUploadedSarif(uploadFailedSarifResult, logger);
|
||||
}
|
||||
|
||||
// Upload appropriate Actions artifacts for debugging
|
||||
if (config.debugMode) {
|
||||
core.info(
|
||||
logger.info(
|
||||
"Debug mode is on. Uploading available database bundles and logs as Actions debugging artifacts...",
|
||||
);
|
||||
await uploadDatabaseBundleDebugArtifact(config, logger);
|
||||
|
|
@ -193,3 +203,77 @@ export async function run(
|
|||
|
||||
return uploadFailedSarifResult;
|
||||
}
|
||||
|
||||
async function removeUploadedSarif(
|
||||
uploadFailedSarifResult: UploadFailedSarifResult,
|
||||
logger: Logger,
|
||||
) {
|
||||
const sarifID = uploadFailedSarifResult.sarifID;
|
||||
if (sarifID) {
|
||||
logger.startGroup("Deleting failed SARIF upload");
|
||||
logger.info(
|
||||
`In test mode, therefore deleting the failed analysis to avoid impacting tool status for the Action repository. SARIF ID to delete: ${sarifID}.`,
|
||||
);
|
||||
const client = getApiClient();
|
||||
|
||||
try {
|
||||
const repositoryNwo = parseRepositoryNwo(
|
||||
getRequiredEnvParam("GITHUB_REPOSITORY"),
|
||||
);
|
||||
|
||||
// Wait to make sure the analysis is ready for download before requesting it.
|
||||
await delay(5000);
|
||||
|
||||
// Get the analysis associated with the uploaded sarif
|
||||
const analysisInfo = await client.request(
|
||||
"GET /repos/:owner/:repo/code-scanning/analyses?sarif_id=:sarif_id",
|
||||
{
|
||||
owner: repositoryNwo.owner,
|
||||
repo: repositoryNwo.repo,
|
||||
sarif_id: sarifID,
|
||||
},
|
||||
);
|
||||
|
||||
// Delete the analysis.
|
||||
if (analysisInfo.data.length === 1) {
|
||||
const analysis = analysisInfo.data[0];
|
||||
logger.info(`Analysis ID to delete: ${analysis.id}.`);
|
||||
try {
|
||||
await client.request(
|
||||
"DELETE /repos/:owner/:repo/code-scanning/analyses/:analysis_id?confirm_delete",
|
||||
{
|
||||
owner: repositoryNwo.owner,
|
||||
repo: repositoryNwo.repo,
|
||||
analysis_id: analysis.id,
|
||||
},
|
||||
);
|
||||
logger.info(`Analysis deleted.`);
|
||||
} catch (e) {
|
||||
const origMessage = getErrorMessage(e);
|
||||
const newMessage = origMessage.includes(
|
||||
"No analysis found for analysis ID",
|
||||
)
|
||||
? `Analysis ${analysis.id} does not exist. It was likely already deleted.`
|
||||
: origMessage;
|
||||
throw new Error(newMessage);
|
||||
}
|
||||
} else {
|
||||
throw new Error(
|
||||
`Expected to find exactly one analysis with sarif_id ${sarifID}. Found ${analysisInfo.data.length}.`,
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Failed to delete uploaded SARIF analysis. Reason: ${getErrorMessage(
|
||||
e,
|
||||
)}`,
|
||||
);
|
||||
} finally {
|
||||
logger.endGroup();
|
||||
}
|
||||
} else {
|
||||
logger.warning(
|
||||
"Could not delete the uploaded SARIF analysis because a SARIF ID wasn't provided by the API when uploading the SARIF file.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -624,8 +624,9 @@ export async function bundleDb(
|
|||
*/
|
||||
export async function delay(
|
||||
milliseconds: number,
|
||||
{ allowProcessExit }: { allowProcessExit: boolean },
|
||||
opts?: { allowProcessExit: boolean },
|
||||
) {
|
||||
const { allowProcessExit } = opts || {};
|
||||
return new Promise((resolve) => {
|
||||
const timer = setTimeout(resolve, milliseconds);
|
||||
if (allowProcessExit) {
|
||||
|
|
@ -909,6 +910,10 @@ export function wrapError(error: unknown): Error {
|
|||
return error instanceof Error ? error : new Error(String(error));
|
||||
}
|
||||
|
||||
export function getErrorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.toString() : String(error);
|
||||
}
|
||||
|
||||
export function prettyPrintPack(pack: Pack) {
|
||||
return `${pack.name}${pack.version ? `@${pack.version}` : ""}${
|
||||
pack.path ? `:${pack.path}` : ""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue