Merge pull request #1605 from github/henrymercer/diagnostics-grouping-workaround

Work around duplicate locations bug in diagnostics export
This commit is contained in:
Henry Mercer 2023-03-27 11:43:33 +01:00 committed by GitHub
commit fb32c3fefd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 586 additions and 173 deletions

View file

@ -52,14 +52,23 @@ jobs:
id: init
with:
languages: javascript
queries: security-extended
tools: ${{ steps.prepare-test.outputs.tools-url }}
- name: Manually add a diagnostic
- name: Add test diagnostics
shell: bash
env:
CODEQL_PATH: ${{ steps.init.outputs.codeql-path }}
run: |
"$CODEQL_PATH" database add-diagnostic "$RUNNER_TEMP/codeql_databases/javascript" --plaintext-message="Plaintext message" --source-id="lang/diagnostics/example" --source-name="Diagnostic name"
for i in {1..2}; do
# Use the same location twice to test the workaround for the bug in CodeQL CLI 2.12.5 that
# produces an invalid diagnostic with multiple identical location objects.
"$CODEQL_PATH" database add-diagnostic \
"$RUNNER_TEMP/codeql_databases/javascript" \
--file-path /path/to/file \
--plaintext-message "Plaintext message $i" \
--source-id "lang/diagnostics/example" \
--source-name "Diagnostic name" \
--ready-for-status-page
done
- uses: ./../action/analyze
with:
output: ${{ runner.temp }}/results
@ -75,22 +84,48 @@ jobs:
env:
SARIF_PATH: ${{ runner.temp }}/results/javascript.sarif
with:
script: |-
script: |
const fs = require('fs');
function checkStatusPageNotification(n) {
const expectedMessage = 'Plaintext message 1\n\nCodeQL also found 1 other diagnostic like this. See the workflow log for details.';
if (n.message.text !== expectedMessage) {
core.setFailed(`Expected the status page diagnostic to have the message '${expectedMessage}', but found '${n.message.text}'.`);
}
if (n.locations.length !== 1) {
core.setFailed(`Expected the status page diagnostic to have exactly 1 location, but found ${n.locations.length}.`);
}
}
const sarif = JSON.parse(fs.readFileSync(process.env['SARIF_PATH'], 'utf8'));
const run = sarif.runs[0];
const toolExecutionNotifications = run.invocations[0].toolExecutionNotifications;
const diagnosticToolExecutionNotification = toolExecutionNotifications.filter(n => n.descriptor.id === 'lang/diagnostics/example' && n.message.text === 'Plaintext message');
if (diagnosticToolExecutionNotification.length !== 1) {
core.setFailed(`Expected exactly 1 entry for this diagnostic in the 'runs[].invocations[].toolExecutionNotifications[]' SARIF property, found ${diagnosticToolExecutionNotification.length}`);
const statusPageNotifications = toolExecutionNotifications.filter(n =>
n.descriptor.id === 'lang/diagnostics/example' && n.properties?.visibility?.statusPage
);
if (statusPageNotifications.length !== 1) {
core.setFailed(
'Expected exactly one status page reporting descriptor for this diagnostic in the ' +
`'runs[].invocations[].toolExecutionNotifications[]' SARIF property, but found ` +
`${statusPageNotifications.length}. All notification reporting descriptors: ` +
`${JSON.stringify(toolExecutionNotifications)}.`
);
}
checkStatusPageNotification(statusPageNotifications[0]);
const notifications = run.tool.driver.notifications;
const diagnosticNotification = notifications.filter(n => n.id === 'lang/diagnostics/example' && n.name === 'lang/diagnostics/example' && n.fullDescription.text && 'Diagnostic name');
const diagnosticNotification = notifications.filter(n =>
n.id === 'lang/diagnostics/example' && n.name === 'lang/diagnostics/example' &&
n.fullDescription.text === 'Diagnostic name'
);
if (diagnosticNotification.length !== 1) {
core.setFailed(`Expected exactly 1 entry for this diagnostic in the 'runs[].tool.driver.notifications[]' SARIF property, found ${diagnosticNotification.length}`);
core.setFailed(
'Expected exactly one notification for this diagnostic in the ' +
`'runs[].tool.driver.notifications[]' SARIF property, but found ` +
`${diagnosticNotification.length}. All notifications: ` +
`${JSON.stringify(notifications)}.`
);
}
core.info('Finished diagnostic export test');

2
lib/analyze-action.js generated
View file

@ -155,7 +155,7 @@ async function run() {
if (hasBadExpectErrorInput()) {
throw new Error("`expect-error` input parameter is for internal use only. It should only be set by codeql-action or a fork.");
}
await util.enrichEnvironment(await (0, codeql_1.getCodeQL)(config.codeQLCmd));
await (0, codeql_1.enrichEnvironment)(await (0, codeql_1.getCodeQL)(config.codeQLCmd));
const apiDetails = (0, api_client_1.getApiDetails)();
const outputDir = actionsUtil.getRequiredInput("output");
const threads = util.getThreadsFlag(actionsUtil.getOptionalInput("threads") || process.env["CODEQL_THREADS"], logger);

File diff suppressed because one or more lines are too long

2
lib/analyze.js generated
View file

@ -218,7 +218,7 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
return statusReport;
async function runInterpretResults(language, queries, sarifFile, enableDebugLogging) {
const databasePath = util.getCodeQLDatabasePath(config, language);
return await codeql.databaseInterpretResults(databasePath, queries, sarifFile, addSnippetsFlag, threadsFlag, enableDebugLogging ? "-vv" : "-v", automationDetailsId, config, features);
return await codeql.databaseInterpretResults(databasePath, queries, sarifFile, addSnippetsFlag, threadsFlag, enableDebugLogging ? "-vv" : "-v", automationDetailsId, config, features, logger);
}
async function runPrintLinesOfCode(language) {
const databasePath = util.getCodeQLDatabasePath(config, language);

File diff suppressed because one or more lines are too long

43
lib/codeql.js generated
View file

@ -23,9 +23,10 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getExtraOptions = exports.getCodeQLForCmd = exports.getCodeQLForTesting = exports.getCachedCodeQL = exports.setCodeQL = exports.getCodeQL = exports.setupCodeQL = exports.CODEQL_VERSION_INIT_WITH_QLCONFIG = exports.CODEQL_VERSION_SECURITY_EXPERIMENTAL_SUITE = exports.CODEQL_VERSION_BETTER_RESOLVE_LANGUAGES = exports.CODEQL_VERSION_ML_POWERED_QUERIES_WINDOWS = exports.CODEQL_VERSION_TRACING_GLIBC_2_34 = exports.CODEQL_VERSION_NEW_TRACING = exports.CODEQL_VERSION_GHES_PACK_DOWNLOAD = exports.CommandInvocationError = void 0;
exports.enrichEnvironment = exports.getExtraOptions = exports.getCodeQLForCmd = exports.getCodeQLForTesting = exports.getCachedCodeQL = exports.setCodeQL = exports.getCodeQL = exports.setupCodeQL = exports.CODEQL_VERSION_INIT_WITH_QLCONFIG = exports.CODEQL_VERSION_SECURITY_EXPERIMENTAL_SUITE = exports.CODEQL_VERSION_BETTER_RESOLVE_LANGUAGES = exports.CODEQL_VERSION_ML_POWERED_QUERIES_WINDOWS = exports.CODEQL_VERSION_TRACING_GLIBC_2_34 = exports.CODEQL_VERSION_NEW_TRACING = exports.CODEQL_VERSION_GHES_PACK_DOWNLOAD = exports.CommandInvocationError = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const core = __importStar(require("@actions/core"));
const toolrunner = __importStar(require("@actions/exec/lib/toolrunner"));
const yaml = __importStar(require("js-yaml"));
const actions_util_1 = require("./actions-util");
@ -34,6 +35,7 @@ const error_matcher_1 = require("./error-matcher");
const feature_flags_1 = require("./feature-flags");
const languages_1 = require("./languages");
const setupCodeql = __importStar(require("./setup-codeql"));
const shared_environment_1 = require("./shared-environment");
const toolrunner_error_catcher_1 = require("./toolrunner-error-catcher");
const trap_caching_1 = require("./trap-caching");
const util = __importStar(require("./util"));
@ -505,14 +507,18 @@ async function getCodeQLForCmd(cmd, checkVersion) {
}
await (0, toolrunner_error_catcher_1.toolrunnerErrorCatcher)(cmd, codeqlArgs, error_matcher_1.errorMatchers);
},
async databaseInterpretResults(databasePath, querySuitePaths, sarifFile, addSnippetsFlag, threadsFlag, verbosityFlag, automationDetailsId, config, features) {
async databaseInterpretResults(databasePath, querySuitePaths, sarifFile, addSnippetsFlag, threadsFlag, verbosityFlag, automationDetailsId, config, features, logger) {
const shouldExportDiagnostics = await features.getValue(feature_flags_1.Feature.ExportDiagnosticsEnabled, this);
const codeqlOutputFile = shouldExportDiagnostics
? path.join(config.tempDir, "codeql-intermediate-results.sarif")
: sarifFile;
const codeqlArgs = [
"database",
"interpret-results",
threadsFlag,
"--format=sarif-latest",
verbosityFlag,
`--output=${sarifFile}`,
`--output=${codeqlOutputFile}`,
addSnippetsFlag,
"--print-diagnostics-summary",
"--print-metrics-summary",
@ -528,7 +534,7 @@ async function getCodeQLForCmd(cmd, checkVersion) {
if (await util.codeQlVersionAbove(this, CODEQL_VERSION_FILE_BASELINE_INFORMATION)) {
codeqlArgs.push("--sarif-add-baseline-file-info");
}
if (await features.getValue(feature_flags_1.Feature.ExportDiagnosticsEnabled, this)) {
if (shouldExportDiagnostics) {
codeqlArgs.push("--sarif-include-diagnostics");
}
codeqlArgs.push(databasePath);
@ -537,6 +543,11 @@ async function getCodeQLForCmd(cmd, checkVersion) {
}
// capture stdout, which contains analysis summaries
const returnState = await (0, toolrunner_error_catcher_1.toolrunnerErrorCatcher)(cmd, codeqlArgs, error_matcher_1.errorMatchers);
if (shouldExportDiagnostics) {
let sarif = JSON.parse(fs.readFileSync(codeqlOutputFile, "utf8"));
sarif = util.fixInvalidNotifications(sarif, logger);
fs.writeFileSync(sarifFile, JSON.stringify(sarif));
}
return returnState.stdout;
},
async databasePrintBaseline(databasePath) {
@ -613,14 +624,15 @@ async function getCodeQLForCmd(cmd, checkVersion) {
];
await new toolrunner.ToolRunner(cmd, args).exec();
},
async databaseExportDiagnostics(databasePath, sarifFile, automationDetailsId) {
async databaseExportDiagnostics(databasePath, sarifFile, automationDetailsId, tempDir, logger) {
const intermediateSarifFile = path.join(tempDir, "codeql-intermediate-results.sarif");
const args = [
"database",
"export-diagnostics",
`${databasePath}`,
"--db-cluster",
"--format=sarif-latest",
`--output=${sarifFile}`,
`--output=${intermediateSarifFile}`,
"--sarif-include-diagnostics",
"-vvv",
...getExtraOptionsFromEnv(["diagnostics", "export"]),
@ -629,6 +641,10 @@ async function getCodeQLForCmd(cmd, checkVersion) {
args.push("--sarif-category", automationDetailsId);
}
await new toolrunner.ToolRunner(cmd, args).exec();
// Fix invalid notifications in the SARIF file output by CodeQL.
let sarif = JSON.parse(fs.readFileSync(intermediateSarifFile, "utf8"));
sarif = util.fixInvalidNotifications(sarif, logger);
fs.writeFileSync(sarifFile, JSON.stringify(sarif));
},
async diagnosticsExport(sarifFile, automationDetailsId, config, features) {
const args = [
@ -829,4 +845,19 @@ async function getCodeScanningConfigExportArguments(config, codeql, features) {
}
return [];
}
/**
* Enrich the environment variables with further flags that we cannot
* know the value of until we know what version of CodeQL we're running.
*/
async function enrichEnvironment(codeql) {
if (await util.codeQlVersionAbove(codeql, exports.CODEQL_VERSION_NEW_TRACING)) {
core.exportVariable(shared_environment_1.EnvVar.FEATURE_MULTI_LANGUAGE, "false");
core.exportVariable(shared_environment_1.EnvVar.FEATURE_SANDWICH, "false");
}
else {
core.exportVariable(shared_environment_1.EnvVar.FEATURE_MULTI_LANGUAGE, "true");
core.exportVariable(shared_environment_1.EnvVar.FEATURE_SANDWICH, "true");
}
}
exports.enrichEnvironment = enrichEnvironment;
//# sourceMappingURL=codeql.js.map

File diff suppressed because one or more lines are too long

8
lib/codeql.test.js generated
View file

@ -424,7 +424,7 @@ for (const isBundleVersionInUrl of [true, false]) {
sinon.stub(codeqlObject, "getVersion").resolves("2.7.0");
// safeWhich throws because of the test CodeQL object.
sinon.stub(safeWhich, "safeWhich").resolves("");
await codeqlObject.databaseInterpretResults("", [], "", "", "", "-v", "", stubConfig, (0, testing_utils_1.createFeatures)([]));
await codeqlObject.databaseInterpretResults("", [], "", "", "", "-v", "", stubConfig, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
t.false(runnerConstructorStub.firstCall.args[1].includes("--sarif-add-query-help"), "--sarif-add-query-help should be absent, but it is present");
});
(0, ava_1.default)("databaseInterpretResults() sets --sarif-add-query-help for 2.7.1", async (t) => {
@ -433,7 +433,7 @@ for (const isBundleVersionInUrl of [true, false]) {
sinon.stub(codeqlObject, "getVersion").resolves("2.7.1");
// safeWhich throws because of the test CodeQL object.
sinon.stub(safeWhich, "safeWhich").resolves("");
await codeqlObject.databaseInterpretResults("", [], "", "", "", "-v", "", stubConfig, (0, testing_utils_1.createFeatures)([]));
await codeqlObject.databaseInterpretResults("", [], "", "", "", "-v", "", stubConfig, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
t.true(runnerConstructorStub.firstCall.args[1].includes("--sarif-add-query-help"), "--sarif-add-query-help should be present, but it is absent");
});
(0, ava_1.default)("databaseInitCluster() without injected codescanning config", async (t) => {
@ -733,7 +733,7 @@ const injectedConfigMacro = ava_1.default.macro({
sinon.stub(codeqlObject, "getVersion").resolves("2.11.3");
// safeWhich throws because of the test CodeQL object.
sinon.stub(safeWhich, "safeWhich").resolves("");
await codeqlObject.databaseInterpretResults("", [], "", "", "", "-v", "", stubConfig, (0, testing_utils_1.createFeatures)([]));
await codeqlObject.databaseInterpretResults("", [], "", "", "", "-v", "", stubConfig, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
t.true(runnerConstructorStub.firstCall.args[1].includes("--sarif-add-baseline-file-info"), "--sarif-add-baseline-file-info should be present, but it is absent");
});
(0, ava_1.default)("databaseInterpretResults() does not set --sarif-add-baseline-file-info for 2.11.2", async (t) => {
@ -742,7 +742,7 @@ const injectedConfigMacro = ava_1.default.macro({
sinon.stub(codeqlObject, "getVersion").resolves("2.11.2");
// safeWhich throws because of the test CodeQL object.
sinon.stub(safeWhich, "safeWhich").resolves("");
await codeqlObject.databaseInterpretResults("", [], "", "", "", "-v", "", stubConfig, (0, testing_utils_1.createFeatures)([]));
await codeqlObject.databaseInterpretResults("", [], "", "", "", "-v", "", stubConfig, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
t.false(runnerConstructorStub.firstCall.args[1].includes("--sarif-add-baseline-file-info"), "--sarif-add-baseline-file-info must be absent, but it is present");
});
function stubToolRunnerConstructor() {

File diff suppressed because one or more lines are too long

View file

@ -70,7 +70,7 @@ async function maybeUploadFailedSarif(config, repositoryNwo, features, logger) {
}
else {
// We call 'database export-diagnostics' to find any per-database diagnostics.
await codeql.databaseExportDiagnostics(databasePath, sarifFile, category);
await codeql.databaseExportDiagnostics(databasePath, sarifFile, category, config.tempDir, logger);
}
core.info(`Uploading failed SARIF file ${sarifFile}`);
const uploadResult = await uploadLib.uploadFromActions(sarifFile, checkoutPath, category, logger);

View file

@ -1 +1 @@
{"version":3,"file":"init-action-post-helper.js","sourceRoot":"","sources":["../src/init-action-post-helper.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"init-action-post-helper.js","sourceRoot":"","sources":["../src/init-action-post-helper.ts"],"names":[],"mappings":"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"}

View file

@ -344,7 +344,7 @@ async function testFailedSarifUpload(t, actionsWorkflow, { category, databaseExi
zipped_upload_size_bytes: 10,
});
if (databaseExists && exportDiagnosticsEnabled) {
t.true(databaseExportDiagnosticsStub.calledOnceWith(config.dbLocation, sinon.match.string, category), `Actual args were: ${databaseExportDiagnosticsStub.args}`);
t.true(databaseExportDiagnosticsStub.calledOnceWith(config.dbLocation, sinon.match.string, category, sinon.match.any, sinon.match.any), `Actual args were: ${databaseExportDiagnosticsStub.args}`);
}
else {
t.true(diagnosticsExportStub.calledOnceWith(sinon.match.string, category, config, sinon.match.any), `Actual args were: ${diagnosticsExportStub.args}`);

File diff suppressed because one or more lines are too long

2
lib/init-action.js generated
View file

@ -129,7 +129,7 @@ async function run() {
toolsDownloadDurationMs = initCodeQLResult.toolsDownloadDurationMs;
toolsVersion = initCodeQLResult.toolsVersion;
toolsSource = initCodeQLResult.toolsSource;
await (0, util_1.enrichEnvironment)(codeql);
await (0, codeql_1.enrichEnvironment)(codeql);
config = await (0, init_1.initConfig)((0, actions_util_1.getOptionalInput)("languages"), (0, actions_util_1.getOptionalInput)("queries"), (0, actions_util_1.getOptionalInput)("packs"), registriesInput, (0, actions_util_1.getOptionalInput)("config-file"), (0, actions_util_1.getOptionalInput)("db-location"), getTrapCachingEnabled(),
// Debug mode is enabled if:
// - The `init` Action is passed `debug: true`.

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,38 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ODASA_TRACER_CONFIGURATION = exports.CODEQL_WORKFLOW_STARTED_AT = exports.CODEQL_ACTION_TEST_MODE = exports.CODEQL_ACTION_TESTING_ENVIRONMENT = exports.CODEQL_ACTION_ANALYZE_DID_COMPLETE_SUCCESSFULLY = exports.CODEQL_ACTION_DID_AUTOBUILD_GOLANG = void 0;
exports.ODASA_TRACER_CONFIGURATION = exports.CODEQL_WORKFLOW_STARTED_AT = exports.CODEQL_ACTION_DISABLE_DUPLICATE_LOCATION_FIX = exports.CODEQL_ACTION_TEST_MODE = exports.CODEQL_ACTION_TESTING_ENVIRONMENT = exports.CODEQL_ACTION_ANALYZE_DID_COMPLETE_SUCCESSFULLY = exports.CODEQL_ACTION_DID_AUTOBUILD_GOLANG = exports.EnvVar = void 0;
/**
* Environment variables to be set by codeql-action and used by the
* CLI.
*/
var EnvVar;
(function (EnvVar) {
/**
* Semver of the codeql-action as specified in package.json.
*/
EnvVar["VERSION"] = "CODEQL_ACTION_VERSION";
/**
* If set to a truthy value, then the codeql-action might combine SARIF
* output from several `interpret-results` runs for the same Language.
*/
EnvVar["FEATURE_SARIF_COMBINE"] = "CODEQL_ACTION_FEATURE_SARIF_COMBINE";
/**
* If set to the "true" string, then the codeql-action will upload SARIF,
* not the cli.
*/
EnvVar["FEATURE_WILL_UPLOAD"] = "CODEQL_ACTION_FEATURE_WILL_UPLOAD";
/**
* If set to the "true" string, then the codeql-action is using its
* own deprecated and non-standard way of scanning for multiple
* languages.
*/
EnvVar["FEATURE_MULTI_LANGUAGE"] = "CODEQL_ACTION_FEATURE_MULTI_LANGUAGE";
/**
* If set to the "true" string, then the codeql-action is using its
* own sandwiched workflow mechanism
*/
EnvVar["FEATURE_SANDWICH"] = "CODEQL_ACTION_FEATURE_SANDWICH";
})(EnvVar = exports.EnvVar || (exports.EnvVar = {}));
/**
* Environment variable that is set to true when the CodeQL Action has invoked
* the Go autobuilder.
@ -14,6 +46,11 @@ exports.CODEQL_ACTION_ANALYZE_DID_COMPLETE_SUCCESSFULLY = "CODEQL_ACTION_ANALYZE
exports.CODEQL_ACTION_TESTING_ENVIRONMENT = "CODEQL_ACTION_TESTING_ENVIRONMENT";
/** Used to disable uploading SARIF results or status reports to the GitHub API */
exports.CODEQL_ACTION_TEST_MODE = "CODEQL_ACTION_TEST_MODE";
/**
* Used to disable the SARIF post-processing in the Action that removes duplicate locations from
* notifications in the `run[].invocations[].toolExecutionNotifications` SARIF property.
*/
exports.CODEQL_ACTION_DISABLE_DUPLICATE_LOCATION_FIX = "CODEQL_ACTION_DISABLE_DUPLICATE_LOCATION_FIX";
/**
* The time at which the first action (normally init) started executing.
* If a workflow invokes a different action without first invoking the init

View file

@ -1 +1 @@
{"version":3,"file":"shared-environment.js","sourceRoot":"","sources":["../src/shared-environment.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACU,QAAA,kCAAkC,GAC7C,oCAAoC,CAAC;AAEvC;;;GAGG;AACU,QAAA,+CAA+C,GAC1D,iDAAiD,CAAC;AAEvC,QAAA,iCAAiC,GAC5C,mCAAmC,CAAC;AAEtC,kFAAkF;AACrE,QAAA,uBAAuB,GAAG,yBAAyB,CAAC;AAEjE;;;;;;GAMG;AACU,QAAA,0BAA0B,GAAG,4BAA4B,CAAC;AAE1D,QAAA,0BAA0B,GAAG,4BAA4B,CAAC"}
{"version":3,"file":"shared-environment.js","sourceRoot":"","sources":["../src/shared-environment.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACH,IAAY,MA8BX;AA9BD,WAAY,MAAM;IAChB;;OAEG;IACH,2CAAiC,CAAA;IAEjC;;;OAGG;IACH,uEAA6D,CAAA;IAE7D;;;OAGG;IACH,mEAAyD,CAAA;IAEzD;;;;OAIG;IACH,yEAA+D,CAAA;IAE/D;;;OAGG;IACH,6DAAmD,CAAA;AACrD,CAAC,EA9BW,MAAM,GAAN,cAAM,KAAN,cAAM,QA8BjB;AAED;;;GAGG;AACU,QAAA,kCAAkC,GAC7C,oCAAoC,CAAC;AAEvC;;;GAGG;AACU,QAAA,+CAA+C,GAC1D,iDAAiD,CAAC;AAEvC,QAAA,iCAAiC,GAC5C,mCAAmC,CAAC;AAEtC,kFAAkF;AACrE,QAAA,uBAAuB,GAAG,yBAAyB,CAAC;AAEjE;;;GAGG;AACU,QAAA,4CAA4C,GACvD,8CAA8C,CAAC;AAEjD;;;;;;GAMG;AACU,QAAA,0BAA0B,GAAG,4BAA4B,CAAC;AAE1D,QAAA,0BAA0B,GAAG,4BAA4B,CAAC"}

4
lib/upload-lib.js generated
View file

@ -38,7 +38,7 @@ const actionsUtil = __importStar(require("./actions-util"));
const api = __importStar(require("./api-client"));
const fingerprints = __importStar(require("./fingerprints"));
const repository_1 = require("./repository");
const sharedEnv = __importStar(require("./shared-environment"));
const shared_environment_1 = require("./shared-environment");
const util = __importStar(require("./util"));
const workflow = __importStar(require("./workflow"));
// Takes a list of paths to sarif files and combines them together,
@ -206,7 +206,7 @@ function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, wo
workflow_run_id: workflowRunID,
checkout_uri: checkoutURI,
environment,
started_at: process.env[sharedEnv.CODEQL_WORKFLOW_STARTED_AT],
started_at: process.env[shared_environment_1.CODEQL_WORKFLOW_STARTED_AT],
tool_names: toolNames,
base_ref: undefined,
base_sha: undefined,

File diff suppressed because one or more lines are too long

119
lib/util.js generated
View file

@ -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.parseMatrixInput = exports.isHostedRunner = exports.checkForTimeout = exports.withTimeout = exports.tryGetFolderBytes = exports.listFolder = exports.doesDirectoryExist = exports.logCodeScanningConfigInCli = exports.useCodeScanningConfigInCli = exports.isInTestMode = exports.getMlPoweredJsQueriesStatus = exports.getMlPoweredJsQueriesPack = exports.ML_POWERED_JS_QUERIES_PACK_NAME = exports.supportExpectDiscardedCache = exports.isGoodVersion = exports.delay = exports.bundleDb = exports.codeQlVersionAbove = exports.getCachedCodeQlVersion = exports.cacheCodeQlVersion = exports.isHTTPError = exports.UserError = exports.HTTPError = exports.getRequiredEnvParam = exports.enrichEnvironment = exports.initializeEnvironment = exports.EnvVar = exports.assertNever = exports.apiVersionInRange = exports.DisallowedAPIVersionReason = exports.checkGitHubVersionInRange = exports.getGitHubVersion = exports.GitHubVariant = exports.parseGitHubUrl = exports.getCodeQLDatabasePath = exports.getThreadsFlag = exports.getThreadsFlagValue = exports.getAddSnippetsFlag = exports.getMemoryFlag = exports.getMemoryFlagValue = exports.withTmpDir = exports.getToolNames = exports.getExtraOptionsEnvParam = exports.DEFAULT_DEBUG_DATABASE_NAME = exports.DEFAULT_DEBUG_ARTIFACT_NAME = exports.GITHUB_DOTCOM_URL = void 0;
exports.fixInvalidNotifications = exports.parseMatrixInput = exports.isHostedRunner = exports.checkForTimeout = exports.withTimeout = exports.tryGetFolderBytes = exports.listFolder = exports.doesDirectoryExist = exports.logCodeScanningConfigInCli = exports.useCodeScanningConfigInCli = exports.isInTestMode = exports.getMlPoweredJsQueriesStatus = exports.getMlPoweredJsQueriesPack = exports.ML_POWERED_JS_QUERIES_PACK_NAME = 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.getGitHubVersion = exports.GitHubVariant = exports.parseGitHubUrl = exports.getCodeQLDatabasePath = exports.getThreadsFlag = exports.getThreadsFlagValue = exports.getAddSnippetsFlag = exports.getMemoryFlag = exports.getMemoryFlagValue = 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"));
@ -37,7 +37,6 @@ const get_folder_size_1 = __importDefault(require("get-folder-size"));
const semver = __importStar(require("semver"));
const api_client_1 = require("./api-client");
const apiCompatibility = __importStar(require("./api-compatibility.json"));
const codeql_1 = require("./codeql");
const config_utils_1 = require("./config-utils");
const feature_flags_1 = require("./feature-flags");
const shared_environment_1 = require("./shared-environment");
@ -333,63 +332,16 @@ function assertNever(value) {
throw new ExhaustivityCheckingError(value);
}
exports.assertNever = assertNever;
/**
* Environment variables to be set by codeql-action and used by the
* CLI.
*/
var EnvVar;
(function (EnvVar) {
/**
* Semver of the codeql-action as specified in package.json.
*/
EnvVar["VERSION"] = "CODEQL_ACTION_VERSION";
/**
* If set to a truthy value, then the codeql-action might combine SARIF
* output from several `interpret-results` runs for the same Language.
*/
EnvVar["FEATURE_SARIF_COMBINE"] = "CODEQL_ACTION_FEATURE_SARIF_COMBINE";
/**
* If set to the "true" string, then the codeql-action will upload SARIF,
* not the cli.
*/
EnvVar["FEATURE_WILL_UPLOAD"] = "CODEQL_ACTION_FEATURE_WILL_UPLOAD";
/**
* If set to the "true" string, then the codeql-action is using its
* own deprecated and non-standard way of scanning for multiple
* languages.
*/
EnvVar["FEATURE_MULTI_LANGUAGE"] = "CODEQL_ACTION_FEATURE_MULTI_LANGUAGE";
/**
* If set to the "true" string, then the codeql-action is using its
* own sandwiched workflow mechanism
*/
EnvVar["FEATURE_SANDWICH"] = "CODEQL_ACTION_FEATURE_SANDWICH";
})(EnvVar = exports.EnvVar || (exports.EnvVar = {}));
/**
* Set some initial environment variables that we can set even without
* knowing what version of CodeQL we're running.
*/
function initializeEnvironment(version) {
core.exportVariable(EnvVar.VERSION, version);
core.exportVariable(EnvVar.FEATURE_SARIF_COMBINE, "true");
core.exportVariable(EnvVar.FEATURE_WILL_UPLOAD, "true");
core.exportVariable(shared_environment_1.EnvVar.VERSION, version);
core.exportVariable(shared_environment_1.EnvVar.FEATURE_SARIF_COMBINE, "true");
core.exportVariable(shared_environment_1.EnvVar.FEATURE_WILL_UPLOAD, "true");
}
exports.initializeEnvironment = initializeEnvironment;
/**
* Enrich the environment variables with further flags that we cannot
* know the value of until we know what version of CodeQL we're running.
*/
async function enrichEnvironment(codeql) {
if (await codeQlVersionAbove(codeql, codeql_1.CODEQL_VERSION_NEW_TRACING)) {
core.exportVariable(EnvVar.FEATURE_MULTI_LANGUAGE, "false");
core.exportVariable(EnvVar.FEATURE_SANDWICH, "false");
}
else {
core.exportVariable(EnvVar.FEATURE_MULTI_LANGUAGE, "true");
core.exportVariable(EnvVar.FEATURE_SANDWICH, "true");
}
}
exports.enrichEnvironment = enrichEnvironment;
/**
* Get an environment parameter, but throw an error if it is not set.
*/
@ -707,4 +659,67 @@ function parseMatrixInput(matrixInput) {
return JSON.parse(matrixInput);
}
exports.parseMatrixInput = parseMatrixInput;
function removeDuplicateLocations(locations) {
const newJsonLocations = new Set();
return locations.filter((location) => {
const jsonLocation = JSON.stringify(location);
if (!newJsonLocations.has(jsonLocation)) {
newJsonLocations.add(jsonLocation);
return true;
}
return false;
});
}
function fixInvalidNotifications(sarif, logger) {
if (process.env[shared_environment_1.CODEQL_ACTION_DISABLE_DUPLICATE_LOCATION_FIX] === "true") {
logger.info("SARIF notification object duplicate location fix disabled by the " +
`${shared_environment_1.CODEQL_ACTION_DISABLE_DUPLICATE_LOCATION_FIX} environment variable.`);
return sarif;
}
if (!(sarif.runs instanceof Array)) {
return sarif;
}
// Ensure that the array of locations for each SARIF notification contains unique locations.
// This is a workaround for a bug in the CodeQL CLI that causes duplicate locations to be
// emitted in some cases.
let numDuplicateLocationsRemoved = 0;
const newSarif = {
...sarif,
runs: sarif.runs.map((run) => {
if (run.tool?.driver?.name !== "CodeQL" ||
!(run.invocations instanceof Array)) {
return run;
}
return {
...run,
invocations: run.invocations.map((invocation) => {
if (!(invocation.toolExecutionNotifications instanceof Array)) {
return invocation;
}
return {
...invocation,
toolExecutionNotifications: invocation.toolExecutionNotifications.map((notification) => {
if (!(notification.locations instanceof Array)) {
return notification;
}
const newLocations = removeDuplicateLocations(notification.locations);
numDuplicateLocationsRemoved +=
notification.locations.length - newLocations.length;
return {
...notification,
locations: newLocations,
};
}),
};
}),
};
}),
};
if (numDuplicateLocationsRemoved > 0) {
logger.info(`Removed ${numDuplicateLocationsRemoved} duplicate locations from SARIF notification ` +
"objects.");
}
return newSarif;
}
exports.fixInvalidNotifications = fixInvalidNotifications;
//# sourceMappingURL=util.js.map

File diff suppressed because one or more lines are too long

45
lib/util.test.js generated
View file

@ -330,4 +330,49 @@ const shortTime = 10;
t.deepEqual(shortTaskTimedOut, false);
t.deepEqual(result, 99);
});
function createMockSarifWithNotification(locations) {
return {
runs: [
{
tool: {
driver: {
name: "CodeQL",
},
},
invocations: [
{
toolExecutionNotifications: [
{
locations,
},
],
},
],
},
],
};
}
const stubLocation = {
physicalLocation: {
artifactLocation: {
uri: "file1",
},
},
};
(0, ava_1.default)("fixInvalidNotifications leaves notifications with unique locations alone", (t) => {
const messages = [];
const result = util.fixInvalidNotifications(createMockSarifWithNotification([stubLocation]), (0, testing_utils_1.getRecordingLogger)(messages));
t.deepEqual(result, createMockSarifWithNotification([stubLocation]));
t.is(messages.length, 0);
});
(0, ava_1.default)("fixInvalidNotifications removes duplicate locations", (t) => {
const messages = [];
const result = util.fixInvalidNotifications(createMockSarifWithNotification([stubLocation, stubLocation]), (0, testing_utils_1.getRecordingLogger)(messages));
t.deepEqual(result, createMockSarifWithNotification([stubLocation]));
t.is(messages.length, 1);
t.deepEqual(messages[0], {
type: "info",
message: "Removed 1 duplicate locations from SARIF notification objects.",
});
});
//# sourceMappingURL=util.test.js.map

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,5 @@
name: "Diagnostic export"
description: "Tests that a manually added diagnostic is exported to SARIF."
description: "Tests that manually added diagnostics are correctly exported to SARIF."
versions: ["latest", "nightly-latest"]
env:
CODEQL_ACTION_EXPORT_DIAGNOSTICS: true
@ -8,14 +8,23 @@ steps:
id: init
with:
languages: javascript
queries: security-extended
tools: ${{ steps.prepare-test.outputs.tools-url }}
- name: Manually add a diagnostic
- name: Add test diagnostics
shell: bash
env:
CODEQL_PATH: ${{ steps.init.outputs.codeql-path }}
run: |
"$CODEQL_PATH" database add-diagnostic "$RUNNER_TEMP/codeql_databases/javascript" --plaintext-message="Plaintext message" --source-id="lang/diagnostics/example" --source-name="Diagnostic name"
for i in {1..2}; do
# Use the same location twice to test the workaround for the bug in CodeQL CLI 2.12.5 that
# produces an invalid diagnostic with multiple identical location objects.
"$CODEQL_PATH" database add-diagnostic \
"$RUNNER_TEMP/codeql_databases/javascript" \
--file-path /path/to/file \
--plaintext-message "Plaintext message $i" \
--source-id "lang/diagnostics/example" \
--source-name "Diagnostic name" \
--ready-for-status-page
done
- uses: ./../action/analyze
with:
output: "${{ runner.temp }}/results"
@ -34,19 +43,45 @@ steps:
script: |
const fs = require('fs');
function checkStatusPageNotification(n) {
const expectedMessage = 'Plaintext message 1\n\nCodeQL also found 1 other diagnostic like this. See the workflow log for details.';
if (n.message.text !== expectedMessage) {
core.setFailed(`Expected the status page diagnostic to have the message '${expectedMessage}', but found '${n.message.text}'.`);
}
if (n.locations.length !== 1) {
core.setFailed(`Expected the status page diagnostic to have exactly 1 location, but found ${n.locations.length}.`);
}
}
const sarif = JSON.parse(fs.readFileSync(process.env['SARIF_PATH'], 'utf8'));
const run = sarif.runs[0];
const toolExecutionNotifications = run.invocations[0].toolExecutionNotifications;
const diagnosticToolExecutionNotification = toolExecutionNotifications.filter(n => n.descriptor.id === 'lang/diagnostics/example' && n.message.text === 'Plaintext message');
if (diagnosticToolExecutionNotification.length !== 1) {
core.setFailed(`Expected exactly 1 entry for this diagnostic in the 'runs[].invocations[].toolExecutionNotifications[]' SARIF property, found ${diagnosticToolExecutionNotification.length}`);
const statusPageNotifications = toolExecutionNotifications.filter(n =>
n.descriptor.id === 'lang/diagnostics/example' && n.properties?.visibility?.statusPage
);
if (statusPageNotifications.length !== 1) {
core.setFailed(
'Expected exactly one status page reporting descriptor for this diagnostic in the ' +
`'runs[].invocations[].toolExecutionNotifications[]' SARIF property, but found ` +
`${statusPageNotifications.length}. All notification reporting descriptors: ` +
`${JSON.stringify(toolExecutionNotifications)}.`
);
}
checkStatusPageNotification(statusPageNotifications[0]);
const notifications = run.tool.driver.notifications;
const diagnosticNotification = notifications.filter(n => n.id === 'lang/diagnostics/example' && n.name === 'lang/diagnostics/example' && n.fullDescription.text && 'Diagnostic name');
const diagnosticNotification = notifications.filter(n =>
n.id === 'lang/diagnostics/example' && n.name === 'lang/diagnostics/example' &&
n.fullDescription.text === 'Diagnostic name'
);
if (diagnosticNotification.length !== 1) {
core.setFailed(`Expected exactly 1 entry for this diagnostic in the 'runs[].tool.driver.notifications[]' SARIF property, found ${diagnosticNotification.length}`);
core.setFailed(
'Expected exactly one notification for this diagnostic in the ' +
`'runs[].tool.driver.notifications[]' SARIF property, but found ` +
`${diagnosticNotification.length}. All notifications: ` +
`${JSON.stringify(notifications)}.`
);
}
core.info('Finished diagnostic export test');
core.info('Finished diagnostic export test');

View file

@ -16,7 +16,7 @@ import {
} from "./analyze";
import { getApiDetails, getGitHubVersion } from "./api-client";
import { runAutobuild } from "./autobuild";
import { getCodeQL } from "./codeql";
import { enrichEnvironment, getCodeQL } from "./codeql";
import { Config, getConfig } from "./config-utils";
import { uploadDatabases } from "./database-upload";
import { Features } from "./feature-flags";
@ -207,7 +207,7 @@ async function run() {
);
}
await util.enrichEnvironment(await getCodeQL(config.codeQLCmd));
await enrichEnvironment(await getCodeQL(config.codeQLCmd));
const apiDetails = getApiDetails();
const outputDir = actionsUtil.getRequiredInput("output");

View file

@ -369,7 +369,8 @@ export async function runQueries(
enableDebugLogging ? "-vv" : "-v",
automationDetailsId,
config,
features
features,
logger
);
}

View file

@ -637,7 +637,8 @@ test("databaseInterpretResults() does not set --sarif-add-query-help for 2.7.0",
"-v",
"",
stubConfig,
createFeatures([])
createFeatures([]),
getRunnerLogger(true)
);
t.false(
runnerConstructorStub.firstCall.args[1].includes("--sarif-add-query-help"),
@ -660,7 +661,8 @@ test("databaseInterpretResults() sets --sarif-add-query-help for 2.7.1", async (
"-v",
"",
stubConfig,
createFeatures([])
createFeatures([]),
getRunnerLogger(true)
);
t.true(
runnerConstructorStub.firstCall.args[1].includes("--sarif-add-query-help"),
@ -1158,7 +1160,8 @@ test("databaseInterpretResults() sets --sarif-add-baseline-file-info for 2.11.3"
"-v",
"",
stubConfig,
createFeatures([])
createFeatures([]),
getRunnerLogger(true)
);
t.true(
runnerConstructorStub.firstCall.args[1].includes(
@ -1183,7 +1186,8 @@ test("databaseInterpretResults() does not set --sarif-add-baseline-file-info for
"-v",
"",
stubConfig,
createFeatures([])
createFeatures([]),
getRunnerLogger(true)
);
t.false(
runnerConstructorStub.firstCall.args[1].includes(

View file

@ -1,6 +1,7 @@
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";
@ -17,6 +18,7 @@ import { ToolsSource } from "./init";
import { isTracedLanguage, Language } from "./languages";
import { Logger } from "./logging";
import * as setupCodeql from "./setup-codeql";
import { EnvVar } from "./shared-environment";
import { toolrunnerErrorCatcher } from "./toolrunner-error-catcher";
import {
getTrapCachingExtractorConfigArgs,
@ -179,7 +181,8 @@ export interface CodeQL {
verbosityFlag: string | undefined,
automationDetailsId: string | undefined,
config: Config,
features: FeatureEnablement
features: FeatureEnablement,
logger: Logger
): Promise<string>;
/**
* Run 'codeql database print-baseline'.
@ -194,7 +197,9 @@ export interface CodeQL {
databaseExportDiagnostics(
databasePath: string,
sarifFile: string,
automationDetailsId: string | undefined
automationDetailsId: string | undefined,
tempDir: string,
logger: Logger
): Promise<void>;
/**
* Run 'codeql diagnostics export'.
@ -866,15 +871,23 @@ export async function getCodeQLForCmd(
verbosityFlag: string,
automationDetailsId: string | undefined,
config: Config,
features: FeatureEnablement
features: FeatureEnablement,
logger: Logger
): Promise<string> {
const shouldExportDiagnostics = await features.getValue(
Feature.ExportDiagnosticsEnabled,
this
);
const codeqlOutputFile = shouldExportDiagnostics
? path.join(config.tempDir, "codeql-intermediate-results.sarif")
: sarifFile;
const codeqlArgs = [
"database",
"interpret-results",
threadsFlag,
"--format=sarif-latest",
verbosityFlag,
`--output=${sarifFile}`,
`--output=${codeqlOutputFile}`,
addSnippetsFlag,
"--print-diagnostics-summary",
"--print-metrics-summary",
@ -895,7 +908,7 @@ export async function getCodeQLForCmd(
) {
codeqlArgs.push("--sarif-add-baseline-file-info");
}
if (await features.getValue(Feature.ExportDiagnosticsEnabled, this)) {
if (shouldExportDiagnostics) {
codeqlArgs.push("--sarif-include-diagnostics");
}
codeqlArgs.push(databasePath);
@ -908,6 +921,15 @@ export async function getCodeQLForCmd(
codeqlArgs,
errorMatchers
);
if (shouldExportDiagnostics) {
let sarif = JSON.parse(
fs.readFileSync(codeqlOutputFile, "utf8")
) as util.SarifFile;
sarif = util.fixInvalidNotifications(sarif, logger);
fs.writeFileSync(sarifFile, JSON.stringify(sarif));
}
return returnState.stdout;
},
async databasePrintBaseline(databasePath: string): Promise<string> {
@ -1003,15 +1025,21 @@ export async function getCodeQLForCmd(
async databaseExportDiagnostics(
databasePath: string,
sarifFile: string,
automationDetailsId: string | undefined
automationDetailsId: string | undefined,
tempDir: string,
logger: Logger
): Promise<void> {
const intermediateSarifFile = path.join(
tempDir,
"codeql-intermediate-results.sarif"
);
const args = [
"database",
"export-diagnostics",
`${databasePath}`,
"--db-cluster", // Database is always a cluster for CodeQL versions that support diagnostics.
"--format=sarif-latest",
`--output=${sarifFile}`,
`--output=${intermediateSarifFile}`,
"--sarif-include-diagnostics", // ExportDiagnosticsEnabled is always true if this command is run.
"-vvv",
...getExtraOptionsFromEnv(["diagnostics", "export"]),
@ -1020,6 +1048,13 @@ export async function getCodeQLForCmd(
args.push("--sarif-category", automationDetailsId);
}
await new toolrunner.ToolRunner(cmd, args).exec();
// Fix invalid notifications in the SARIF file output by CodeQL.
let sarif = JSON.parse(
fs.readFileSync(intermediateSarifFile, "utf8")
) as util.SarifFile;
sarif = util.fixInvalidNotifications(sarif, logger);
fs.writeFileSync(sarifFile, JSON.stringify(sarif));
},
async diagnosticsExport(
sarifFile: string,
@ -1270,3 +1305,17 @@ async function getCodeScanningConfigExportArguments(
}
return [];
}
/**
* Enrich the environment variables with further flags that we cannot
* know the value of until we know what version of CodeQL we're running.
*/
export async function enrichEnvironment(codeql: CodeQL) {
if (await util.codeQlVersionAbove(codeql, CODEQL_VERSION_NEW_TRACING)) {
core.exportVariable(EnvVar.FEATURE_MULTI_LANGUAGE, "false");
core.exportVariable(EnvVar.FEATURE_SANDWICH, "false");
} else {
core.exportVariable(EnvVar.FEATURE_MULTI_LANGUAGE, "true");
core.exportVariable(EnvVar.FEATURE_SANDWICH, "true");
}
}

View file

@ -398,7 +398,9 @@ async function testFailedSarifUpload(
databaseExportDiagnosticsStub.calledOnceWith(
config.dbLocation,
sinon.match.string,
category
category,
sinon.match.any,
sinon.match.any
),
`Actual args were: ${databaseExportDiagnosticsStub.args}`
);

View file

@ -79,7 +79,13 @@ async function maybeUploadFailedSarif(
await codeql.diagnosticsExport(sarifFile, category, config, features);
} else {
// We call 'database export-diagnostics' to find any per-database diagnostics.
await codeql.databaseExportDiagnostics(databasePath, sarifFile, category);
await codeql.databaseExportDiagnostics(
databasePath,
sarifFile,
category,
config.tempDir,
logger
);
}
core.info(`Uploading failed SARIF file ${sarifFile}`);

View file

@ -14,7 +14,11 @@ import {
StatusReportBase,
} from "./actions-util";
import { getGitHubVersion } from "./api-client";
import { CodeQL, CODEQL_VERSION_NEW_TRACING } from "./codeql";
import {
CodeQL,
CODEQL_VERSION_NEW_TRACING,
enrichEnvironment,
} from "./codeql";
import * as configUtils from "./config-utils";
import { Feature, Features } from "./feature-flags";
import {
@ -35,7 +39,6 @@ import {
codeQlVersionAbove,
DEFAULT_DEBUG_ARTIFACT_NAME,
DEFAULT_DEBUG_DATABASE_NAME,
enrichEnvironment,
getMemoryFlagValue,
getMlPoweredJsQueriesStatus,
getRequiredEnvParam,

View file

@ -1,3 +1,39 @@
/**
* Environment variables to be set by codeql-action and used by the
* CLI.
*/
export enum EnvVar {
/**
* Semver of the codeql-action as specified in package.json.
*/
VERSION = "CODEQL_ACTION_VERSION",
/**
* If set to a truthy value, then the codeql-action might combine SARIF
* output from several `interpret-results` runs for the same Language.
*/
FEATURE_SARIF_COMBINE = "CODEQL_ACTION_FEATURE_SARIF_COMBINE",
/**
* If set to the "true" string, then the codeql-action will upload SARIF,
* not the cli.
*/
FEATURE_WILL_UPLOAD = "CODEQL_ACTION_FEATURE_WILL_UPLOAD",
/**
* If set to the "true" string, then the codeql-action is using its
* own deprecated and non-standard way of scanning for multiple
* languages.
*/
FEATURE_MULTI_LANGUAGE = "CODEQL_ACTION_FEATURE_MULTI_LANGUAGE",
/**
* If set to the "true" string, then the codeql-action is using its
* own sandwiched workflow mechanism
*/
FEATURE_SANDWICH = "CODEQL_ACTION_FEATURE_SANDWICH",
}
/**
* Environment variable that is set to true when the CodeQL Action has invoked
* the Go autobuilder.
@ -18,6 +54,13 @@ export const CODEQL_ACTION_TESTING_ENVIRONMENT =
/** Used to disable uploading SARIF results or status reports to the GitHub API */
export const CODEQL_ACTION_TEST_MODE = "CODEQL_ACTION_TEST_MODE";
/**
* Used to disable the SARIF post-processing in the Action that removes duplicate locations from
* notifications in the `run[].invocations[].toolExecutionNotifications` SARIF property.
*/
export const CODEQL_ACTION_DISABLE_DUPLICATE_LOCATION_FIX =
"CODEQL_ACTION_DISABLE_DUPLICATE_LOCATION_FIX";
/**
* The time at which the first action (normally init) started executing.
* If a workflow invokes a different action without first invoking the init

View file

@ -13,7 +13,7 @@ import * as api from "./api-client";
import * as fingerprints from "./fingerprints";
import { Logger } from "./logging";
import { parseRepositoryNwo, RepositoryNwo } from "./repository";
import * as sharedEnv from "./shared-environment";
import { CODEQL_WORKFLOW_STARTED_AT } from "./shared-environment";
import * as util from "./util";
import { SarifFile, SarifResult, SarifRun } from "./util";
import * as workflow from "./workflow";
@ -272,7 +272,7 @@ export function buildPayload(
workflow_run_id: workflowRunID,
checkout_uri: checkoutURI,
environment,
started_at: process.env[sharedEnv.CODEQL_WORKFLOW_STARTED_AT],
started_at: process.env[CODEQL_WORKFLOW_STARTED_AT],
tool_names: toolNames,
base_ref: undefined as undefined | string,
base_sha: undefined as undefined | string,

View file

@ -9,7 +9,7 @@ import * as sinon from "sinon";
import * as api from "./api-client";
import { Config } from "./config-utils";
import { getRunnerLogger } from "./logging";
import { setupTests } from "./testing-utils";
import { getRecordingLogger, LoggedMessage, setupTests } from "./testing-utils";
import * as util from "./util";
setupTests(test);
@ -400,3 +400,60 @@ test("withTimeout doesn't call callback if promise resolves", async (t) => {
t.deepEqual(shortTaskTimedOut, false);
t.deepEqual(result, 99);
});
function createMockSarifWithNotification(
locations: util.SarifLocation[]
): util.SarifFile {
return {
runs: [
{
tool: {
driver: {
name: "CodeQL",
},
},
invocations: [
{
toolExecutionNotifications: [
{
locations,
},
],
},
],
},
],
};
}
const stubLocation: util.SarifLocation = {
physicalLocation: {
artifactLocation: {
uri: "file1",
},
},
};
test("fixInvalidNotifications leaves notifications with unique locations alone", (t) => {
const messages: LoggedMessage[] = [];
const result = util.fixInvalidNotifications(
createMockSarifWithNotification([stubLocation]),
getRecordingLogger(messages)
);
t.deepEqual(result, createMockSarifWithNotification([stubLocation]));
t.is(messages.length, 0);
});
test("fixInvalidNotifications removes duplicate locations", (t) => {
const messages: LoggedMessage[] = [];
const result = util.fixInvalidNotifications(
createMockSarifWithNotification([stubLocation, stubLocation]),
getRecordingLogger(messages)
);
t.deepEqual(result, createMockSarifWithNotification([stubLocation]));
t.is(messages.length, 1);
t.deepEqual(messages[0], {
type: "info",
message: "Removed 1 duplicate locations from SARIF notification objects.",
});
});

View file

@ -10,7 +10,7 @@ import * as semver from "semver";
import { getApiClient, GitHubApiDetails } from "./api-client";
import * as apiCompatibility from "./api-compatibility.json";
import { CodeQL, CODEQL_VERSION_NEW_TRACING } from "./codeql";
import { CodeQL } from "./codeql";
import {
Config,
parsePacksSpecification,
@ -19,7 +19,11 @@ import {
import { Feature, FeatureEnablement } from "./feature-flags";
import { Language } from "./languages";
import { Logger } from "./logging";
import { CODEQL_ACTION_TEST_MODE } from "./shared-environment";
import {
CODEQL_ACTION_DISABLE_DUPLICATE_LOCATION_FIX,
CODEQL_ACTION_TEST_MODE,
EnvVar,
} from "./shared-environment";
/**
* Specifies bundle versions that are known to be broken
@ -58,9 +62,14 @@ export interface SarifRun {
id?: string;
};
artifacts?: string[];
invocations?: SarifInvocation[];
results?: SarifResult[];
}
export interface SarifInvocation {
toolExecutionNotifications?: SarifNotification[];
}
export interface SarifResult {
ruleId?: string;
message?: {
@ -81,6 +90,18 @@ export interface SarifResult {
};
}
export interface SarifNotification {
locations?: SarifLocation[];
}
export interface SarifLocation {
physicalLocation?: {
artifactLocation?: {
uri?: string;
};
};
}
/**
* Get the extra options for the codeql commands.
*/
@ -412,42 +433,6 @@ export function assertNever(value: never): never {
throw new ExhaustivityCheckingError(value);
}
/**
* Environment variables to be set by codeql-action and used by the
* CLI.
*/
export enum EnvVar {
/**
* Semver of the codeql-action as specified in package.json.
*/
VERSION = "CODEQL_ACTION_VERSION",
/**
* If set to a truthy value, then the codeql-action might combine SARIF
* output from several `interpret-results` runs for the same Language.
*/
FEATURE_SARIF_COMBINE = "CODEQL_ACTION_FEATURE_SARIF_COMBINE",
/**
* If set to the "true" string, then the codeql-action will upload SARIF,
* not the cli.
*/
FEATURE_WILL_UPLOAD = "CODEQL_ACTION_FEATURE_WILL_UPLOAD",
/**
* If set to the "true" string, then the codeql-action is using its
* own deprecated and non-standard way of scanning for multiple
* languages.
*/
FEATURE_MULTI_LANGUAGE = "CODEQL_ACTION_FEATURE_MULTI_LANGUAGE",
/**
* If set to the "true" string, then the codeql-action is using its
* own sandwiched workflow mechanism
*/
FEATURE_SANDWICH = "CODEQL_ACTION_FEATURE_SANDWICH",
}
/**
* Set some initial environment variables that we can set even without
* knowing what version of CodeQL we're running.
@ -458,20 +443,6 @@ export function initializeEnvironment(version: string) {
core.exportVariable(EnvVar.FEATURE_WILL_UPLOAD, "true");
}
/**
* Enrich the environment variables with further flags that we cannot
* know the value of until we know what version of CodeQL we're running.
*/
export async function enrichEnvironment(codeql: CodeQL) {
if (await codeQlVersionAbove(codeql, CODEQL_VERSION_NEW_TRACING)) {
core.exportVariable(EnvVar.FEATURE_MULTI_LANGUAGE, "false");
core.exportVariable(EnvVar.FEATURE_SANDWICH, "false");
} else {
core.exportVariable(EnvVar.FEATURE_MULTI_LANGUAGE, "true");
core.exportVariable(EnvVar.FEATURE_SANDWICH, "true");
}
}
/**
* Get an environment parameter, but throw an error if it is not set.
*/
@ -828,3 +799,82 @@ export function parseMatrixInput(
}
return JSON.parse(matrixInput);
}
function removeDuplicateLocations(locations: SarifLocation[]): SarifLocation[] {
const newJsonLocations = new Set<string>();
return locations.filter((location) => {
const jsonLocation = JSON.stringify(location);
if (!newJsonLocations.has(jsonLocation)) {
newJsonLocations.add(jsonLocation);
return true;
}
return false;
});
}
export function fixInvalidNotifications(
sarif: SarifFile,
logger: Logger
): SarifFile {
if (process.env[CODEQL_ACTION_DISABLE_DUPLICATE_LOCATION_FIX] === "true") {
logger.info(
"SARIF notification object duplicate location fix disabled by the " +
`${CODEQL_ACTION_DISABLE_DUPLICATE_LOCATION_FIX} environment variable.`
);
return sarif;
}
if (!(sarif.runs instanceof Array)) {
return sarif;
}
// Ensure that the array of locations for each SARIF notification contains unique locations.
// This is a workaround for a bug in the CodeQL CLI that causes duplicate locations to be
// emitted in some cases.
let numDuplicateLocationsRemoved = 0;
const newSarif = {
...sarif,
runs: sarif.runs.map((run) => {
if (
run.tool?.driver?.name !== "CodeQL" ||
!(run.invocations instanceof Array)
) {
return run;
}
return {
...run,
invocations: run.invocations.map((invocation) => {
if (!(invocation.toolExecutionNotifications instanceof Array)) {
return invocation;
}
return {
...invocation,
toolExecutionNotifications:
invocation.toolExecutionNotifications.map((notification) => {
if (!(notification.locations instanceof Array)) {
return notification;
}
const newLocations = removeDuplicateLocations(
notification.locations
);
numDuplicateLocationsRemoved +=
notification.locations.length - newLocations.length;
return {
...notification,
locations: newLocations,
};
}),
};
}),
};
}),
};
if (numDuplicateLocationsRemoved > 0) {
logger.info(
`Removed ${numDuplicateLocationsRemoved} duplicate locations from SARIF notification ` +
"objects."
);
}
return newSarif;
}