Compare commits

...

25 Commits

Author SHA1 Message Date
Henry Mercer
ccf74c9479 Merge pull request #2275 from github/update-v3.25.4-4b812a5df
Merge main into releases/v3
2024-05-08 13:30:22 +01:00
github-actions[bot]
4fdf4ac628 Update changelog for v3.25.4 2024-05-08 11:29:41 +00:00
Henry Mercer
4b812a5dff Merge pull request #2270 from github/update-bundle/codeql-bundle-v2.17.2
Update default bundle to 2.17.2
2024-05-07 12:13:33 +01:00
Marco Gario
1e21373a75 Merge pull request #2272 from github/marcogario-patch-1
Fix broken link to deprecation changelog
2024-05-06 21:07:46 +02:00
Marco Gario
4673d41da1 Build js files 2024-05-06 18:44:55 +00:00
Marco Gario
65297ef0b0 Update link to deprecation changelog 2024-05-06 20:39:22 +02:00
Koen Vlaswinkel
84d6ead480 Merge pull request #2271 from github/koesie10/remove-cli-sarif-merge-ff
Remove CLI SARIF merge feature flag
2024-05-03 16:40:46 +02:00
Koen Vlaswinkel
b20bf5914d Remove CLI SARIF merge feature flag 2024-05-03 15:14:12 +02:00
Koen Vlaswinkel
93b8232a39 Merge pull request #2265 from github/koesie10/deprecate-merge
Add deprecation warning for merging SARIF files with non-unique categories
2024-05-03 10:23:10 +02:00
github-actions[bot]
ee63da2847 Add changelog note 2024-05-02 20:40:31 +00:00
github-actions[bot]
e62cc70a8b Update default bundle to codeql-bundle-v2.17.2 2024-05-02 20:40:26 +00:00
Koen Vlaswinkel
5d274be858 Update CodeQL deprecation message 2024-05-02 14:02:42 +02:00
Koen Vlaswinkel
3a471a06fa Update comment 2024-05-02 14:01:44 +02:00
Koen Vlaswinkel
725ed4139d Add tests for shouldShowCombineSarifFilesDeprecationWarning 2024-05-02 10:20:11 +02:00
Koen Vlaswinkel
1de9b371a1 Clarify name of function 2024-05-02 10:01:11 +02:00
Koen Vlaswinkel
757fcd3d21 Remove unnecessary optional chaining 2024-05-02 10:00:29 +02:00
Koen Vlaswinkel
40f70f96b1 Extract more information message 2024-05-02 09:59:52 +02:00
Angela P Wen
41857bab35 Textually replace CodeQL version in package.json (#2269)
Textually replace CodeQL version in `package.json` instead of using `npm version`, which occasionally fails due to merge conflicts that arise in the `package.json` process.

Co-authored-by: Henry Mercer <henrymercer@github.com>
2024-05-01 10:10:05 -07:00
Koen Vlaswinkel
b3225af51b Mention GHES 3.18 as removal version on GHES 2024-04-26 14:38:20 +02:00
Koen Vlaswinkel
905f9b0083 Only show deprecation warning on GHES 3.14+ 2024-04-26 14:38:06 +02:00
Koen Vlaswinkel
80394dcc32 Hide deprecation warning if feature flag is not set 2024-04-26 14:37:27 +02:00
Koen Vlaswinkel
7c29971135 Add combine_sarif_files_deprecation_warning_enabled feature flag 2024-04-26 14:36:55 +02:00
Koen Vlaswinkel
a5e49d1544 Extract check for combine SARIF files deprecation warning 2024-04-26 14:36:54 +02:00
Koen Vlaswinkel
24acd7711e Set correct changelog URL 2024-04-26 14:23:51 +02:00
Koen Vlaswinkel
8b0dfa84c7 Add deprecation warning for merging SARIF files with non-unique categories 2024-04-26 14:22:30 +02:00
15 changed files with 378 additions and 54 deletions

View File

@@ -1,5 +1,6 @@
import argparse import argparse
import datetime import datetime
import fileinput
import re import re
from github import Github from github import Github
import json import json
@@ -171,6 +172,19 @@ def get_current_version():
with open('package.json', 'r') as f: with open('package.json', 'r') as f:
return json.load(f)['version'] return json.load(f)['version']
# `npm version` doesn't always work because of merge conflicts, so we
# replace the version in package.json textually.
def replace_version_package_json(prev_version, new_version):
prev_line_is_codeql = False
for line in fileinput.input('package.json', inplace = True, encoding='utf-8'):
if prev_line_is_codeql and f'\"version\": \"{prev_version}\"' in line:
print(line.replace(prev_version, new_version), end='')
else:
prev_line_is_codeql = False
print(line, end='')
if '\"name\": \"codeql\",' in line:
prev_line_is_codeql = True
def get_today_string(): def get_today_string():
today = datetime.datetime.today() today = datetime.datetime.today()
return '{:%d %b %Y}'.format(today) return '{:%d %b %Y}'.format(today)
@@ -374,9 +388,9 @@ def main():
run_git('commit', '--no-edit') run_git('commit', '--no-edit')
# Migrate the package version number from a vLatest version number to a vOlder version number # Migrate the package version number from a vLatest version number to a vOlder version number
print(f'Setting version number to {version}') print(f'Setting version number to {version} in package.json')
subprocess.check_output(['npm', 'version', version, '--no-git-tag-version']) replace_version_package_json(get_current_version(), version) # We rely on the `Update dependencies` workflow to update package-lock.json
run_git('add', 'package.json', 'package-lock.json') run_git('add', 'package.json')
# Migrate the changelog notes from vLatest version numbers to vOlder version numbers # Migrate the changelog notes from vLatest version numbers to vOlder version numbers
print(f'Migrating changelog notes from v{source_branch_major_version} to v{target_branch_major_version}') print(f'Migrating changelog notes from v{source_branch_major_version} to v{target_branch_major_version}')

View File

@@ -4,9 +4,9 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th
Note that the only difference between `v2` and `v3` of the CodeQL Action is the node version they support, with `v3` running on node 20 while we continue to release `v2` to support running on node 16. For example `3.22.11` was the first `v3` release and is functionally identical to `2.22.11`. This approach ensures an easy way to track exactly which features are included in different versions, indicated by the minor and patch version numbers. Note that the only difference between `v2` and `v3` of the CodeQL Action is the node version they support, with `v3` running on node 20 while we continue to release `v2` to support running on node 16. For example `3.22.11` was the first `v3` release and is functionally identical to `2.22.11`. This approach ensures an easy way to track exactly which features are included in different versions, indicated by the minor and patch version numbers.
## [UNRELEASED] ## 3.25.4 - 08 May 2024
No user facing changes. - Update default CodeQL bundle version to 2.17.2. [#2270](https://github.com/github/codeql-action/pull/2270)
## 3.25.3 - 25 Apr 2024 ## 3.25.3 - 25 Apr 2024

View File

@@ -1,6 +1,6 @@
{ {
"bundleVersion": "codeql-bundle-v2.17.1", "bundleVersion": "codeql-bundle-v2.17.2",
"cliVersion": "2.17.1", "cliVersion": "2.17.2",
"priorBundleVersion": "codeql-bundle-v2.17.0", "priorBundleVersion": "codeql-bundle-v2.17.1",
"priorCliVersion": "2.17.0" "priorCliVersion": "2.17.1"
} }

8
lib/feature-flags.js generated
View File

@@ -50,7 +50,7 @@ exports.CODEQL_VERSION_FINE_GRAINED_PARALLELISM = "2.15.1";
var Feature; var Feature;
(function (Feature) { (function (Feature) {
Feature["AutobuildDirectTracingEnabled"] = "autobuild_direct_tracing_enabled"; Feature["AutobuildDirectTracingEnabled"] = "autobuild_direct_tracing_enabled";
Feature["CliSarifMerge"] = "cli_sarif_merge_enabled"; Feature["CombineSarifFilesDeprecationWarning"] = "combine_sarif_files_deprecation_warning_enabled";
Feature["CppDependencyInstallation"] = "cpp_dependency_installation_enabled"; Feature["CppDependencyInstallation"] = "cpp_dependency_installation_enabled";
Feature["CppTrapCachingEnabled"] = "cpp_trap_caching_enabled"; Feature["CppTrapCachingEnabled"] = "cpp_trap_caching_enabled";
Feature["DisableJavaBuildlessEnabled"] = "disable_java_buildless_enabled"; Feature["DisableJavaBuildlessEnabled"] = "disable_java_buildless_enabled";
@@ -65,9 +65,9 @@ exports.featureConfig = {
toolsFeature: tools_features_1.ToolsFeature.TraceCommandUseBuildMode, toolsFeature: tools_features_1.ToolsFeature.TraceCommandUseBuildMode,
defaultValue: false, defaultValue: false,
}, },
[Feature.CliSarifMerge]: { [Feature.CombineSarifFilesDeprecationWarning]: {
envVar: "CODEQL_ACTION_CLI_SARIF_MERGE", envVar: "CODEQL_ACTION_COMBINE_SARIF_FILES_DEPRECATION_WARNING",
// This is guarded by a `supportsFeature` check rather than by a version check. // Independent of the CLI version.
minimumVersion: undefined, minimumVersion: undefined,
defaultValue: false, defaultValue: false,
}, },

File diff suppressed because one or more lines are too long

76
lib/upload-lib.js generated
View File

@@ -26,13 +26,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.InvalidSarifUploadError = exports.validateUniqueCategory = exports.waitForProcessing = exports.buildPayload = exports.validateSarifFileSchema = exports.uploadFromActions = exports.findSarifFilesInDir = exports.populateRunAutomationDetails = void 0; exports.InvalidSarifUploadError = exports.validateUniqueCategory = exports.waitForProcessing = exports.buildPayload = exports.validateSarifFileSchema = exports.uploadFromActions = exports.findSarifFilesInDir = exports.populateRunAutomationDetails = exports.shouldShowCombineSarifFilesDeprecationWarning = void 0;
const fs = __importStar(require("fs")); const fs = __importStar(require("fs"));
const path = __importStar(require("path")); const path = __importStar(require("path"));
const zlib_1 = __importDefault(require("zlib")); const zlib_1 = __importDefault(require("zlib"));
const core = __importStar(require("@actions/core")); const core = __importStar(require("@actions/core"));
const file_url_1 = __importDefault(require("file-url")); const file_url_1 = __importDefault(require("file-url"));
const jsonschema = __importStar(require("jsonschema")); const jsonschema = __importStar(require("jsonschema"));
const semver = __importStar(require("semver"));
const actionsUtil = __importStar(require("./actions-util")); const actionsUtil = __importStar(require("./actions-util"));
const actions_util_1 = require("./actions-util"); const actions_util_1 = require("./actions-util");
const api = __importStar(require("./api-client")); const api = __importStar(require("./api-client"));
@@ -73,14 +74,58 @@ function combineSarifFiles(sarifFiles, logger) {
} }
/** /**
* Checks whether all the runs in the given SARIF files were produced by CodeQL. * Checks whether all the runs in the given SARIF files were produced by CodeQL.
* @param sarifFiles The list of SARIF files to check. * @param sarifObjects The list of SARIF objects to check.
*/ */
function areAllRunsProducedByCodeQL(sarifFiles) { function areAllRunsProducedByCodeQL(sarifObjects) {
return sarifFiles.every((sarifFile) => { return sarifObjects.every((sarifObject) => {
const sarifObject = JSON.parse(fs.readFileSync(sarifFile, "utf8"));
return sarifObject.runs?.every((run) => run.tool?.driver?.name === "CodeQL"); return sarifObject.runs?.every((run) => run.tool?.driver?.name === "CodeQL");
}); });
} }
function createRunKey(run) {
return {
name: run.tool?.driver?.name,
fullName: run.tool?.driver?.fullName,
version: run.tool?.driver?.version,
semanticVersion: run.tool?.driver?.semanticVersion,
guid: run.tool?.driver?.guid,
automationId: run.automationDetails?.id,
};
}
/**
* Checks whether all runs in the given SARIF files are unique (based on the
* criteria used by Code Scanning to determine analysis categories).
* @param sarifObjects The list of SARIF objects to check.
*/
function areAllRunsUnique(sarifObjects) {
const keys = new Set();
for (const sarifObject of sarifObjects) {
for (const run of sarifObject.runs) {
const key = JSON.stringify(createRunKey(run));
// If the key already exists, the runs are not unique.
if (keys.has(key)) {
return false;
}
keys.add(key);
}
}
return true;
}
// Checks whether the deprecation warning for combining SARIF files should be shown.
async function shouldShowCombineSarifFilesDeprecationWarning(sarifObjects, features, githubVersion) {
if (!(await features.getValue(feature_flags_1.Feature.CombineSarifFilesDeprecationWarning))) {
return false;
}
// Do not show this warning on GHES versions before 3.14.0
if (githubVersion.type === util_1.GitHubVariant.GHES &&
semver.lt(githubVersion.version, "3.14.0")) {
return false;
}
// Only give a deprecation warning when not all runs are unique and
// we haven't already shown the warning.
return (!areAllRunsUnique(sarifObjects) &&
!process.env.CODEQL_MERGE_SARIF_DEPRECATION_WARNING);
}
exports.shouldShowCombineSarifFilesDeprecationWarning = shouldShowCombineSarifFilesDeprecationWarning;
// Takes a list of paths to sarif files and combines them together using the // Takes a list of paths to sarif files and combines them together using the
// CLI `github merge-results` command when all SARIF files are produced by // CLI `github merge-results` command when all SARIF files are produced by
// CodeQL. Otherwise, it will fall back to combining the files in the action. // CodeQL. Otherwise, it will fall back to combining the files in the action.
@@ -90,8 +135,19 @@ async function combineSarifFilesUsingCLI(sarifFiles, gitHubVersion, features, lo
if (sarifFiles.length === 1) { if (sarifFiles.length === 1) {
return JSON.parse(fs.readFileSync(sarifFiles[0], "utf8")); return JSON.parse(fs.readFileSync(sarifFiles[0], "utf8"));
} }
if (!areAllRunsProducedByCodeQL(sarifFiles)) { const sarifObjects = sarifFiles.map((sarifFile) => {
return JSON.parse(fs.readFileSync(sarifFile, "utf8"));
});
const deprecationWarningMessage = gitHubVersion.type === util_1.GitHubVariant.GHES
? "and will be removed in GitHub Enterprise Server 3.18"
: "and will be removed on June 4, 2025";
const deprecationMoreInformationMessage = "For more information, see https://github.blog/changelog/2024-05-06-code-scanning-will-stop-combining-runs-from-a-single-upload";
if (!areAllRunsProducedByCodeQL(sarifObjects)) {
logger.debug("Not all SARIF files were produced by CodeQL. Merging files in the action."); logger.debug("Not all SARIF files were produced by CodeQL. Merging files in the action.");
if (await shouldShowCombineSarifFilesDeprecationWarning(sarifObjects, features, gitHubVersion)) {
logger.warning(`Uploading multiple SARIF runs with the same category is deprecated ${deprecationWarningMessage}. Please update your workflow to upload a single run per category. ${deprecationMoreInformationMessage}`);
core.exportVariable("CODEQL_MERGE_SARIF_DEPRECATION_WARNING", "true");
}
// If not, use the naive method of combining the files. // If not, use the naive method of combining the files.
return combineSarifFiles(sarifFiles, logger); return combineSarifFiles(sarifFiles, logger);
} }
@@ -119,6 +175,10 @@ async function combineSarifFilesUsingCLI(sarifFiles, gitHubVersion, features, lo
} }
if (!(await codeQL.supportsFeature(tools_features_1.ToolsFeature.SarifMergeRunsFromEqualCategory))) { if (!(await codeQL.supportsFeature(tools_features_1.ToolsFeature.SarifMergeRunsFromEqualCategory))) {
logger.warning("The CodeQL CLI does not support merging SARIF files. Merging files in the action."); logger.warning("The CodeQL CLI does not support merging SARIF files. Merging files in the action.");
if (await shouldShowCombineSarifFilesDeprecationWarning(sarifObjects, features, gitHubVersion)) {
logger.warning(`Uploading multiple CodeQL runs with the same category is deprecated ${deprecationWarningMessage} for CodeQL CLI 2.16.6 and earlier. Please update your CodeQL CLI version or update your workflow to set a distinct category for each CodeQL run. ${deprecationMoreInformationMessage}`);
core.exportVariable("CODEQL_MERGE_SARIF_DEPRECATION_WARNING", "true");
}
return combineSarifFiles(sarifFiles, logger); return combineSarifFiles(sarifFiles, logger);
} }
const baseTempDir = path.resolve(tempDir, "combined-sarif"); const baseTempDir = path.resolve(tempDir, "combined-sarif");
@@ -341,9 +401,7 @@ async function uploadFiles(sarifFiles, repositoryNwo, commitOid, ref, analysisKe
for (const file of sarifFiles) { for (const file of sarifFiles) {
validateSarifFileSchema(file, logger); validateSarifFileSchema(file, logger);
} }
let sarif = (await features.getValue(feature_flags_1.Feature.CliSarifMerge)) let sarif = await combineSarifFilesUsingCLI(sarifFiles, gitHubVersion, features, logger);
? await combineSarifFilesUsingCLI(sarifFiles, gitHubVersion, features, logger)
: combineSarifFiles(sarifFiles, logger);
sarif = await fingerprints.addFingerprints(sarif, sourceRoot, logger); sarif = await fingerprints.addFingerprints(sarif, sourceRoot, logger);
sarif = populateRunAutomationDetails(sarif, category, analysisKey, environment); sarif = populateRunAutomationDetails(sarif, category, analysisKey, environment);
const toolNames = util.getToolNames(sarif); const toolNames = util.getToolNames(sarif);

File diff suppressed because one or more lines are too long

44
lib/upload-lib.test.js generated
View File

@@ -29,6 +29,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
const fs = __importStar(require("fs")); const fs = __importStar(require("fs"));
const path = __importStar(require("path")); const path = __importStar(require("path"));
const ava_1 = __importDefault(require("ava")); const ava_1 = __importDefault(require("ava"));
const feature_flags_1 = require("./feature-flags");
const logging_1 = require("./logging"); const logging_1 = require("./logging");
const testing_utils_1 = require("./testing-utils"); const testing_utils_1 = require("./testing-utils");
const uploadLib = __importStar(require("./upload-lib")); const uploadLib = __importStar(require("./upload-lib"));
@@ -195,6 +196,49 @@ ava_1.default.beforeEach(() => {
t.deepEqual(loggedMessages.length, 2); t.deepEqual(loggedMessages.length, 2);
t.deepEqual(loggedMessages[1], "Warning: 'not a valid URI' is not a valid URI in 'instance.runs[0].results[0].locations[0].physicalLocation.artifactLocation.uri'."); t.deepEqual(loggedMessages[1], "Warning: 'not a valid URI' is not a valid URI in 'instance.runs[0].results[0].locations[0].physicalLocation.artifactLocation.uri'.");
}); });
(0, ava_1.default)("shouldShowCombineSarifFilesDeprecationWarning when on dotcom with feature flag", async (t) => {
t.true(await uploadLib.shouldShowCombineSarifFilesDeprecationWarning([createMockSarif("abc", "def"), createMockSarif("abc", "def")], (0, testing_utils_1.createFeatures)([feature_flags_1.Feature.CombineSarifFilesDeprecationWarning]), {
type: util_1.GitHubVariant.DOTCOM,
}));
});
(0, ava_1.default)("shouldShowCombineSarifFilesDeprecationWarning without feature flag", async (t) => {
t.false(await uploadLib.shouldShowCombineSarifFilesDeprecationWarning([createMockSarif("abc", "def"), createMockSarif("abc", "def")], (0, testing_utils_1.createFeatures)([]), {
type: util_1.GitHubVariant.DOTCOM,
}));
});
(0, ava_1.default)("shouldShowCombineSarifFilesDeprecationWarning when on GHES 3.13", async (t) => {
t.false(await uploadLib.shouldShowCombineSarifFilesDeprecationWarning([createMockSarif("abc", "def"), createMockSarif("abc", "def")], (0, testing_utils_1.createFeatures)([feature_flags_1.Feature.CombineSarifFilesDeprecationWarning]), {
type: util_1.GitHubVariant.GHES,
version: "3.13.2",
}));
});
(0, ava_1.default)("shouldShowCombineSarifFilesDeprecationWarning when on GHES 3.14", async (t) => {
t.true(await uploadLib.shouldShowCombineSarifFilesDeprecationWarning([createMockSarif("abc", "def"), createMockSarif("abc", "def")], (0, testing_utils_1.createFeatures)([feature_flags_1.Feature.CombineSarifFilesDeprecationWarning]), {
type: util_1.GitHubVariant.GHES,
version: "3.14.0",
}));
});
(0, ava_1.default)("shouldShowCombineSarifFilesDeprecationWarning with only 1 run", async (t) => {
t.false(await uploadLib.shouldShowCombineSarifFilesDeprecationWarning([createMockSarif("abc", "def")], (0, testing_utils_1.createFeatures)([feature_flags_1.Feature.CombineSarifFilesDeprecationWarning]), {
type: util_1.GitHubVariant.DOTCOM,
}));
});
(0, ava_1.default)("shouldShowCombineSarifFilesDeprecationWarning with distinct categories", async (t) => {
t.false(await uploadLib.shouldShowCombineSarifFilesDeprecationWarning([createMockSarif("abc", "def"), createMockSarif("def", "def")], (0, testing_utils_1.createFeatures)([feature_flags_1.Feature.CombineSarifFilesDeprecationWarning]), {
type: util_1.GitHubVariant.DOTCOM,
}));
});
(0, ava_1.default)("shouldShowCombineSarifFilesDeprecationWarning with distinct tools", async (t) => {
t.false(await uploadLib.shouldShowCombineSarifFilesDeprecationWarning([createMockSarif("abc", "abc"), createMockSarif("abc", "def")], (0, testing_utils_1.createFeatures)([feature_flags_1.Feature.CombineSarifFilesDeprecationWarning]), {
type: util_1.GitHubVariant.DOTCOM,
}));
});
(0, ava_1.default)("shouldShowCombineSarifFilesDeprecationWarning when environment variable is already set", async (t) => {
process.env["CODEQL_MERGE_SARIF_DEPRECATION_WARNING"] = "true";
t.false(await uploadLib.shouldShowCombineSarifFilesDeprecationWarning([createMockSarif("abc", "def"), createMockSarif("abc", "def")], (0, testing_utils_1.createFeatures)([feature_flags_1.Feature.CombineSarifFilesDeprecationWarning]), {
type: util_1.GitHubVariant.DOTCOM,
}));
});
function createMockSarif(id, tool) { function createMockSarif(id, tool) {
return { return {
runs: [ runs: [

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
{ {
"bundleVersion": "codeql-bundle-v2.17.1", "bundleVersion": "codeql-bundle-v2.17.2",
"cliVersion": "2.17.1", "cliVersion": "2.17.2",
"priorBundleVersion": "codeql-bundle-v2.17.0", "priorBundleVersion": "codeql-bundle-v2.17.1",
"priorCliVersion": "2.17.0" "priorCliVersion": "2.17.1"
} }

View File

@@ -46,7 +46,7 @@ export interface FeatureEnablement {
*/ */
export enum Feature { export enum Feature {
AutobuildDirectTracingEnabled = "autobuild_direct_tracing_enabled", AutobuildDirectTracingEnabled = "autobuild_direct_tracing_enabled",
CliSarifMerge = "cli_sarif_merge_enabled", CombineSarifFilesDeprecationWarning = "combine_sarif_files_deprecation_warning_enabled",
CppDependencyInstallation = "cpp_dependency_installation_enabled", CppDependencyInstallation = "cpp_dependency_installation_enabled",
CppTrapCachingEnabled = "cpp_trap_caching_enabled", CppTrapCachingEnabled = "cpp_trap_caching_enabled",
DisableJavaBuildlessEnabled = "disable_java_buildless_enabled", DisableJavaBuildlessEnabled = "disable_java_buildless_enabled",
@@ -85,9 +85,9 @@ export const featureConfig: Record<
toolsFeature: ToolsFeature.TraceCommandUseBuildMode, toolsFeature: ToolsFeature.TraceCommandUseBuildMode,
defaultValue: false, defaultValue: false,
}, },
[Feature.CliSarifMerge]: { [Feature.CombineSarifFilesDeprecationWarning]: {
envVar: "CODEQL_ACTION_CLI_SARIF_MERGE", envVar: "CODEQL_ACTION_COMBINE_SARIF_FILES_DEPRECATION_WARNING",
// This is guarded by a `supportsFeature` check rather than by a version check. // Independent of the CLI version.
minimumVersion: undefined, minimumVersion: undefined,
defaultValue: false, defaultValue: false,
}, },

View File

@@ -3,10 +3,11 @@ import * as path from "path";
import test from "ava"; import test from "ava";
import { Feature } from "./feature-flags";
import { getRunnerLogger, Logger } from "./logging"; import { getRunnerLogger, Logger } from "./logging";
import { setupTests } from "./testing-utils"; import { createFeatures, setupTests } from "./testing-utils";
import * as uploadLib from "./upload-lib"; import * as uploadLib from "./upload-lib";
import { initializeEnvironment, withTmpDir } from "./util"; import { GitHubVariant, initializeEnvironment, withTmpDir } from "./util";
setupTests(test); setupTests(test);
@@ -324,6 +325,106 @@ test("accept results with invalid artifactLocation.uri value", (t) => {
); );
}); });
test("shouldShowCombineSarifFilesDeprecationWarning when on dotcom with feature flag", async (t) => {
t.true(
await uploadLib.shouldShowCombineSarifFilesDeprecationWarning(
[createMockSarif("abc", "def"), createMockSarif("abc", "def")],
createFeatures([Feature.CombineSarifFilesDeprecationWarning]),
{
type: GitHubVariant.DOTCOM,
},
),
);
});
test("shouldShowCombineSarifFilesDeprecationWarning without feature flag", async (t) => {
t.false(
await uploadLib.shouldShowCombineSarifFilesDeprecationWarning(
[createMockSarif("abc", "def"), createMockSarif("abc", "def")],
createFeatures([]),
{
type: GitHubVariant.DOTCOM,
},
),
);
});
test("shouldShowCombineSarifFilesDeprecationWarning when on GHES 3.13", async (t) => {
t.false(
await uploadLib.shouldShowCombineSarifFilesDeprecationWarning(
[createMockSarif("abc", "def"), createMockSarif("abc", "def")],
createFeatures([Feature.CombineSarifFilesDeprecationWarning]),
{
type: GitHubVariant.GHES,
version: "3.13.2",
},
),
);
});
test("shouldShowCombineSarifFilesDeprecationWarning when on GHES 3.14", async (t) => {
t.true(
await uploadLib.shouldShowCombineSarifFilesDeprecationWarning(
[createMockSarif("abc", "def"), createMockSarif("abc", "def")],
createFeatures([Feature.CombineSarifFilesDeprecationWarning]),
{
type: GitHubVariant.GHES,
version: "3.14.0",
},
),
);
});
test("shouldShowCombineSarifFilesDeprecationWarning with only 1 run", async (t) => {
t.false(
await uploadLib.shouldShowCombineSarifFilesDeprecationWarning(
[createMockSarif("abc", "def")],
createFeatures([Feature.CombineSarifFilesDeprecationWarning]),
{
type: GitHubVariant.DOTCOM,
},
),
);
});
test("shouldShowCombineSarifFilesDeprecationWarning with distinct categories", async (t) => {
t.false(
await uploadLib.shouldShowCombineSarifFilesDeprecationWarning(
[createMockSarif("abc", "def"), createMockSarif("def", "def")],
createFeatures([Feature.CombineSarifFilesDeprecationWarning]),
{
type: GitHubVariant.DOTCOM,
},
),
);
});
test("shouldShowCombineSarifFilesDeprecationWarning with distinct tools", async (t) => {
t.false(
await uploadLib.shouldShowCombineSarifFilesDeprecationWarning(
[createMockSarif("abc", "abc"), createMockSarif("abc", "def")],
createFeatures([Feature.CombineSarifFilesDeprecationWarning]),
{
type: GitHubVariant.DOTCOM,
},
),
);
});
test("shouldShowCombineSarifFilesDeprecationWarning when environment variable is already set", async (t) => {
process.env["CODEQL_MERGE_SARIF_DEPRECATION_WARNING"] = "true";
t.false(
await uploadLib.shouldShowCombineSarifFilesDeprecationWarning(
[createMockSarif("abc", "def"), createMockSarif("abc", "def")],
createFeatures([Feature.CombineSarifFilesDeprecationWarning]),
{
type: GitHubVariant.DOTCOM,
},
),
);
});
function createMockSarif(id?: string, tool?: string) { function createMockSarif(id?: string, tool?: string) {
return { return {
runs: [ runs: [

View File

@@ -6,6 +6,7 @@ import * as core from "@actions/core";
import { OctokitResponse } from "@octokit/types"; import { OctokitResponse } from "@octokit/types";
import fileUrl from "file-url"; import fileUrl from "file-url";
import * as jsonschema from "jsonschema"; import * as jsonschema from "jsonschema";
import * as semver from "semver";
import * as actionsUtil from "./actions-util"; import * as actionsUtil from "./actions-util";
import { getOptionalInput, getRequiredInput } from "./actions-util"; import { getOptionalInput, getRequiredInput } from "./actions-util";
@@ -14,7 +15,7 @@ import { getGitHubVersion, wrapApiConfigurationError } from "./api-client";
import { CodeQL, getCodeQL } from "./codeql"; import { CodeQL, getCodeQL } from "./codeql";
import { getConfig } from "./config-utils"; import { getConfig } from "./config-utils";
import { EnvVar } from "./environment"; import { EnvVar } from "./environment";
import { Feature, Features } from "./feature-flags"; import { Feature, FeatureEnablement, Features } from "./feature-flags";
import * as fingerprints from "./fingerprints"; import * as fingerprints from "./fingerprints";
import { initCodeQL } from "./init"; import { initCodeQL } from "./init";
import { Logger } from "./logging"; import { Logger } from "./logging";
@@ -24,8 +25,10 @@ import * as util from "./util";
import { import {
ConfigurationError, ConfigurationError,
getRequiredEnvParam, getRequiredEnvParam,
GitHubVariant,
GitHubVersion, GitHubVersion,
SarifFile, SarifFile,
SarifRun,
wrapError, wrapError,
} from "./util"; } from "./util";
@@ -65,20 +68,86 @@ function combineSarifFiles(sarifFiles: string[], logger: Logger): SarifFile {
/** /**
* Checks whether all the runs in the given SARIF files were produced by CodeQL. * Checks whether all the runs in the given SARIF files were produced by CodeQL.
* @param sarifFiles The list of SARIF files to check. * @param sarifObjects The list of SARIF objects to check.
*/ */
function areAllRunsProducedByCodeQL(sarifFiles: string[]): boolean { function areAllRunsProducedByCodeQL(sarifObjects: SarifFile[]): boolean {
return sarifFiles.every((sarifFile) => { return sarifObjects.every((sarifObject) => {
const sarifObject = JSON.parse(
fs.readFileSync(sarifFile, "utf8"),
) as SarifFile;
return sarifObject.runs?.every( return sarifObject.runs?.every(
(run) => run.tool?.driver?.name === "CodeQL", (run) => run.tool?.driver?.name === "CodeQL",
); );
}); });
} }
type SarifRunKey = {
name: string | undefined;
fullName: string | undefined;
version: string | undefined;
semanticVersion: string | undefined;
guid: string | undefined;
automationId: string | undefined;
};
function createRunKey(run: SarifRun): SarifRunKey {
return {
name: run.tool?.driver?.name,
fullName: run.tool?.driver?.fullName,
version: run.tool?.driver?.version,
semanticVersion: run.tool?.driver?.semanticVersion,
guid: run.tool?.driver?.guid,
automationId: run.automationDetails?.id,
};
}
/**
* Checks whether all runs in the given SARIF files are unique (based on the
* criteria used by Code Scanning to determine analysis categories).
* @param sarifObjects The list of SARIF objects to check.
*/
function areAllRunsUnique(sarifObjects: SarifFile[]): boolean {
const keys = new Set<string>();
for (const sarifObject of sarifObjects) {
for (const run of sarifObject.runs) {
const key = JSON.stringify(createRunKey(run));
// If the key already exists, the runs are not unique.
if (keys.has(key)) {
return false;
}
keys.add(key);
}
}
return true;
}
// Checks whether the deprecation warning for combining SARIF files should be shown.
export async function shouldShowCombineSarifFilesDeprecationWarning(
sarifObjects: util.SarifFile[],
features: FeatureEnablement,
githubVersion: GitHubVersion,
) {
if (!(await features.getValue(Feature.CombineSarifFilesDeprecationWarning))) {
return false;
}
// Do not show this warning on GHES versions before 3.14.0
if (
githubVersion.type === GitHubVariant.GHES &&
semver.lt(githubVersion.version, "3.14.0")
) {
return false;
}
// Only give a deprecation warning when not all runs are unique and
// we haven't already shown the warning.
return (
!areAllRunsUnique(sarifObjects) &&
!process.env.CODEQL_MERGE_SARIF_DEPRECATION_WARNING
);
}
// Takes a list of paths to sarif files and combines them together using the // Takes a list of paths to sarif files and combines them together using the
// CLI `github merge-results` command when all SARIF files are produced by // CLI `github merge-results` command when all SARIF files are produced by
// CodeQL. Otherwise, it will fall back to combining the files in the action. // CodeQL. Otherwise, it will fall back to combining the files in the action.
@@ -86,7 +155,7 @@ function areAllRunsProducedByCodeQL(sarifFiles: string[]): boolean {
async function combineSarifFilesUsingCLI( async function combineSarifFilesUsingCLI(
sarifFiles: string[], sarifFiles: string[],
gitHubVersion: GitHubVersion, gitHubVersion: GitHubVersion,
features: Features, features: FeatureEnablement,
logger: Logger, logger: Logger,
): Promise<SarifFile> { ): Promise<SarifFile> {
logger.info("Combining SARIF files using the CodeQL CLI"); logger.info("Combining SARIF files using the CodeQL CLI");
@@ -94,11 +163,35 @@ async function combineSarifFilesUsingCLI(
return JSON.parse(fs.readFileSync(sarifFiles[0], "utf8")) as SarifFile; return JSON.parse(fs.readFileSync(sarifFiles[0], "utf8")) as SarifFile;
} }
if (!areAllRunsProducedByCodeQL(sarifFiles)) { const sarifObjects = sarifFiles.map((sarifFile): SarifFile => {
return JSON.parse(fs.readFileSync(sarifFile, "utf8")) as SarifFile;
});
const deprecationWarningMessage =
gitHubVersion.type === GitHubVariant.GHES
? "and will be removed in GitHub Enterprise Server 3.18"
: "and will be removed on June 4, 2025";
const deprecationMoreInformationMessage =
"For more information, see https://github.blog/changelog/2024-05-06-code-scanning-will-stop-combining-runs-from-a-single-upload";
if (!areAllRunsProducedByCodeQL(sarifObjects)) {
logger.debug( logger.debug(
"Not all SARIF files were produced by CodeQL. Merging files in the action.", "Not all SARIF files were produced by CodeQL. Merging files in the action.",
); );
if (
await shouldShowCombineSarifFilesDeprecationWarning(
sarifObjects,
features,
gitHubVersion,
)
) {
logger.warning(
`Uploading multiple SARIF runs with the same category is deprecated ${deprecationWarningMessage}. Please update your workflow to upload a single run per category. ${deprecationMoreInformationMessage}`,
);
core.exportVariable("CODEQL_MERGE_SARIF_DEPRECATION_WARNING", "true");
}
// If not, use the naive method of combining the files. // If not, use the naive method of combining the files.
return combineSarifFiles(sarifFiles, logger); return combineSarifFiles(sarifFiles, logger);
} }
@@ -149,6 +242,19 @@ async function combineSarifFilesUsingCLI(
"The CodeQL CLI does not support merging SARIF files. Merging files in the action.", "The CodeQL CLI does not support merging SARIF files. Merging files in the action.",
); );
if (
await shouldShowCombineSarifFilesDeprecationWarning(
sarifObjects,
features,
gitHubVersion,
)
) {
logger.warning(
`Uploading multiple CodeQL runs with the same category is deprecated ${deprecationWarningMessage} for CodeQL CLI 2.16.6 and earlier. Please update your CodeQL CLI version or update your workflow to set a distinct category for each CodeQL run. ${deprecationMoreInformationMessage}`,
);
core.exportVariable("CODEQL_MERGE_SARIF_DEPRECATION_WARNING", "true");
}
return combineSarifFiles(sarifFiles, logger); return combineSarifFiles(sarifFiles, logger);
} }
@@ -496,14 +602,12 @@ async function uploadFiles(
validateSarifFileSchema(file, logger); validateSarifFileSchema(file, logger);
} }
let sarif = (await features.getValue(Feature.CliSarifMerge)) let sarif = await combineSarifFilesUsingCLI(
? await combineSarifFilesUsingCLI(
sarifFiles, sarifFiles,
gitHubVersion, gitHubVersion,
features, features,
logger, logger,
) );
: combineSarifFiles(sarifFiles, logger);
sarif = await fingerprints.addFingerprints(sarif, sourceRoot, logger); sarif = await fingerprints.addFingerprints(sarif, sourceRoot, logger);
sarif = populateRunAutomationDetails( sarif = populateRunAutomationDetails(

View File

@@ -56,8 +56,11 @@ export interface SarifFile {
export interface SarifRun { export interface SarifRun {
tool?: { tool?: {
driver?: { driver?: {
guid?: string;
name?: string; name?: string;
fullName?: string;
semanticVersion?: string; semanticVersion?: string;
version?: string;
}; };
}; };
automationDetails?: { automationDetails?: {