mirror of
https://github.com/github/codeql-action.git
synced 2026-05-08 06:40:19 +00:00
Add database export-diagnostics command
This commit is contained in:
+1
-5
@@ -1,7 +1,6 @@
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
import * as core from "@actions/core";
|
||||
import * as toolrunner from "@actions/exec/lib/toolrunner";
|
||||
import * as yaml from "js-yaml";
|
||||
|
||||
@@ -14,7 +13,6 @@ import { ToolsSource } from "./init";
|
||||
import { isTracedLanguage, Language } from "./languages";
|
||||
import { Logger } from "./logging";
|
||||
import * as setupCodeql from "./setup-codeql";
|
||||
import { CODEQL_ACTION_IS_DATABASE_CLUSTER } from "./shared-environment";
|
||||
import { toolrunnerErrorCatcher } from "./toolrunner-error-catcher";
|
||||
import {
|
||||
getTrapCachingExtractorConfigArgs,
|
||||
@@ -651,7 +649,6 @@ export async function getCodeQLForCmd(
|
||||
],
|
||||
{ stdin: externalRepositoryToken }
|
||||
);
|
||||
core.exportVariable(CODEQL_ACTION_IS_DATABASE_CLUSTER, "true");
|
||||
},
|
||||
async runAutobuild(language: Language) {
|
||||
const cmdName =
|
||||
@@ -994,8 +991,7 @@ export async function getCodeQLForCmd(
|
||||
): Promise<void> {
|
||||
const args = [
|
||||
"database",
|
||||
"export",
|
||||
"diagnostics",
|
||||
"export-diagnostics",
|
||||
"--format=sarif-latest",
|
||||
`--output=${sarifFile}`,
|
||||
...getExtraOptionsFromEnv(["diagnostics", "export"]),
|
||||
|
||||
@@ -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[0].upload_failed_run_skipped_because, "SARIF upload is disabled");
|
||||
t.is(result.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[0].upload_failed_run_error,
|
||||
result.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[0].upload_failed_run_error,
|
||||
result.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[0].upload_failed_run_stack_trace);
|
||||
t.truthy(result.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,12 +282,10 @@ 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(
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import * as fs from "fs";
|
||||
|
||||
import * as core from "@actions/core";
|
||||
|
||||
import * as actionsUtil from "./actions-util";
|
||||
@@ -6,17 +8,9 @@ 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,
|
||||
CODEQL_ACTION_IS_DATABASE_CLUSTER,
|
||||
} from "./shared-environment";
|
||||
import { CODEQL_ACTION_ANALYZE_DID_COMPLETE_SUCCESSFULLY } from "./shared-environment";
|
||||
import * as uploadLib from "./upload-lib";
|
||||
import {
|
||||
getExistingDatabasePaths,
|
||||
getRequiredEnvParam,
|
||||
isInTestMode,
|
||||
parseMatrixInput,
|
||||
} from "./util";
|
||||
import { getRequiredEnvParam, isInTestMode, parseMatrixInput } from "./util";
|
||||
import {
|
||||
getCategoryInputOrThrow,
|
||||
getCheckoutPathInputOrThrow,
|
||||
@@ -53,9 +47,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 (
|
||||
@@ -64,7 +58,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");
|
||||
@@ -73,62 +67,40 @@ 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 databasePath = config.dbLocation;
|
||||
|
||||
const existingDatabasePaths = getExistingDatabasePaths(config);
|
||||
if (existingDatabasePaths.length === 0) {
|
||||
const sarifFile = "../codeql-failed-run.sarif";
|
||||
// We call 'database export-diagnostics' to find any per-database diagnostics.
|
||||
const sarifFile = "../codeql-failed-run.sarif";
|
||||
await codeql.databaseExportDiagnostics(
|
||||
databasePath,
|
||||
true, // Database is always a cluster for CodeQL versions that support diagnostics.
|
||||
sarifFile,
|
||||
category
|
||||
);
|
||||
|
||||
// If there was no SARIF file produced, then we fall back on 'export diagnostics'.
|
||||
if (!fs.existsSync(sarifFile)) {
|
||||
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 ?? [];
|
||||
}
|
||||
|
||||
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 ?? {};
|
||||
}
|
||||
|
||||
export async function tryUploadSarifIfRunFailed(
|
||||
@@ -136,7 +108,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(
|
||||
@@ -149,15 +121,13 @@ 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",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,29 +147,28 @@ export async function run(
|
||||
return;
|
||||
}
|
||||
|
||||
const uploadFailedSarifResults = await tryUploadSarifIfRunFailed(
|
||||
const uploadFailedSarifResult = await tryUploadSarifIfRunFailed(
|
||||
config,
|
||||
repositoryNwo,
|
||||
featureEnablement,
|
||||
logger
|
||||
);
|
||||
|
||||
// If the upload was skipped, it is the only item in the results array.
|
||||
if (uploadFailedSarifResults[0].upload_failed_run_skipped_because) {
|
||||
if (uploadFailedSarifResult.upload_failed_run_skipped_because) {
|
||||
logger.debug(
|
||||
"Won't upload a failed SARIF file for this CodeQL code scanning run because: " +
|
||||
`${uploadFailedSarifResults[0].upload_failed_run_skipped_because}.`
|
||||
`${uploadFailedSarifResult.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" &&
|
||||
!uploadFailedSarifResults[0].raw_upload_size_bytes
|
||||
!uploadFailedSarifResult.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 ${uploadFailedSarifResults}.`
|
||||
`but the result was instead ${uploadFailedSarifResult}.`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -214,5 +183,5 @@ export async function run(
|
||||
await printDebugLogs(config);
|
||||
}
|
||||
|
||||
return uploadFailedSarifResults;
|
||||
return uploadFailedSarifResult;
|
||||
}
|
||||
|
||||
+8
-10
@@ -28,8 +28,8 @@ interface InitPostStatusReport
|
||||
|
||||
async function runWrapper() {
|
||||
const startedAt = new Date();
|
||||
let uploadFailedSarifResults:
|
||||
| initActionPostHelper.UploadFailedSarifResult[]
|
||||
let uploadFailedSarifResult:
|
||||
| initActionPostHelper.UploadFailedSarifResult
|
||||
| undefined;
|
||||
try {
|
||||
const logger = getActionsLogger();
|
||||
@@ -46,7 +46,7 @@ async function runWrapper() {
|
||||
logger
|
||||
);
|
||||
|
||||
uploadFailedSarifResults = await initActionPostHelper.run(
|
||||
uploadFailedSarifResult = await initActionPostHelper.run(
|
||||
debugArtifacts.uploadDatabaseBundleDebugArtifact,
|
||||
debugArtifacts.uploadLogsDebugArtifact,
|
||||
printDebugLogs,
|
||||
@@ -74,13 +74,11 @@ async function runWrapper() {
|
||||
"success",
|
||||
startedAt
|
||||
);
|
||||
for (const result of uploadFailedSarifResults ?? []) {
|
||||
const statusReport: InitPostStatusReport = {
|
||||
...statusReportBase,
|
||||
...result,
|
||||
};
|
||||
await sendStatusReport(statusReport);
|
||||
}
|
||||
const statusReport: InitPostStatusReport = {
|
||||
...statusReportBase,
|
||||
...uploadFailedSarifResult,
|
||||
};
|
||||
await sendStatusReport(statusReport);
|
||||
}
|
||||
|
||||
void runWrapper();
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
/**
|
||||
* Environment variable that is set to true when `codeql database init --db-cluster" is run.
|
||||
*/
|
||||
export const CODEQL_ACTION_IS_DATABASE_CLUSTER =
|
||||
"CODEQL_ACTION_IS_DATABASE_CLUSTER";
|
||||
|
||||
/**
|
||||
* Environment variable that is set to true when the CodeQL Action has invoked
|
||||
* the Go autobuilder.
|
||||
|
||||
@@ -252,15 +252,6 @@ 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