Add deprecation warning for merging SARIF files with non-unique categories

This commit is contained in:
Koen Vlaswinkel
2024-04-22 16:42:21 +02:00
parent 4ebadbc746
commit 8b0dfa84c7
5 changed files with 126 additions and 15 deletions

52
lib/upload-lib.js generated
View File

@@ -73,14 +73,42 @@ 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;
}
// 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 +118,17 @@ 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"));
});
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.");
// Only give a deprecation warning when not all runs are unique
if (!areAllRunsUnique(sarifObjects) &&
!process.env.CODEQL_MERGE_SARIF_DEPRECATION_WARNING) {
logger.warning("Uploading multiple SARIF runs with the same category is deprecated and will be removed on June 4, 2025. Please update your workflow to upload a single run per category. For more information, see https://github.blog/changelog/TODO");
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 +156,11 @@ 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 (!areAllRunsUnique(sarifObjects) &&
!process.env.CODEQL_MERGE_SARIF_DEPRECATION_WARNING) {
logger.warning("Uploading multiple CodeQL runs with the same category is deprecated and will be removed on June 4, 2025. Please update your CodeQL CLI version or update your workflow to set a distinct category for each CodeQL run. For more information, see https://github.blog/changelog/TODO");
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");

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -26,6 +26,7 @@ import {
getRequiredEnvParam, getRequiredEnvParam,
GitHubVersion, GitHubVersion,
SarifFile, SarifFile,
SarifRun,
wrapError, wrapError,
} from "./util"; } from "./util";
@@ -65,20 +66,60 @@ 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;
}
// 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.
@@ -94,11 +135,26 @@ 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;
});
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.",
); );
// Only give a deprecation warning when not all runs are unique
if (
!areAllRunsUnique(sarifObjects) &&
!process.env.CODEQL_MERGE_SARIF_DEPRECATION_WARNING
) {
logger.warning(
"Uploading multiple SARIF runs with the same category is deprecated and will be removed on June 4, 2025. Please update your workflow to upload a single run per category. For more information, see https://github.blog/changelog/TODO",
);
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 +205,16 @@ 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 (
!areAllRunsUnique(sarifObjects) &&
!process.env.CODEQL_MERGE_SARIF_DEPRECATION_WARNING
) {
logger.warning(
"Uploading multiple CodeQL runs with the same category is deprecated and will be removed on June 4, 2025. Please update your CodeQL CLI version or update your workflow to set a distinct category for each CodeQL run. For more information, see https://github.blog/changelog/TODO",
);
core.exportVariable("CODEQL_MERGE_SARIF_DEPRECATION_WARNING", "true");
}
return combineSarifFiles(sarifFiles, logger); return combineSarifFiles(sarifFiles, logger);
} }

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?: {