mirror of
https://github.com/github/codeql-action.git
synced 2026-05-07 22:30:44 +00:00
Upload per-database failed SARIFs, if applicable
This commit is contained in:
@@ -132,7 +132,7 @@ test("doesn't upload failed SARIF for workflow with upload: false", async (t) =>
|
||||
const result = await testFailedSarifUpload(t, actionsWorkflow, {
|
||||
expectUpload: false,
|
||||
});
|
||||
t.is(result.upload_failed_run_skipped_because, "SARIF upload is disabled");
|
||||
t.is(result[0].upload_failed_run_skipped_because, "SARIF upload is disabled");
|
||||
});
|
||||
|
||||
test("uploading failed SARIF run succeeds when workflow uses an input with a matrix var", async (t) => {
|
||||
@@ -187,7 +187,7 @@ test("uploading failed SARIF run fails when workflow uses a complex upload input
|
||||
expectUpload: false,
|
||||
});
|
||||
t.is(
|
||||
result.upload_failed_run_error,
|
||||
result[0].upload_failed_run_error,
|
||||
"Could not get upload input to github/codeql-action/analyze since it contained an " +
|
||||
"unrecognized dynamic value."
|
||||
);
|
||||
@@ -204,11 +204,11 @@ test("uploading failed SARIF run fails when workflow does not reference github/c
|
||||
expectUpload: false,
|
||||
});
|
||||
t.is(
|
||||
result.upload_failed_run_error,
|
||||
result[0].upload_failed_run_error,
|
||||
"Could not get upload input to github/codeql-action/analyze since the analyze job does not " +
|
||||
"call github/codeql-action/analyze."
|
||||
);
|
||||
t.truthy(result.upload_failed_run_stack_trace);
|
||||
t.truthy(result[0].upload_failed_run_stack_trace);
|
||||
});
|
||||
|
||||
function createTestWorkflow(
|
||||
@@ -246,7 +246,7 @@ async function testFailedSarifUpload(
|
||||
expectUpload?: boolean;
|
||||
matrix?: { [key: string]: string };
|
||||
} = {}
|
||||
): Promise<initActionPostHelper.UploadFailedSarifResult> {
|
||||
): Promise<initActionPostHelper.UploadFailedSarifResult[]> {
|
||||
const config = {
|
||||
codeQLCmd: "codeql",
|
||||
debugMode: true,
|
||||
@@ -282,10 +282,12 @@ async function testFailedSarifUpload(
|
||||
getRunnerLogger(true)
|
||||
);
|
||||
if (expectUpload) {
|
||||
t.deepEqual(result, {
|
||||
raw_upload_size_bytes: 20,
|
||||
zipped_upload_size_bytes: 10,
|
||||
});
|
||||
t.deepEqual(result, [
|
||||
{
|
||||
raw_upload_size_bytes: 20,
|
||||
zipped_upload_size_bytes: 10,
|
||||
},
|
||||
]);
|
||||
}
|
||||
if (expectUpload) {
|
||||
t.true(
|
||||
|
||||
@@ -6,9 +6,17 @@ import { Config, getConfig } from "./config-utils";
|
||||
import { Feature, FeatureEnablement } from "./feature-flags";
|
||||
import { Logger } from "./logging";
|
||||
import { RepositoryNwo } from "./repository";
|
||||
import { CODEQL_ACTION_ANALYZE_DID_COMPLETE_SUCCESSFULLY } from "./shared-environment";
|
||||
import {
|
||||
CODEQL_ACTION_ANALYZE_DID_COMPLETE_SUCCESSFULLY,
|
||||
CODEQL_ACTION_IS_DATABASE_CLUSTER,
|
||||
} from "./shared-environment";
|
||||
import * as uploadLib from "./upload-lib";
|
||||
import { getRequiredEnvParam, isInTestMode, parseMatrixInput } from "./util";
|
||||
import {
|
||||
getExistingDatabasePaths,
|
||||
getRequiredEnvParam,
|
||||
isInTestMode,
|
||||
parseMatrixInput,
|
||||
} from "./util";
|
||||
import {
|
||||
getCategoryInputOrThrow,
|
||||
getCheckoutPathInputOrThrow,
|
||||
@@ -45,9 +53,9 @@ async function maybeUploadFailedSarif(
|
||||
repositoryNwo: RepositoryNwo,
|
||||
featureEnablement: FeatureEnablement,
|
||||
logger: Logger
|
||||
): Promise<UploadFailedSarifResult> {
|
||||
): Promise<UploadFailedSarifResult[]> {
|
||||
if (!config.codeQLCmd) {
|
||||
return { upload_failed_run_skipped_because: "CodeQL command not found" };
|
||||
return [{ upload_failed_run_skipped_because: "CodeQL command not found" }];
|
||||
}
|
||||
const codeql = await getCodeQL(config.codeQLCmd);
|
||||
if (
|
||||
@@ -56,7 +64,7 @@ async function maybeUploadFailedSarif(
|
||||
codeql
|
||||
))
|
||||
) {
|
||||
return { upload_failed_run_skipped_because: "Feature disabled" };
|
||||
return [{ upload_failed_run_skipped_because: "Feature disabled" }];
|
||||
}
|
||||
const workflow = await getWorkflow();
|
||||
const jobName = getRequiredEnvParam("GITHUB_JOB");
|
||||
@@ -65,28 +73,62 @@ async function maybeUploadFailedSarif(
|
||||
getUploadInputOrThrow(workflow, jobName, matrix) !== "true" ||
|
||||
isInTestMode()
|
||||
) {
|
||||
return { upload_failed_run_skipped_because: "SARIF upload is disabled" };
|
||||
return [{ upload_failed_run_skipped_because: "SARIF upload is disabled" }];
|
||||
}
|
||||
const category = getCategoryInputOrThrow(workflow, jobName, matrix);
|
||||
const checkoutPath = getCheckoutPathInputOrThrow(workflow, jobName, matrix);
|
||||
|
||||
const sarifFile = "../codeql-failed-run.sarif";
|
||||
await codeql.diagnosticsExport(sarifFile, category);
|
||||
|
||||
core.info(`Uploading failed SARIF file ${sarifFile}`);
|
||||
const uploadResult = await uploadLib.uploadFromActions(
|
||||
sarifFile,
|
||||
checkoutPath,
|
||||
category,
|
||||
logger
|
||||
);
|
||||
await uploadLib.waitForProcessing(
|
||||
repositoryNwo,
|
||||
uploadResult.sarifID,
|
||||
logger,
|
||||
{ isUnsuccessfulExecution: true }
|
||||
);
|
||||
return uploadResult?.statusReport ?? {};
|
||||
const existingDatabasePaths = getExistingDatabasePaths(config);
|
||||
if (existingDatabasePaths.length === 0) {
|
||||
const sarifFile = "../codeql-failed-run.sarif";
|
||||
await codeql.diagnosticsExport(sarifFile, category);
|
||||
core.info(`Uploading failed SARIF file ${sarifFile}`);
|
||||
const uploadResult = await uploadLib.uploadFromActions(
|
||||
sarifFile,
|
||||
checkoutPath,
|
||||
category,
|
||||
logger
|
||||
);
|
||||
await uploadLib.waitForProcessing(
|
||||
repositoryNwo,
|
||||
uploadResult.sarifID,
|
||||
logger,
|
||||
{ isUnsuccessfulExecution: true }
|
||||
);
|
||||
return [uploadResult?.statusReport ?? {}];
|
||||
} else {
|
||||
const uploadStatusReports: uploadLib.UploadStatusReport[] = [];
|
||||
const maybeIsDatabaseCluster =
|
||||
process.env[CODEQL_ACTION_IS_DATABASE_CLUSTER];
|
||||
// If we have already created database(s), then we call database diagnostic export.
|
||||
existingDatabasePaths.map(async (databasePath) => {
|
||||
const databaseSarifFile = `../codeql-failed-run-${existingDatabasePaths}.sarif`;
|
||||
await codeql.databaseExportDiagnostics(
|
||||
databasePath,
|
||||
maybeIsDatabaseCluster === undefined ||
|
||||
maybeIsDatabaseCluster.length === 0
|
||||
? false
|
||||
: true,
|
||||
databaseSarifFile,
|
||||
category
|
||||
);
|
||||
core.info(`Uploading failed SARIF file ${databaseSarifFile}`);
|
||||
const uploadResult = await uploadLib.uploadFromActions(
|
||||
databaseSarifFile,
|
||||
checkoutPath,
|
||||
category,
|
||||
logger
|
||||
);
|
||||
await uploadLib.waitForProcessing(
|
||||
repositoryNwo,
|
||||
uploadResult.sarifID,
|
||||
logger,
|
||||
{ isUnsuccessfulExecution: true }
|
||||
);
|
||||
uploadStatusReports.push(uploadResult.statusReport);
|
||||
});
|
||||
return uploadStatusReports ?? [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function tryUploadSarifIfRunFailed(
|
||||
@@ -94,7 +136,7 @@ export async function tryUploadSarifIfRunFailed(
|
||||
repositoryNwo: RepositoryNwo,
|
||||
featureEnablement: FeatureEnablement,
|
||||
logger: Logger
|
||||
): Promise<UploadFailedSarifResult> {
|
||||
): Promise<UploadFailedSarifResult[]> {
|
||||
if (process.env[CODEQL_ACTION_ANALYZE_DID_COMPLETE_SUCCESSFULLY] !== "true") {
|
||||
try {
|
||||
return await maybeUploadFailedSarif(
|
||||
@@ -107,13 +149,15 @@ export async function tryUploadSarifIfRunFailed(
|
||||
logger.debug(
|
||||
`Failed to upload a SARIF file for this failed CodeQL code scanning run. ${e}`
|
||||
);
|
||||
return createFailedUploadFailedSarifResult(e);
|
||||
return [createFailedUploadFailedSarifResult(e)];
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
upload_failed_run_skipped_because:
|
||||
"Analyze Action completed successfully",
|
||||
};
|
||||
return [
|
||||
{
|
||||
upload_failed_run_skipped_because:
|
||||
"Analyze Action completed successfully",
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,27 +177,29 @@ export async function run(
|
||||
return;
|
||||
}
|
||||
|
||||
const uploadFailedSarifResult = await tryUploadSarifIfRunFailed(
|
||||
const uploadFailedSarifResults = await tryUploadSarifIfRunFailed(
|
||||
config,
|
||||
repositoryNwo,
|
||||
featureEnablement,
|
||||
logger
|
||||
);
|
||||
if (uploadFailedSarifResult.upload_failed_run_skipped_because) {
|
||||
|
||||
// If the upload was skipped, it is the only item in the results array.
|
||||
if (uploadFailedSarifResults[0].upload_failed_run_skipped_because) {
|
||||
logger.debug(
|
||||
"Won't upload a failed SARIF file for this CodeQL code scanning run because: " +
|
||||
`${uploadFailedSarifResult.upload_failed_run_skipped_because}.`
|
||||
`${uploadFailedSarifResults[0].upload_failed_run_skipped_because}.`
|
||||
);
|
||||
}
|
||||
// Throw an error if in integration tests, we expected to upload a SARIF file for a failed run
|
||||
// but we didn't upload anything.
|
||||
if (
|
||||
process.env["CODEQL_ACTION_EXPECT_UPLOAD_FAILED_SARIF"] === "true" &&
|
||||
!uploadFailedSarifResult.raw_upload_size_bytes
|
||||
!uploadFailedSarifResults[0].raw_upload_size_bytes
|
||||
) {
|
||||
throw new Error(
|
||||
"Expected to upload a failed SARIF file for this CodeQL code scanning run, " +
|
||||
`but the result was instead ${uploadFailedSarifResult}.`
|
||||
`but the result was instead ${uploadFailedSarifResults}.`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -168,5 +214,5 @@ export async function run(
|
||||
await printDebugLogs(config);
|
||||
}
|
||||
|
||||
return uploadFailedSarifResult;
|
||||
return uploadFailedSarifResults;
|
||||
}
|
||||
|
||||
+10
-8
@@ -28,8 +28,8 @@ interface InitPostStatusReport
|
||||
|
||||
async function runWrapper() {
|
||||
const startedAt = new Date();
|
||||
let uploadFailedSarifResult:
|
||||
| initActionPostHelper.UploadFailedSarifResult
|
||||
let uploadFailedSarifResults:
|
||||
| initActionPostHelper.UploadFailedSarifResult[]
|
||||
| undefined;
|
||||
try {
|
||||
const logger = getActionsLogger();
|
||||
@@ -46,7 +46,7 @@ async function runWrapper() {
|
||||
logger
|
||||
);
|
||||
|
||||
uploadFailedSarifResult = await initActionPostHelper.run(
|
||||
uploadFailedSarifResults = await initActionPostHelper.run(
|
||||
debugArtifacts.uploadDatabaseBundleDebugArtifact,
|
||||
debugArtifacts.uploadLogsDebugArtifact,
|
||||
printDebugLogs,
|
||||
@@ -74,11 +74,13 @@ async function runWrapper() {
|
||||
"success",
|
||||
startedAt
|
||||
);
|
||||
const statusReport: InitPostStatusReport = {
|
||||
...statusReportBase,
|
||||
...uploadFailedSarifResult,
|
||||
};
|
||||
await sendStatusReport(statusReport);
|
||||
for (const result of uploadFailedSarifResults ?? []) {
|
||||
const statusReport: InitPostStatusReport = {
|
||||
...statusReportBase,
|
||||
...result,
|
||||
};
|
||||
await sendStatusReport(statusReport);
|
||||
}
|
||||
}
|
||||
|
||||
void runWrapper();
|
||||
|
||||
@@ -252,6 +252,15 @@ export function getCodeQLDatabasePath(config: Config, language: Language) {
|
||||
return path.resolve(config.dbLocation, language);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the paths of all CodeQL databases that currently exist.
|
||||
*/
|
||||
export function getExistingDatabasePaths(config: Config): string[] {
|
||||
return config.languages
|
||||
.map((language) => getCodeQLDatabasePath(config, language))
|
||||
.filter((databasePath) => fs.existsSync(databasePath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses user input of a github.com or GHES URL to a canonical form.
|
||||
* Removes any API prefix or suffix if one is present.
|
||||
|
||||
Reference in New Issue
Block a user