From 40aec383a1e9545cf4efa0f1898f87d492f28484 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Sun, 1 Mar 2026 14:22:49 +0000 Subject: [PATCH] Move more SARIF helpers to `sarif` module --- lib/analyze-action.js | 112 ++++++++++++++++++------------------ lib/init-action-post.js | 112 ++++++++++++++++++------------------ lib/upload-lib.js | 114 ++++++++++++++++++------------------- lib/upload-sarif-action.js | 112 ++++++++++++++++++------------------ src/sarif/index.ts | 91 +++++++++++++++++++++++++++++ src/upload-lib.ts | 104 ++++----------------------------- src/upload-sarif-action.ts | 3 +- 7 files changed, 328 insertions(+), 320 deletions(-) diff --git a/lib/analyze-action.js b/lib/analyze-action.js index 72dc91b04..982289ce3 100644 --- a/lib/analyze-action.js +++ b/lib/analyze-action.js @@ -105899,6 +105899,8 @@ var semver = __toESM(require_semver2()); // src/sarif/index.ts var fs = __toESM(require("fs")); +var InvalidSarifUploadError = class extends Error { +}; function getToolNames(sarif) { const toolNames = {}; for (const run2 of sarif.runs || []) { @@ -105913,6 +105915,56 @@ function getToolNames(sarif) { function readSarifFile(sarifFilePath) { return JSON.parse(fs.readFileSync(sarifFilePath, "utf8")); } +function combineSarifFiles(sarifFiles, logger) { + logger.info(`Loading SARIF file(s)`); + const combinedSarif = { + version: null, + runs: [] + }; + for (const sarifFile of sarifFiles) { + logger.debug(`Loading SARIF file: ${sarifFile}`); + const sarifObject = readSarifFile(sarifFile); + if (combinedSarif.version === null) { + combinedSarif.version = sarifObject.version; + } else if (combinedSarif.version !== sarifObject.version) { + throw new InvalidSarifUploadError( + `Different SARIF versions encountered: ${combinedSarif.version} and ${sarifObject.version}` + ); + } + combinedSarif.runs.push(...sarifObject.runs); + } + return combinedSarif; +} +function areAllRunsProducedByCodeQL(sarifObjects) { + return sarifObjects.every((sarifObject) => { + return sarifObject.runs?.every( + (run2) => run2.tool?.driver?.name === "CodeQL" + ); + }); +} +function createRunKey(run2) { + return { + name: run2.tool?.driver?.name, + fullName: run2.tool?.driver?.fullName, + version: run2.tool?.driver?.version, + semanticVersion: run2.tool?.driver?.semanticVersion, + guid: run2.tool?.driver?.guid, + automationId: run2.automationDetails?.id + }; +} +function areAllRunsUnique(sarifObjects) { + const keys = /* @__PURE__ */ new Set(); + for (const sarifObject of sarifObjects) { + for (const run2 of sarifObject.runs) { + const key = JSON.stringify(createRunKey(run2)); + if (keys.has(key)) { + return false; + } + keys.add(key); + } + } + return true; +} // src/util.ts var BASE_DATABASE_OIDS_FILE_NAME = "base-database-oids.json"; @@ -112407,56 +112459,6 @@ async function initCodeQL(toolsInput, apiDetails, tempDir, variant, defaultCliVe // src/upload-lib.ts var GENERIC_403_MSG = "The repo on which this action is running has not opted-in to CodeQL code scanning."; var GENERIC_404_MSG = "The CodeQL code scanning feature is forbidden on this repository."; -function combineSarifFiles(sarifFiles, logger) { - logger.info(`Loading SARIF file(s)`); - const combinedSarif = { - version: null, - runs: [] - }; - for (const sarifFile of sarifFiles) { - logger.debug(`Loading SARIF file: ${sarifFile}`); - const sarifObject = readSarifFile(sarifFile); - if (combinedSarif.version === null) { - combinedSarif.version = sarifObject.version; - } else if (combinedSarif.version !== sarifObject.version) { - throw new InvalidSarifUploadError( - `Different SARIF versions encountered: ${combinedSarif.version} and ${sarifObject.version}` - ); - } - combinedSarif.runs.push(...sarifObject.runs); - } - return combinedSarif; -} -function areAllRunsProducedByCodeQL(sarifObjects) { - return sarifObjects.every((sarifObject) => { - return sarifObject.runs?.every( - (run2) => run2.tool?.driver?.name === "CodeQL" - ); - }); -} -function createRunKey(run2) { - return { - name: run2.tool?.driver?.name, - fullName: run2.tool?.driver?.fullName, - version: run2.tool?.driver?.version, - semanticVersion: run2.tool?.driver?.semanticVersion, - guid: run2.tool?.driver?.guid, - automationId: run2.automationDetails?.id - }; -} -function areAllRunsUnique(sarifObjects) { - const keys = /* @__PURE__ */ new Set(); - for (const sarifObject of sarifObjects) { - for (const run2 of sarifObject.runs) { - const key = JSON.stringify(createRunKey(run2)); - if (keys.has(key)) { - return false; - } - keys.add(key); - } - } - return true; -} async function shouldShowCombineSarifFilesDeprecationWarning(sarifObjects, githubVersion) { if (githubVersion.type === "GitHub Enterprise Server" /* GHES */ && satisfiesGHESVersion(githubVersion.version, "<3.14", true)) { return false; @@ -112546,19 +112548,19 @@ async function combineSarifFilesUsingCLI(sarifFiles, gitHubVersion, features, lo }); return readSarifFile(outputFile); } -function populateRunAutomationDetails(sarif, category, analysis_key, environment) { +function populateRunAutomationDetails(sarifFile, category, analysis_key, environment) { const automationID = getAutomationID2(category, analysis_key, environment); if (automationID !== void 0) { - for (const run2 of sarif.runs || []) { + for (const run2 of sarifFile.runs || []) { if (run2.automationDetails === void 0) { run2.automationDetails = { id: automationID }; } } - return sarif; + return sarifFile; } - return sarif; + return sarifFile; } function getAutomationID2(category, analysis_key, environment) { if (category !== void 0) { @@ -112997,8 +112999,6 @@ function validateUniqueCategory(sarif, sentinelPrefix) { function sanitize(str2) { return (str2 ?? "_").replace(/[^a-zA-Z0-9_]/g, "_").toLocaleUpperCase(); } -var InvalidSarifUploadError = class extends Error { -}; function filterAlertsByDiffRange(logger, sarif) { const diffRanges = readDiffRangesJsonFile(logger); if (!diffRanges?.length) { diff --git a/lib/init-action-post.js b/lib/init-action-post.js index c6d485ab6..7631d46f7 100644 --- a/lib/init-action-post.js +++ b/lib/init-action-post.js @@ -164002,6 +164002,8 @@ var minimumVersion = "3.14"; // src/sarif/index.ts var fs = __toESM(require("fs")); +var InvalidSarifUploadError = class extends Error { +}; function getToolNames(sarif) { const toolNames = {}; for (const run3 of sarif.runs || []) { @@ -164016,6 +164018,56 @@ function getToolNames(sarif) { function readSarifFile(sarifFilePath) { return JSON.parse(fs.readFileSync(sarifFilePath, "utf8")); } +function combineSarifFiles(sarifFiles, logger) { + logger.info(`Loading SARIF file(s)`); + const combinedSarif = { + version: null, + runs: [] + }; + for (const sarifFile of sarifFiles) { + logger.debug(`Loading SARIF file: ${sarifFile}`); + const sarifObject = readSarifFile(sarifFile); + if (combinedSarif.version === null) { + combinedSarif.version = sarifObject.version; + } else if (combinedSarif.version !== sarifObject.version) { + throw new InvalidSarifUploadError( + `Different SARIF versions encountered: ${combinedSarif.version} and ${sarifObject.version}` + ); + } + combinedSarif.runs.push(...sarifObject.runs); + } + return combinedSarif; +} +function areAllRunsProducedByCodeQL(sarifObjects) { + return sarifObjects.every((sarifObject) => { + return sarifObject.runs?.every( + (run3) => run3.tool?.driver?.name === "CodeQL" + ); + }); +} +function createRunKey(run3) { + return { + name: run3.tool?.driver?.name, + fullName: run3.tool?.driver?.fullName, + version: run3.tool?.driver?.version, + semanticVersion: run3.tool?.driver?.semanticVersion, + guid: run3.tool?.driver?.guid, + automationId: run3.automationDetails?.id + }; +} +function areAllRunsUnique(sarifObjects) { + const keys = /* @__PURE__ */ new Set(); + for (const sarifObject of sarifObjects) { + for (const run3 of sarifObject.runs) { + const key = JSON.stringify(createRunKey(run3)); + if (keys.has(key)) { + return false; + } + keys.add(key); + } + } + return true; +} // src/util.ts var BASE_DATABASE_OIDS_FILE_NAME = "base-database-oids.json"; @@ -169483,56 +169535,6 @@ async function initCodeQL(toolsInput, apiDetails, tempDir, variant, defaultCliVe // src/upload-lib.ts var GENERIC_403_MSG = "The repo on which this action is running has not opted-in to CodeQL code scanning."; var GENERIC_404_MSG = "The CodeQL code scanning feature is forbidden on this repository."; -function combineSarifFiles(sarifFiles, logger) { - logger.info(`Loading SARIF file(s)`); - const combinedSarif = { - version: null, - runs: [] - }; - for (const sarifFile of sarifFiles) { - logger.debug(`Loading SARIF file: ${sarifFile}`); - const sarifObject = readSarifFile(sarifFile); - if (combinedSarif.version === null) { - combinedSarif.version = sarifObject.version; - } else if (combinedSarif.version !== sarifObject.version) { - throw new InvalidSarifUploadError( - `Different SARIF versions encountered: ${combinedSarif.version} and ${sarifObject.version}` - ); - } - combinedSarif.runs.push(...sarifObject.runs); - } - return combinedSarif; -} -function areAllRunsProducedByCodeQL(sarifObjects) { - return sarifObjects.every((sarifObject) => { - return sarifObject.runs?.every( - (run3) => run3.tool?.driver?.name === "CodeQL" - ); - }); -} -function createRunKey(run3) { - return { - name: run3.tool?.driver?.name, - fullName: run3.tool?.driver?.fullName, - version: run3.tool?.driver?.version, - semanticVersion: run3.tool?.driver?.semanticVersion, - guid: run3.tool?.driver?.guid, - automationId: run3.automationDetails?.id - }; -} -function areAllRunsUnique(sarifObjects) { - const keys = /* @__PURE__ */ new Set(); - for (const sarifObject of sarifObjects) { - for (const run3 of sarifObject.runs) { - const key = JSON.stringify(createRunKey(run3)); - if (keys.has(key)) { - return false; - } - keys.add(key); - } - } - return true; -} async function shouldShowCombineSarifFilesDeprecationWarning(sarifObjects, githubVersion) { if (githubVersion.type === "GitHub Enterprise Server" /* GHES */ && satisfiesGHESVersion(githubVersion.version, "<3.14", true)) { return false; @@ -169622,19 +169624,19 @@ async function combineSarifFilesUsingCLI(sarifFiles, gitHubVersion, features, lo }); return readSarifFile(outputFile); } -function populateRunAutomationDetails(sarif, category, analysis_key, environment) { +function populateRunAutomationDetails(sarifFile, category, analysis_key, environment) { const automationID = getAutomationID2(category, analysis_key, environment); if (automationID !== void 0) { - for (const run3 of sarif.runs || []) { + for (const run3 of sarifFile.runs || []) { if (run3.automationDetails === void 0) { run3.automationDetails = { id: automationID }; } } - return sarif; + return sarifFile; } - return sarif; + return sarifFile; } function getAutomationID2(category, analysis_key, environment) { if (category !== void 0) { @@ -170044,8 +170046,6 @@ function validateUniqueCategory(sarif, sentinelPrefix) { function sanitize(str2) { return (str2 ?? "_").replace(/[^a-zA-Z0-9_]/g, "_").toLocaleUpperCase(); } -var InvalidSarifUploadError = class extends Error { -}; function filterAlertsByDiffRange(logger, sarif) { const diffRanges = readDiffRangesJsonFile(logger); if (!diffRanges?.length) { diff --git a/lib/upload-lib.js b/lib/upload-lib.js index a6505fbf0..a258cc46a 100644 --- a/lib/upload-lib.js +++ b/lib/upload-lib.js @@ -103229,7 +103229,6 @@ var require_sarif_schema_2_1_0 = __commonJS({ // src/upload-lib.ts var upload_lib_exports = {}; __export(upload_lib_exports, { - InvalidSarifUploadError: () => InvalidSarifUploadError, buildPayload: () => buildPayload, findSarifFilesInDir: () => findSarifFilesInDir, getGroupedSarifFilePaths: () => getGroupedSarifFilePaths, @@ -105916,6 +105915,8 @@ var semver = __toESM(require_semver2()); // src/sarif/index.ts var fs = __toESM(require("fs")); +var InvalidSarifUploadError = class extends Error { +}; function getToolNames(sarif) { const toolNames = {}; for (const run of sarif.runs || []) { @@ -105930,6 +105931,56 @@ function getToolNames(sarif) { function readSarifFile(sarifFilePath) { return JSON.parse(fs.readFileSync(sarifFilePath, "utf8")); } +function combineSarifFiles(sarifFiles, logger) { + logger.info(`Loading SARIF file(s)`); + const combinedSarif = { + version: null, + runs: [] + }; + for (const sarifFile of sarifFiles) { + logger.debug(`Loading SARIF file: ${sarifFile}`); + const sarifObject = readSarifFile(sarifFile); + if (combinedSarif.version === null) { + combinedSarif.version = sarifObject.version; + } else if (combinedSarif.version !== sarifObject.version) { + throw new InvalidSarifUploadError( + `Different SARIF versions encountered: ${combinedSarif.version} and ${sarifObject.version}` + ); + } + combinedSarif.runs.push(...sarifObject.runs); + } + return combinedSarif; +} +function areAllRunsProducedByCodeQL(sarifObjects) { + return sarifObjects.every((sarifObject) => { + 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 + }; +} +function areAllRunsUnique(sarifObjects) { + const keys = /* @__PURE__ */ new Set(); + for (const sarifObject of sarifObjects) { + for (const run of sarifObject.runs) { + const key = JSON.stringify(createRunKey(run)); + if (keys.has(key)) { + return false; + } + keys.add(key); + } + } + return true; +} // src/util.ts var BASE_DATABASE_OIDS_FILE_NAME = "base-database-oids.json"; @@ -110295,56 +110346,6 @@ async function initCodeQL(toolsInput, apiDetails, tempDir, variant, defaultCliVe // src/upload-lib.ts var GENERIC_403_MSG = "The repo on which this action is running has not opted-in to CodeQL code scanning."; var GENERIC_404_MSG = "The CodeQL code scanning feature is forbidden on this repository."; -function combineSarifFiles(sarifFiles, logger) { - logger.info(`Loading SARIF file(s)`); - const combinedSarif = { - version: null, - runs: [] - }; - for (const sarifFile of sarifFiles) { - logger.debug(`Loading SARIF file: ${sarifFile}`); - const sarifObject = readSarifFile(sarifFile); - if (combinedSarif.version === null) { - combinedSarif.version = sarifObject.version; - } else if (combinedSarif.version !== sarifObject.version) { - throw new InvalidSarifUploadError( - `Different SARIF versions encountered: ${combinedSarif.version} and ${sarifObject.version}` - ); - } - combinedSarif.runs.push(...sarifObject.runs); - } - return combinedSarif; -} -function areAllRunsProducedByCodeQL(sarifObjects) { - return sarifObjects.every((sarifObject) => { - 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 - }; -} -function areAllRunsUnique(sarifObjects) { - const keys = /* @__PURE__ */ new Set(); - for (const sarifObject of sarifObjects) { - for (const run of sarifObject.runs) { - const key = JSON.stringify(createRunKey(run)); - if (keys.has(key)) { - return false; - } - keys.add(key); - } - } - return true; -} async function shouldShowCombineSarifFilesDeprecationWarning(sarifObjects, githubVersion) { if (githubVersion.type === "GitHub Enterprise Server" /* GHES */ && satisfiesGHESVersion(githubVersion.version, "<3.14", true)) { return false; @@ -110434,19 +110435,19 @@ async function combineSarifFilesUsingCLI(sarifFiles, gitHubVersion, features, lo }); return readSarifFile(outputFile); } -function populateRunAutomationDetails(sarif, category, analysis_key, environment) { +function populateRunAutomationDetails(sarifFile, category, analysis_key, environment) { const automationID = getAutomationID2(category, analysis_key, environment); if (automationID !== void 0) { - for (const run of sarif.runs || []) { + for (const run of sarifFile.runs || []) { if (run.automationDetails === void 0) { run.automationDetails = { id: automationID }; } } - return sarif; + return sarifFile; } - return sarif; + return sarifFile; } function getAutomationID2(category, analysis_key, environment) { if (category !== void 0) { @@ -110932,8 +110933,6 @@ function validateUniqueCategory(sarif, sentinelPrefix) { function sanitize(str2) { return (str2 ?? "_").replace(/[^a-zA-Z0-9_]/g, "_").toLocaleUpperCase(); } -var InvalidSarifUploadError = class extends Error { -}; function filterAlertsByDiffRange(logger, sarif) { const diffRanges = readDiffRangesJsonFile(logger); if (!diffRanges?.length) { @@ -110965,7 +110964,6 @@ function filterAlertsByDiffRange(logger, sarif) { } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { - InvalidSarifUploadError, buildPayload, findSarifFilesInDir, getGroupedSarifFilePaths, diff --git a/lib/upload-sarif-action.js b/lib/upload-sarif-action.js index 1adb7849c..f853efa10 100644 --- a/lib/upload-sarif-action.js +++ b/lib/upload-sarif-action.js @@ -105890,6 +105890,8 @@ var semver = __toESM(require_semver2()); // src/sarif/index.ts var fs = __toESM(require("fs")); +var InvalidSarifUploadError = class extends Error { +}; function getToolNames(sarif) { const toolNames = {}; for (const run2 of sarif.runs || []) { @@ -105904,6 +105906,56 @@ function getToolNames(sarif) { function readSarifFile(sarifFilePath) { return JSON.parse(fs.readFileSync(sarifFilePath, "utf8")); } +function combineSarifFiles(sarifFiles, logger) { + logger.info(`Loading SARIF file(s)`); + const combinedSarif = { + version: null, + runs: [] + }; + for (const sarifFile of sarifFiles) { + logger.debug(`Loading SARIF file: ${sarifFile}`); + const sarifObject = readSarifFile(sarifFile); + if (combinedSarif.version === null) { + combinedSarif.version = sarifObject.version; + } else if (combinedSarif.version !== sarifObject.version) { + throw new InvalidSarifUploadError( + `Different SARIF versions encountered: ${combinedSarif.version} and ${sarifObject.version}` + ); + } + combinedSarif.runs.push(...sarifObject.runs); + } + return combinedSarif; +} +function areAllRunsProducedByCodeQL(sarifObjects) { + return sarifObjects.every((sarifObject) => { + return sarifObject.runs?.every( + (run2) => run2.tool?.driver?.name === "CodeQL" + ); + }); +} +function createRunKey(run2) { + return { + name: run2.tool?.driver?.name, + fullName: run2.tool?.driver?.fullName, + version: run2.tool?.driver?.version, + semanticVersion: run2.tool?.driver?.semanticVersion, + guid: run2.tool?.driver?.guid, + automationId: run2.automationDetails?.id + }; +} +function areAllRunsUnique(sarifObjects) { + const keys = /* @__PURE__ */ new Set(); + for (const sarifObject of sarifObjects) { + for (const run2 of sarifObject.runs) { + const key = JSON.stringify(createRunKey(run2)); + if (keys.has(key)) { + return false; + } + keys.add(key); + } + } + return true; +} // src/util.ts var BASE_DATABASE_OIDS_FILE_NAME = "base-database-oids.json"; @@ -110886,56 +110938,6 @@ async function initCodeQL(toolsInput, apiDetails, tempDir, variant, defaultCliVe // src/upload-lib.ts var GENERIC_403_MSG = "The repo on which this action is running has not opted-in to CodeQL code scanning."; var GENERIC_404_MSG = "The CodeQL code scanning feature is forbidden on this repository."; -function combineSarifFiles(sarifFiles, logger) { - logger.info(`Loading SARIF file(s)`); - const combinedSarif = { - version: null, - runs: [] - }; - for (const sarifFile of sarifFiles) { - logger.debug(`Loading SARIF file: ${sarifFile}`); - const sarifObject = readSarifFile(sarifFile); - if (combinedSarif.version === null) { - combinedSarif.version = sarifObject.version; - } else if (combinedSarif.version !== sarifObject.version) { - throw new InvalidSarifUploadError( - `Different SARIF versions encountered: ${combinedSarif.version} and ${sarifObject.version}` - ); - } - combinedSarif.runs.push(...sarifObject.runs); - } - return combinedSarif; -} -function areAllRunsProducedByCodeQL(sarifObjects) { - return sarifObjects.every((sarifObject) => { - return sarifObject.runs?.every( - (run2) => run2.tool?.driver?.name === "CodeQL" - ); - }); -} -function createRunKey(run2) { - return { - name: run2.tool?.driver?.name, - fullName: run2.tool?.driver?.fullName, - version: run2.tool?.driver?.version, - semanticVersion: run2.tool?.driver?.semanticVersion, - guid: run2.tool?.driver?.guid, - automationId: run2.automationDetails?.id - }; -} -function areAllRunsUnique(sarifObjects) { - const keys = /* @__PURE__ */ new Set(); - for (const sarifObject of sarifObjects) { - for (const run2 of sarifObject.runs) { - const key = JSON.stringify(createRunKey(run2)); - if (keys.has(key)) { - return false; - } - keys.add(key); - } - } - return true; -} async function shouldShowCombineSarifFilesDeprecationWarning(sarifObjects, githubVersion) { if (githubVersion.type === "GitHub Enterprise Server" /* GHES */ && satisfiesGHESVersion(githubVersion.version, "<3.14", true)) { return false; @@ -111025,19 +111027,19 @@ async function combineSarifFilesUsingCLI(sarifFiles, gitHubVersion, features, lo }); return readSarifFile(outputFile); } -function populateRunAutomationDetails(sarif, category, analysis_key, environment) { +function populateRunAutomationDetails(sarifFile, category, analysis_key, environment) { const automationID = getAutomationID2(category, analysis_key, environment); if (automationID !== void 0) { - for (const run2 of sarif.runs || []) { + for (const run2 of sarifFile.runs || []) { if (run2.automationDetails === void 0) { run2.automationDetails = { id: automationID }; } } - return sarif; + return sarifFile; } - return sarif; + return sarifFile; } function getAutomationID2(category, analysis_key, environment) { if (category !== void 0) { @@ -111476,8 +111478,6 @@ function validateUniqueCategory(sarif, sentinelPrefix) { function sanitize(str2) { return (str2 ?? "_").replace(/[^a-zA-Z0-9_]/g, "_").toLocaleUpperCase(); } -var InvalidSarifUploadError = class extends Error { -}; function filterAlertsByDiffRange(logger, sarif) { const diffRanges = readDiffRangesJsonFile(logger); if (!diffRanges?.length) { diff --git a/src/sarif/index.ts b/src/sarif/index.ts index 2764f26fc..c8811bb42 100644 --- a/src/sarif/index.ts +++ b/src/sarif/index.ts @@ -74,6 +74,20 @@ export interface SarifFile { runs: SarifRun[]; } +export type SarifRunKey = { + name: string | undefined; + fullName: string | undefined; + version: string | undefined; + semanticVersion: string | undefined; + guid: string | undefined; + automationId: string | undefined; +}; + +/** + * An error that occurred due to an invalid SARIF upload request. + */ +export class InvalidSarifUploadError extends Error {} + /** * Get the array of all the tool names contained in the given sarif contents. * @@ -172,3 +186,80 @@ export function fixInvalidNotifications( export function readSarifFile(sarifFilePath: string): SarifFile { return JSON.parse(fs.readFileSync(sarifFilePath, "utf8")) as SarifFile; } + +// Takes a list of paths to sarif files and combines them together, +// returning the contents of the combined sarif file. +export function combineSarifFiles( + sarifFiles: string[], + logger: Logger, +): SarifFile { + logger.info(`Loading SARIF file(s)`); + const combinedSarif: SarifFile = { + version: null, + runs: [], + }; + + for (const sarifFile of sarifFiles) { + logger.debug(`Loading SARIF file: ${sarifFile}`); + const sarifObject = readSarifFile(sarifFile); + // Check SARIF version + if (combinedSarif.version === null) { + combinedSarif.version = sarifObject.version; + } else if (combinedSarif.version !== sarifObject.version) { + throw new InvalidSarifUploadError( + `Different SARIF versions encountered: ${combinedSarif.version} and ${sarifObject.version}`, + ); + } + + combinedSarif.runs.push(...sarifObject.runs); + } + + return combinedSarif; +} + +/** + * Checks whether all the runs in the given SARIF files were produced by CodeQL. + * @param sarifObjects The list of SARIF objects to check. + */ +export function areAllRunsProducedByCodeQL(sarifObjects: SarifFile[]): boolean { + return sarifObjects.every((sarifObject) => { + return sarifObject.runs?.every( + (run) => run.tool?.driver?.name === "CodeQL", + ); + }); +} + +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. + */ +export function areAllRunsUnique(sarifObjects: SarifFile[]): boolean { + 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; +} diff --git a/src/upload-lib.ts b/src/upload-lib.ts index 5904f08e2..919adbccf 100644 --- a/src/upload-lib.ts +++ b/src/upload-lib.ts @@ -21,7 +21,13 @@ import * as gitUtils from "./git-utils"; import { initCodeQL } from "./init"; import { Logger } from "./logging"; import { getRepositoryNwo, RepositoryNwo } from "./repository"; -import type { SarifFile, SarifRun } from "./sarif"; +import type { SarifFile } from "./sarif"; +import { + areAllRunsProducedByCodeQL, + areAllRunsUnique, + combineSarifFiles, + InvalidSarifUploadError, +} from "./sarif"; import { BasePayload, UploadPayload } from "./upload-lib/types"; import * as util from "./util"; import { @@ -38,89 +44,6 @@ const GENERIC_403_MSG = const GENERIC_404_MSG = "The CodeQL code scanning feature is forbidden on this repository."; -// Takes a list of paths to sarif files and combines them together, -// returning the contents of the combined sarif file. -function combineSarifFiles(sarifFiles: string[], logger: Logger): SarifFile { - logger.info(`Loading SARIF file(s)`); - const combinedSarif: SarifFile = { - version: null, - runs: [], - }; - - for (const sarifFile of sarifFiles) { - logger.debug(`Loading SARIF file: ${sarifFile}`); - const sarifObject = util.readSarifFile(sarifFile); - // Check SARIF version - if (combinedSarif.version === null) { - combinedSarif.version = sarifObject.version; - } else if (combinedSarif.version !== sarifObject.version) { - throw new InvalidSarifUploadError( - `Different SARIF versions encountered: ${combinedSarif.version} and ${sarifObject.version}`, - ); - } - - combinedSarif.runs.push(...sarifObject.runs); - } - - return combinedSarif; -} - -/** - * Checks whether all the runs in the given SARIF files were produced by CodeQL. - * @param sarifObjects The list of SARIF objects to check. - */ -function areAllRunsProducedByCodeQL(sarifObjects: SarifFile[]): boolean { - return sarifObjects.every((sarifObject) => { - return sarifObject.runs?.every( - (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(); - - 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[], @@ -280,7 +203,7 @@ async function combineSarifFilesUsingCLI( // Populates the run.automationDetails.id field using the analysis_key and environment // and return an updated sarif file contents. export function populateRunAutomationDetails( - sarif: SarifFile, + sarifFile: SarifFile, category: string | undefined, analysis_key: string, environment: string | undefined, @@ -288,16 +211,16 @@ export function populateRunAutomationDetails( const automationID = getAutomationID(category, analysis_key, environment); if (automationID !== undefined) { - for (const run of sarif.runs || []) { + for (const run of sarifFile.runs || []) { if (run.automationDetails === undefined) { run.automationDetails = { id: automationID, }; } } - return sarif; + return sarifFile; } - return sarif; + return sarifFile; } function getAutomationID( @@ -1122,11 +1045,6 @@ function sanitize(str?: string) { return (str ?? "_").replace(/[^a-zA-Z0-9_]/g, "_").toLocaleUpperCase(); } -/** - * An error that occurred due to an invalid SARIF upload request. - */ -export class InvalidSarifUploadError extends Error {} - function filterAlertsByDiffRange(logger: Logger, sarif: SarifFile): SarifFile { const diffRanges = readDiffRangesJsonFile(logger); if (!diffRanges?.length) { diff --git a/src/upload-sarif-action.ts b/src/upload-sarif-action.ts index cec41b276..b09821924 100644 --- a/src/upload-sarif-action.ts +++ b/src/upload-sarif-action.ts @@ -20,6 +20,7 @@ import * as upload_lib from "./upload-lib"; import { postProcessAndUploadSarif } from "./upload-sarif"; import { ConfigurationError, + InvalidSarifUploadError, checkActionVersion, checkDiskUsage, getErrorMessage, @@ -141,7 +142,7 @@ async function run(startedAt: Date) { } catch (unwrappedError) { const error = isThirdPartyAnalysis(ActionName.UploadSarif) && - unwrappedError instanceof upload_lib.InvalidSarifUploadError + unwrappedError instanceof InvalidSarifUploadError ? new ConfigurationError(unwrappedError.message) : wrapError(unwrappedError); const message = error.message;